#include <streambuf>
#include <ios>    
#include <thread>
#include <sstream>

class seppjs_thread_logger_streambuf : public std::streambuf
{
public:
  seppjs_thread_logger_streambuf(std::ios& in) : in(in), buf (in.rdbuf()), newline(true)
  {
    in.rdbuf(this);
  }
  ~seppjs_thread_logger_streambuf()
  {
    in.rdbuf(buf);
  }
  seppjs_thread_logger_streambuf(const seppjs_thread_logger_streambuf&) = delete;
  seppjs_thread_logger_streambuf& operator=(const seppjs_thread_logger_streambuf&) = delete;

private:
  std::ios& in;
  std::streambuf* buf;
  bool newline;
protected:
  virtual int_type overflow(int_type c)
  {
    if(newline)
      {
        std::stringstream message;
        message << "Task " << std::this_thread::get_id() << ": ";
        buf->sputn(message.str().data(), message.str().size());
        newline = false;
      }
    if (traits_type::eq_int_type(c, traits_type::to_int_type('\n')))
      newline = true;
    buf->sputc(c);
    return c;  
  }
};


// Beispielanwendung
#include <iostream>

void function()
{
  std::cout << "Blah\nBlupp\nBäh\n";  
}

int main()
{
  seppjs_thread_logger_streambuf foo(std::cout);
  std::thread t1(function), t2(function);
  
  t1.join();
  t2.join();
}
