How to overload << operator for thread-safe logging in C++? - c++

I'm writing a sketch of a simple thread-safe logging library and some things came on my mind. Here's the code:
#ifndef SimpleLogger_H
#define SimpleLogger_H
#include <iostream>
#include <mutex>
class SimpleLogger
{
public:
template <typename T>
static void log(T message)
{
mutex.lock();
std::cout << message;
mutex.unlock();
}
private:
static std::mutex mutex;
}LOG;
template <typename T>
SimpleLogger &operator<<(SimpleLogger &simpleLogger, T message)
{
simpleLogger.log(message);
return simpleLogger;
}
#endif //SimpleLogger_H
My idea is to use it like this:
LOG << "hello" << " world " << 8 << " I can mix integers and strings";
I understand that the line above is like the following:
auto a1 = LOG.operator<<("hello");
auto a2 = a1.operator<<(" world ");
//Another thread may want to use LOG here, and would print in the middle of my message
auto a3 = a2.operator<<(8);
auto a4 = a3.operator<<(" I can mix integers and strings");
As you can see, because << is broken into several funciton calls, there's a risk that a thread can use the LOG object in the middle of my message (I consider a message the entire cascade of << on one line)
Also, is there a way to automatically add an std::endl for the last << call? I couldn't think of a way to do this, but I saw that some logging libraries have this functionality
How do I solve these two problems?
I know it'd be preferable to use a logging library but I want to mix android, desktop and ios logging in one simple lib without need for high performance, and I'm also puzzled by how I can overcome the difficulties I encountered while writing my own

As others already mentioned, you need a local buffer to collect message before sending to the log file. In the example below, SimpleLoggerBuffer objects are designed to be used as temporary variable only. I.e. it gets destroyed at the end of the expression. The destructor flushes the buffer into the log so that you don't have to explicitly call a flush function (you may add endl there as well if you wish)
#include <iostream>
#include <sstream>
#include <mutex>
using namespace std;
class SimpleLogger
{
public:
template <typename T>
static void log(T& message)
{
mutex.lock();
std::cout << message.str();
message.flush();
mutex.unlock();
}
private:
static std::mutex mutex;
}LOG;
std::mutex SimpleLogger::mutex;
struct SimpleLoggerBuffer{
stringstream ss;
SimpleLoggerBuffer() = default;
SimpleLoggerBuffer(const SimpleLoggerBuffer&) = delete;
SimpleLoggerBuffer& operator=(const SimpleLoggerBuffer&) = delete;
SimpleLoggerBuffer& operator=(SimpleLoggerBuffer&&) = delete;
SimpleLoggerBuffer(SimpleLoggerBuffer&& buf): ss(move(buf.ss)) {
}
template <typename T>
SimpleLoggerBuffer& operator<<(T&& message)
{
ss << std::forward<T>(message);
return *this;
}
~SimpleLoggerBuffer() {
LOG.log(ss);
}
};
template <typename T>
SimpleLoggerBuffer operator<<(SimpleLogger &simpleLogger, T&& message)
{
SimpleLoggerBuffer buf;
buf.ss << std::forward<T>(message);
return buf;
}
int main() {
LOG << "hello" << " world " << 8 << " I can mix integers and strings";
}

You could create a helper class that collects all the output and prints on destruction. Outline:
#include <string>
#include <iostream>
struct Msg;
struct Log {
void print(const Msg &m);
};
struct Msg {
std::string m;
Log &l;
Msg(Log &l) : l(l) {}
~Msg() {
// Print the message on destruction
l.print(*this);
}
};
void Log::print(const Msg &m) {
// Logger specific printing... here, append newline
std::cout << m.m << std::endl;
}
Msg &&operator << (Msg &&m, const std::string &s) {
// Append operator
m.m += s;
return std::move(m);
}
// Helper to log on a specific logger. Just creates the initial message
Msg log(Log &l) { return Msg(l); }
int main()
{
Log l;
log(l) << "a" << "b" << "c";
return 0;
}
As the Msg is local, other threads will not interfere with it. Any necessary locking can be done in the Log.print method, which will receive the complete message

A simple solution is to write into files instead of standard output, and specifically, separate file for each thread. That way no locking or any other synchronization is needed. The files can later be merged if lines have parseable format.
Another solution is to write logs asynchronously from a single thread, and initially store the messages in a thread safe (possibly lock free) queue.
Also, is there a way to automatically add an std::endl for the last << call?
Unless I misunderstand, you can simply do stream << message << std::endl.

I think that you can simply use std::clog. It is thread safe and, in contrary of std::cout, designed to output instantly for logging.
From the reference page :
Unless sync_with_stdio(false) has been issued, it is safe to
concurrently access these objects from multiple threads for both
formatted and unformatted output.
I recommend you this Jason Turner's video about cout, clog and cerror.

The simplest approach is to return a temporary proxy from the first << - this can either log your stream for the duration (and unlock on destruction), or simply build a local ostringstream and flush it in a single call (again, on destruction).
Holding a lock while logging isn't great for performance (although it's better than your existing log method, which should use std::lock_guard for exception safety).
Building and discarding a temporary ostringstream is probably better, but if you care about performance you'll need to benchmark, and may well end up requiring something more elaborate (per-thread circular buffers, mmapped files or something).

Related

Relying on deterministic destruction, avoiding destruction on return

I have been trying to rework my logging class. However, I'm facing a problem.
I want to expose this interface to users:
mylog() << "hello";
The idea is that mylog is an instance of Logger, which defines some useful characteristics for a defined log type. Its operator() function would return an instace of type LogStream. However, I would like to output the newline character automatically at the end, so I had the idea to do that in LogStream's destructor.
My current implementation looks like this (LogStream and Logger being largely dumbed down):
#include <iostream>
struct LogStream
{
~LogStream() { std::cout << '\n'; }
template<class T>
LogStream& operator<<(const T& t)
{
std::cout << t;
return *this;
}
};
struct Logger
{
LogStream operator()()
{
return LogStream{} << "message: ";
}
};
int main()
{
Logger log;
log() << "hello!";
}
Interstingly, I figured out with this piece of code that my previous implementation depended on RVO. The compiler was always performing copy-elision, so the destructor did behave the way I want. However, with this piece of code, the newline character is being printed twice, because the copy constructor is being called when the copy occurs in operator().
The problem disappears when I do not return the temporary instance, and instead put this in operator()'s body:
LogStream stream;
stream << "message: ";
return stream;
Now the RVO makes it work the way I want.
I later on = delete'd the copy constructors, because it made more sense anyway, which effectively causes the code to fail to compile.
What are my options to provide the interface I want, without using the hacky solution to rely on RVO?
Add a constructor to LogStream that takes a char const *.
LogStream(char const* c) { std::cout << c; }
Then, instead of creating a temporary LogStream within operator(), use list-initialization to initialize the return value itself.
LogStream operator()()
{
return {"message: "};
}
The temporary is thus avoided along with the extra new line.
Live demo (note that even using -fno-elide-constructors to disable copy elision doesn't result in the extra newline).

Is it possible to avoid copying arguments to a lambda function?

I'd like to manage file descriptors using a Handle, and I want to use lambda expressions to process them. I'd like to use RAII to manage the underlying file descriptors. One option is to handle invalid values for descriptors (e.g. -1). However, I'd prefer for a handle to always be valid.
I've found that I can't seem to avoid invoking the copy constructor at least once. Here is a working example:
#include <fcntl.h>
#include <unistd.h>
#include <functional>
#include <system_error>
#include <iostream>
class Handle
{
public:
Handle(int descriptor) : _descriptor(descriptor) {}
~Handle()
{
std::cerr << "close(" << _descriptor << ")" << std::endl;
::close(_descriptor);
}
Handle(const Handle & other) : _descriptor(::dup(other._descriptor))
{
std::cerr << "dup(" << other._descriptor << ") = " << _descriptor << std::endl;
if (_descriptor == -1) throw std::system_error(errno, std::generic_category(), "dup");
}
int descriptor() const { return _descriptor; }
private:
int _descriptor;
};
Handle open_path(const char * path)
{
return ::open("/dev/random", O_RDONLY);
}
void invoke(std::function<void()> & function)
{
function();
}
int main(int argc, const char * argv[]) {
// Using auto f = here avoids the copy, but that's not helpful when you need a function to pass to another function.
std::function<void()> function = [handle = open_path("/dev/random")]{
std::cerr << "Opened path with descriptor: " << handle.descriptor() << std::endl;
};
invoke(function);
}
The output of this program is:
dup(3) = 4
close(3)
Opened path with descriptor: 4
close(4)
I know that the handle is being copied because it's being allocated by value within the std::function, but I was under the impression std::function could be heap allocated in some cases, which would perhaps avoid the copy (I guess this is not happening though).
There are a number of options, e.g. heap allocation, orusing a sentinel value (e.g. -1) which is checked. However, I'd like to have an invariant that a handle is always valid. It's sort of a matter of style and invariants.
Is there any way to construct the handle within the stack frame of the std::function to avoid copying, or do I need to take a different approach?
Perhaps as an additional point: to what extent can we rely on std::function to avoid copying it's arguments when it's created?
First, let's get this out of the way: std::function is completely orthogonal to lambdas. I wrote an article, "passing functions to functions" that should clarify their relationship and illustrate various techniques that can be used to implement higher-order functions in modern C++.
Using auto f = here avoids the copy, but that's not helpful when you need a function to pass to another function.
I disagree. You can use a template in invoke or something like function_view (see LLVM's FunctionRef for a production-ready implementation, or my article for another simple implementation):
template <typename F>
void invoke(F&& function)
{
std::forward<F>(function)();
}
void invoke(function_view<void()> function)
{
function();
}
Relying on elision or moving with std::function is not enough. Since std::function is required to be copyable, there's always a chance you might copy your Handle by accident elsewhere.
What you need to do instead is to wrap your Handle in something that will not invoke the copy constructor on copy. An obvious choice is a pointer. And an obvious choice of pointer would be a manged one like std::shared_ptr.
I made a few changes to your Handle class for testing (print statements for dtor, ctor, copy ctor), so I'll show those first:
class Handle
{
public:
Handle(int descriptor) : _descriptor(descriptor) {std::cerr<<"Default ctor, descriptor: " << _descriptor << std::endl;}
~Handle()
{
std::cerr << "Dtor. close(" << _descriptor << ")" << std::endl;
}
Handle(const Handle & other) : _descriptor(other._descriptor+1)
{
std::cerr << "Copy ctor. dup(" << other._descriptor << ") = " << _descriptor << std::endl;
}
int descriptor() const { return _descriptor; }
private:
int _descriptor;
};
Next let's modify open_path to return a shared_ptr:
std::shared_ptr<Handle> open_path(const char * path)
{
return std::make_shared<Handle>(0);
}
And then we'll make a slight modification to our lambda in main:
std::function<void()> function = [handle = open_path("/dev/random")]{
std::cerr << "Opened path with descriptor: " << handle->descriptor() << std::endl;
};
Our output now becomes:
Default ctor, descriptor: 0
Opened path with descriptor: 0
Dtor. close(0)
Live Demo

C++ variable amount of arguments with formatting for std::cout

I used to logging in C with variable amount of arguments and formatting, and I wanna how Can I meet this in C++.
Through Q&A like this (How to make a variadic macro for std::cout?), I know how to handle variable amount. But what I still do not know is, how to format, cause I can not use methods like 'setbase' between arguments now.
For example:
// in C
#define err(fmt, ...) (printf("[%s] "fmt"\n", __FUNCTION__, ##__VA_ARGS__))
#define FATAL(fmt, ...) do{\
err(fmt, ##__VA_ARGS__);\
CLEAN_UP;\
exit(1);\
}while(0)
int main(){
if(1) FATAL("Just a test: 0x%lX, %d", 1, 2);
return 0;
}
"FATAL" here, accept variable amount of arguments with formatting, print them, and do some extra. I have no idea how to declare such a "FATAL" in C++.
You can achieve that by using the operator<< and a custom destructor on an ad-hoc logging object.
class log_error
{
public:
log_error() = default;
log_error(log_error&& other) = default;
~log_error()
{
// Do whatever you want with the input
// Add a timestamp, process/thread id
// Write it to a file, send it to a server ...
std::cerr << "[ERROR] " << ss.str() << std::endl;
throw std::runtime_error(ss.str());
}
std::stringstream ss;
};
template<typename T>
log_error operator<<(log_error&& le, const T& t)
{
le.ss << t;
return std::move(le);
}
I only included the essentials for basic usage. For more complex usage you want to consider a copy variant of the ctor / operator<<.
The usage is very idiomatic C++. But you have to remember the ():
log_error() << "Ooops " << 23 << ", 0x" << std::setbase(16) << 23;
This line will print out the message and throw an exception.
You can customize this however you want. Write to logfiles, add timestamps or other helpful information, verbosity levels and thresholds. It is even possible to have most cases completely optimized out in production builds.
Live example
C++ is not C! While you can use C-style (and often C) code this is not advisable. Firstly you should not normally rely on macros as they violate the type system, use (possibly inlined or constexpr) functions instead. Then you should not use C-style error handling technique, use exceptions instead. I'd also recommend against variadic arguments in general and finally you don't need C-style string formatting techniques -> this is C++, use stringstreams to format your code.
In your particular case I'd do something like this:
#include <exception>
#include <iostream>
#include <sstream>
#include <string>
inline void fatal(std::string msg) {
// clean_up
throw std::runtime_error(msg);
}
int main(){
std::ostringstream msg;
msg << "Just a test: " << 1 << 2;
if(1) fatal(msg.str());
return 0;
}
I also have to point out that C++ and C are two different languages with different patterns and idioms. C++ has better alternatives for many C constructs which are more type-safe and thus preferable. IN your case, I would throw an exception in this case. If you ban catch(...) in your code, it will terminate your program. When the exception is propagated, the compiler will also call destructors of objects and thus do clean-up. If you haven't, I recommend you read up on resource-acquisition-is-initialization (RAII). Since it looks like you are transitioning from C to C++, I recommend to read the tour of C++ which shows fundamental C++ principles. For RAII, the gist is to manage resources in special handler objects which allocate in the constructor and deallocate in the destructor, and implement move semantics. This way, you cannot leak resources. Example implementations are std::vector, std::unique_ptr or std::iostream. As another example, consider mutex locking/unlocking:
class Mutex {
public:
void lock() { ... }
void unlock() { ... }
};
When you use it, it easy to forget unlocking in your code, especially when making modifications to existing code. Also, in case of exceptions, you need try/catch blocks to unlock all the time. Instead, define a MutexLocker class:
class MutexLocker
{
public:
MutexLocker(std::mullptr_t) = delete;
MutexLocker(Mutex* m): mutex_(m) {mutex_->lock();}
MutexLocker(MutexLocker const&) = delete;
MutexLocker& operator=(MutexLocker const&) = delete;
MutexLocker(MutexLocker&& l): mutex_(l.mutex_) {l.mutex_ = nullptr;}
MutexLocker& operator=(MutexLocker&& l)
{
mutex_ = l.mutex_,
l.mutex_ = nullptr;
return *this;
}
~MutexLocker() {if (mutex_) {mutex_->unlock()} };
private:
Mutex* mutex_;
};
Now, you can never forget to unlock a Mutex. The MutexLocker object cannot be copied, but you can transfer ownership. This is superior to anything you can do in C.
For formatting output, you can google "variadic template printf" which should give you some examples, e.g. on Wikipedia:
void printf(const char *s)
{
while (*s) {
if (*s == '%') {
if (*(s + 1) == '%') {
++s;
}
else {
throw std::runtime_error("invalid format string: missing arguments");
}
}
std::cout << *s++;
}
}
template<typename T, typename... Args>
void printf(const char *s, T value, Args... args)
{
while (*s) {
if (*s == '%') {
if (*(s + 1) == '%') {
++s;
}
else {
std::cout << value;
s += 2; // this only works on 2 characters format strings ( %d, %f, etc ). Fails miserably with %5.4f
printf(s, args...); // call even when *s == 0 to detect extra arguments
return;
}
}
std::cout << *s++;
}
}
Or you can use a library, e.g. boost::format or probably thousands of other implementations. If it is only for logging, you could take a look at a logging framework, e.g. boost.log.
First, even it often leads to harder to maintain code, you call always use C techniques in C++. stdio.h functions work natively in C++ and almost all macro are translated the same.
If you want to make use of c++ goodies (better type control at compile time)... you will have to forget old C variadic functions, notably all xprintf. There may be one interesting part anyway with templates.
Anyway the example given in the referenced Q&A is all you need here. Formatting instructions are simply injected in streams the same values are.
But here is a C++11 example showing that you can do what you want without using any macro. It is much longer than the C macro version, but it looks form me much more clear and extensible without the ugly do { ... } while 0 idom:
#include <iostream>
#include <string>
// disp is a variadic templated function injecting any arguments to a stream
// version for one single arg
template <typename T>
void disp(std::ostream& out, T arg) {
out << arg;
}
// recursively displays every arg
template <typename T, typename ... U>
void disp(std::ostream& out, T arg, U ... args) {
disp(out, arg) ;
disp(out, args...);
}
/* fatal displays its args to std::cout, preceded with "FATAL " and followed
* by a newline.
* It then does some cleanup and exits
*/
template<typename ... T>
void fatal(T ... args) {
std::cout << "FATAL ";
disp(std::cout, args...);
std::cout << std::endl;
// cleanup
exit(1);
}
int main() {
int i = 21;
int j = 32;
std::string s = "foo";
if(1) fatal(1, " " , s, " ab ", i, " 0x", std::hex, j);
return 0;
}
output is
FATAL 1 foo ab 21 0x20
Last but not least, you'd better use a throw FatalException() where FatalException is a subclass of std::exception instead of directly use exit(1). You could even write to a stringstream and pass the resulting string to the exception instead of writing to a real stream, but then you should be prepared to deal with bad_alloc exceptions.

how to run multiple operator<< in one go

I have implemented a custom logger where I dump information to the corresponding file:
like this:
Logger::log["log_file"] << "Hi" << "Hi again" << "\n";
The implementation of the operator << is as below. Kindly note the place where the buffer is dumped into the stream when it reaches a limit:
//This is the function signature of std::endl and some other manipulators
typedef CoutType& (*StandardEndLine)(CoutType&);
/// This method defines an operator<< to take in std::endl
BasicLogger& operator<<(StandardEndLine manip);
/// write the log items to buffer
template <typename T>
BasicLogger & operator<< (const T& val)
{
std::stringstream *out = BasicLogger::getOut();
*out << val;
if(out->tellp() > 512000/*500KB*/){
flushLog();
}
return *this;
}
My problem is in the lines that have multiple <<s :
Logger::log["log_file"] << "Hi" << "Hi again" << "\n";
after executing << "Hi", the buffer can get full and flushing to the stream is performed.
This is not desirable for me . I am looking for a solution to ignore that limit(500KB) if a line has not ended yet.
Example scenario:
This problem is highlighted when the application writes buffers filled by different threads to the same file: the last line of the first buffer is half written, when the second buffer from another thread writes another 500kb to the file before I can complete the last line of the first buffer.
I appreciate your thoughts and solutions.
thanks
The traditional solution to grouping multiple << into a single flush is to use a temporary sentry object which is destroyed at the end of the statement.
The destructor would flush (if required), and you can even have it append a newline automatically if that's what you want. As per Andrew Medico's comment, the sentry ctor/dtor should lock/unlock as well, if you need synchronization.
An alternative is to gather everything into a local ostringstream in the sentry, and then you only have to lock/write/flush/unlock a single string from the dtor.
Details:
your Logger::log["log_file"] operator should return a temporary object with the behaviour you chose from the options above
your various << are operator calls taking as the first argument, and returning, a reference to your sentry type
at the ;, the temporary sentry goes out of scope and does any flushing work in its destructor.
Note that if you're just delegating to an existing ostream, you can easily have a single templated Logger::sentry& operator<< (Logger::sentry&, T).
Edit: I thought I'd done this before: the question isn't a duplicate, but the answer is. https://stackoverflow.com/a/19520409/212858
I am looking for a solution to ignore that limit(500KB) if a line has not ended yet.
Why not just check that the last character is a '\n' before flushing the log?
If I knew what was in T, I would give you an example. If its a c++11 string you can just do:
char ch = val.getString().back();
if(out->tellp() > 512000/*500KB*/ && ch == '\n'){
flushLog();
}
Simply flag a carrage return:
bool ended = out.str().find('\n') != string::npos;
if(out->tellp() > 512000/*500KB*/ && ended) {
You can change the implementation of the flushLog method. I assume your implementation writes the contents of the internal stringstream into a file and clears it. You can output the contents of the stringstream only up to the last newline:
void Whatever::flushLog()
{
std::stringstream& out = *BasicLogger::getOut();
std::string stuff = out.str();
size_t pos_of_newline = stuff.rfind('\n');
if (pos_of_newline != std::string::npos)
{
std::string write_it_to_file = stuff.substr(0, pos_of_newline + 1);
... write it to file
std::string leftover = stuff.substr(pos_of_newline + 1);
out.str(leftover);
}
}
The code is only an idea; I didn't check it - maybe there are some bugs. In additon: the str() call duplicates the contents of the stringstream; you might want to use its rdbuf instead (I have no experience with rdbuf, so cannot recommend anything).
Following Useless's suggestion (A suggestion shot by a user called Useless!!!),
I solved my issue using Sentry(temporary) objects:
Logger::log["log_file"] will return the correct instance of BasicLogger
operator<< in BasicLogger will return a copy of a Sentry object.
The subsequent <<s will be taken care of by operator<< in the Sentry object
Sentry will eventually goes out of scope upon hitting ; where its destructor will do the main job:
class BasicLogger {
/// operator overload. write the log items to buffer
template<typename T>
Sentry operator<<(const T& val) {
Sentry t(*this,*getOut());
t << val;//do the first << here
return t;
}
//...
class Sentry {
std::stringstream &out;
BasicLogger &basicLogger;
public:
Sentry(BasicLogger & basicLogger_, std::stringstream &out_) :
out(out_), basicLogger(basicLogger_) {
}
Sentry(const Sentry& t) :
basicLogger(t.basicLogger), out(t.out) {
}
template<typename T>
/// operator overload
Sentry & operator<<(const T& val) {
out << val;
return *this;
}
~Sentry() {
// by some googling this estimated hardcode value promises less cycles to write to a file
if (out.tellp() > 512000/*500KB*/) {
basicLogger.flushLog();
}
}
};
//...
};
class Logger {
//...
public:
static Logger log;
virtual BasicLogger & operator[](const std::string &key);
virtual ~Logger();
};

How does QDebug() << stuff; add a newline automatically?

I'm trying to implement my own qDebug() style debug-output stream, this is basically what I have so far:
struct debug
{
#if defined(DEBUG)
template<typename T>
std::ostream& operator<<(T const& a) const
{
std::cout << a;
return std::cout;
}
#else
template<typename T>
debug const& operator<<(T const&) const
{
return *this;
}
/* must handle manipulators (endl) separately:
* manipulators are functions that take a stream& as argument and return a
* stream&
*/
debug const& operator<<(std::ostream& (*manip)(std::ostream&)) const
{
// do nothing with the manipulator
return *this;
}
#endif
};
Typical usage:
debug() << "stuff" << "more stuff" << std::endl;
But I'd like not to have to add std::endl;
My question is basically, how can I tell when the return type of operator<< isn't going to be used by another operator<< (and so append endl)?
The only way I can think of to achieve anything like this would be to create a list of things to print with associated with each temporary object created by qDebug(), then to print everything, along with trailing newline (and I could do clever things like inserting spaces) in ~debug(), but obviously this is not ideal since I don't have a guarantee that the temporary object is going to be destroyed until the end of the scope (or do I?).
Something like this will do:
struct debug {
debug() {
}
~debug() {
std::cerr << m_SS.str() << std::endl;
}
public:
// accepts just about anything
template<class T>
debug &operator<<(const T &x) {
m_SS << x;
return *this;
}
private:
std::ostringstream m_SS;
};
Which should let you do things like this:
debug() << "hello world";
I've used a pattern like this combined with a lock to provide a stream like logging system which can guarantee that log entries are written atomically.
NOTE: untested code, but should work :-)
Qt uses a method similar to #Evan. See a version of qdebug.h for the implementation details, but they stream everything to an underlying text stream, and then flush the stream and an end-line on destruction of the temporary QDebug object returned by qDebug().
When you write that this is the typical usage:
debug() << "stuff" << "more stuff" << std::endl;
are you definitely planning to construct a debug object each time you use it? If so, you should be able to get the behavior you want by having the debug destructor add the newline:
~debug()
{
*this << std::endl;
... the rest of your destructor ...
}
That does mean you cannot do something like this:
// this won't output "line1" and "line2" on separate lines
debug d;
d << "line1";
d << "line2";
The stream insertion (<<) and extraction (>>) are supposed to be non-members.
My question is basically, how can I
tell when the return type of
operator<< isn't going to be used by
another operator<< (and so append
endl)?
You cannot. Create a member function to specially append this or append an endl once those chained calls are done with. Document your class well so that the clients know how to use it. That's your best bet.