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();
};
Related
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).
I'm learning c++ (coming from a C and Java university coursework) and today I want to write a class that filters the bytes taken from a generic stream and writes its output to another stream.
To be coincise, let's say I want to make a class that base64-encodes the input and writes the output to stdout.
In bash I would write:
echo "some input data" | base64
In C++ i want to implement a class MyB64Encoder that would behave like this:
std::cout << myB64EncoderObject << "some input data";
//Alternatively, is it possible to make it like this?
std::cout << MyB64Encoder << "some input data";
The thing is, the myB64EncoderObject has, of course, to maintain an internal state and an internal buffer. To prevent blocking and excessive memory usage, it must be able to read and process small chunks of data and output each one of them immediately after it has been processed.
There are a few more things to take care of:
The object must wait for the output stream to be able to receive data
The object must throw an error if there is no stream reading from it (kinda like a broken pipe?)
What would be the best approach to a problem like this, in terms of efficiency? How would I implement it in modern C++1x?
The existing things that behave like this:
std::cout << myB64EncoderObject << "some input data";
are I/O manipulators (eg. std::boolalpha, std::hex, ...). However, these just set flags on the stream that it already knows how to interpret.
If you want to keep that syntax, you'll need to something more complex, namely an intermediate wrapper:
class B64Wrapper {
std::ostream &os_;
B64Encoder &enc_; // only if your encoder is really stateful
public:
B64Wrapper() = delete;
B64Wrapper(B64Wrapper&&) = default;
B64Wrapper(B64Wrapper const&) = default;
B64Wrapper(std::ostream &os, B64Encoder &enc) : os_(os), enc_(enc) {}
template <typename T>
B64Wrapper& operator<< (B64Wrapper &self, T val) {
self.enc_.encode(os_, val);
return self;
}
};
B64Wrapper operator<< (std::ostream &os, B64Encoder &enc) {
return B64Wrapper(os, enc);
}
(note you still need to write the B64Encoder::encode(std::ostream &, T value) method).
If your encoder isn't really stateful, you don't need a reference to it, and declare B64Encoder as an empty tag type with a global instance to get the same effect - in that case it only exists to select the operator<< overload.
The other approach is to write a std::basic_streambuf implementation which encodes the input to sputc/sputn/xsputn. It can forward everything else to a wrapped streambuf or to the base class, depending on what you inherit from.
You can do something like this:
class MyEncoder
{
public:
private:
std::ostream* os = nullptr;
// This overload deals with:
// std::cout << myEncoder ...
friend MyEncoder& operator<<(std::ostream& os, MyEncoder& me)
{
// grab a reference to the target output stream
me.os = &os;
return me;
}
// This overload deals with:
// std::cout << MyEncoder() ...
friend MyEncoder& operator<<(std::ostream& os, MyEncoder&& me)
{
// the temporary is currently bound to the l-value parameter me
// so we can just pass this call on to the previous overload
return os << me;
}
// This overload deals with:
// myEncoder << <anything else>
template<typename T>
friend MyEncoder& operator<<(MyEncoder& me, T const& v)
{
// only encode if there is an output stream to send the data to
// this will only be set if one of the above overloads was called
if(!me.os)
throw std::runtime_error("no stream to receive encoded data");
// do your encoding here
(*me.os) << "{encoded: " << v << "}";
return me;
}
};
Basically to achieve this:
std::cout << MyEncoder() << "some data: " << 45;
// ^ calls operator<<(MyEncoder&, 45)
// ^ calls operator<<(MyEncoder&, "some data: ")
// ^ calls operator<<(std::cout, MyEncoder())
The calls go left to right.
It may seem a little involved but it is basically covering 3 different call possibilities.
MyEncoder encoder;
std::cout << encoder; // MyEncoder& object
std::cout << MyEncoder(); // (temporary) MyEncoder&& object
encoder << "anything else" // A MyEncoder& receiving any other object
The first 2 operators are overloaded to set the internal std::ostream* and the third operator is overloaded to do the actual encoding.
I don't know why this is erroring, but I'm just trying to add something "akin" to endl so that I can throw what's in an ostringstream to our debugger. I have the following:
class debug_stream_info
{
public:
debug_stream_info(int errorLine, char *errorFile, int level)
:m_errorLine(errorLine), m_errorFile(errorFile), m_logLevel(level)
{
}
friend std::basic_ostringstream<char>& operator<<(std::basic_ostringstream<char>& os, debug_stream_info& debug_info);
private:
int m_errorLine;
std::string m_errorFile;
int m_logLevel;
};
std::basic_ostringstream<char>& operator<<(std::basic_ostringstream<char>& os, debug_stream_info& debug_info)
{
// Write the stream's contents to cpu_debug
// Deleted custom logging function. No errors here though
// Clear the stream for re-use.
os.str("");
os.seekp(0);
return os;
}
int main(int argc, char** argv)
{
std::ostringstream myout;
myout << "hey there" << " and some more " << "Numbers!!: " << 435 << 54.2 << " that's good for numbers" << debug_stream_info(__LINE__, __FILE__, LOG_LEVEL);
return 0;
}
The error I'm getting is: error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'debug_stream_info' (or there is no acceptable conversion) for the line in main. This is on VS2008.
I'm including sstream, iostream, etc, and have the namespaces set up right. I'm getting no other errors. I even tried replacing all occurrances of basic_ostream with just ostringstream and there was no difference (I'll be having a w_char version later, but I wanted the simple case to work first). I made the object on the line above and then passed a fully-constructed object on the line, and the error was exactly the same. I've changed the signature of the second argument to and from const with no change as well.
Any ideas on what I'm doing wrong here?
Edit: since EVERY response seems to want to put it there, I can NOT use std::ostream because I want this to work ONLY for std::ostringstream (and std::basic_ostringstream) and not for any type of output stream. Besides, the function wouldn't compile with ostream anyways, since I'm using the os.str() method, which isn't in ostream, only the sub-classes.
The real problem with your code is that you've overloaded std::ostringstream rather than std::ostream. So your code would work if you write this:
debug_stream_info info(/** blah blah**/);
std::ostringstream oss;
oss << info ; //OK
However this will not work:
oss << 1 << info; //ERROR
This is compilation error because the expression oss<<1 returns an object of type std::ostream& which doesn't have overload which takes debug_stream_info as second argument. That means if you use cast as:
static_cast<std::ostringstream&>(oss << 1) << info; //OK
then that should work again.
So the solution is to overload std::ostream, instead of std::basic_ostringstream.
Also, the second parameter should be const & . This is also a problem with your code.
So write this:
std::ostream& operator<<(std::ostream&, debug_stream_info const &);
//^^^^^^^ note this
The second parameter should be const & so that you could write temporary objects to the stream.
debug_stream_info(__LINE__, __FILE__, LOG_LEVEL); is creating unnamed object which is not returning anything hence error
#include <iostream>
#include <cstdio>
#include <sstream>
using namespace std;
class debug_stream_info
{
public:
debug_stream_info(int errorLine, char *errorFile, int level)
:m_errorLine(errorLine), m_errorFile(errorFile), m_logLevel(level)
{
}
friend std::basic_ostringstream<char>& operator<<(std::basic_ostringstream<char>& os, debug_stream_info& debug_info);
std::ostringstream& fun(std::ostringstream& os)
{
os<<"Ashish"<<endl;
return os;
}
private:
int m_errorLine;
std::string m_errorFile;
int m_logLevel;
};
std::basic_ostringstream<char>& operator<<(std::basic_ostringstream<char>& os, debug_stream_info& debug_info)
{
// Write the stream's contents to cpu_debug
// Deleted custom logging function. No errors here though
// Clear the stream for re-use.
// os.str("");
// os.seekp(0);
return os;
}
int main(int argc, char** argv)
{
std::ostringstream myout, test;
myout << "hey there" << " and some more " << "Numbers!!: " << 435 << 54.2 << " that's good for numbers"
<< debug_stream_info(1, "/home/ashish/test", 1).fun(test);
return 0;
}
Nawaz has explained very clearly why you're getting the error. The
usual solution in this case is to define your own stream type, unrelated
to std::istream. Something along the lines of:
class DebugStream
{
std::ostringstring* collector;
public:
template <typename T>
DebugStream& operator<<( T const& value )
{
if ( collector != NULL ) {
*collector << value;
}
return *this;
}
};
There are infinite variations on this; in your case, you could add a
non-template member function for your type; more likely, you'd add a
constructor which took the same arguments:
DebugStream( int lineNumber, std::string const& filename, int logLevel )
: collector( isActive( logLevel ) ? new std::ostringstream : NULL )
{
// Initial insertion of lineNumber, filename, timestamp...
}
You can also add a destructor which atomically flushes the collected
data to a file (or sends an email, or writes it to the system log, or
whatever). (Be very careful about this. You don't want an exception to
escape from the destructor, even if the logging fails.)
Finally, you might want to use a custom streambuf, rather than
stringstream. Say one that keeps the allocated buffer from one
instance to the next. And if you do this, rather than newing the
stream each time, you might pick up an instance from a table, indexed by
the log level (and initialized from a configuration file).
I would like to be able to do:
foo(stringstream()<<"number = " << 500);
EDIT: single line solution is crucial since this is for logging purposes. These will be all around the code.
inside foo will print the string to screen or something of the sort.
now since stringstream's operator<< returns ostream&, foo's signature must be:
foo(ostream& o);
but how can I convert ostream& to string? (or char*).
Different approaches to achieving this use case are welcome as well.
The obvious solution is to use dynamic_cast in foo. But the given
code still won't work. (Your example will compile, but it won't do what
you think it should.) The expression std::ostringstream() is a
temporary, you can't initialize a non-const reference with a temporary,
and the first argument of std::operator<<( std::ostream&, char const*)
is a non-const reference. (You can call a member function on a
temporary. Like std::ostream::operator<<( void const* ). So the code
will compile, but it won't do what you expect.
You can work around this problem, using something like:
foo( std::ostringstream().flush() << "number = " << 500 );
std::ostream::flush() returns a non-const reference, so there are no
further problems. And on a freshly created stream, it is a no-op.
Still, I think you'll agree that it isn't the most elegant or intuitive
solution.
What I usually do in such cases is create a wrapper class, which
contains it's own std::ostringstream, and provides a templated
member operator<< which forwards to the contained
std::ostringstream. Your function foo would take a const
reference to this—or what I offen do is have the destructor call
foo directly, so that the client code doesn't even have to worry about
it; it does something like:
log() << "number = " << 500;
The function log() returns an instance of the wrapper class (but see
below), and the (final) destructor of this class calls your function
foo.
There is one slight problem with this. The return value may be copied,
and destructed immediately after the copy. Which will wreck havoc with
what I just explained; in fact, since std::ostringstream isn't
copyable, it won't even compile. The solution here is to put all of the
actual logic, including the instance of std::ostringstream and the
destructor logic calling foo in a separate implementation class, have
the public wrapper have a boost::shared_ptr to it, and forward. Or
just reimplement a bit of the shared pointer logic in your class:
class LogWrapper
{
std::ostringstream* collector;
int* useCount;
public:
LogWrapper()
: collector(new std::ostringstream)
, useCount(new int(1))
{
}
~LogWrapper()
{
-- *useCount;
if ( *useCount == 0 ) {
foo( collector->str() );
delete collector;
delete useCount;
}
}
template<typename T>
LogWrapper& operator<<( T const& value )
{
(*collector) << value;
return *this;
}
};
Note that it's easy to extend this to support optional logging; just
provide a constructor for the LogWrapper which sets collector to
NULL, and test for this in the operator<<.
EDITED:
One other thing occurs to me: you'll probably want to check whether the
destructor is being called as a result of an exception, and not call
foo in that case. Logically, I'd hope that the only exception you
might get is std::bad_alloc, but there will always be a user who
writes something like:
log() << a + b;
where the + is a user defined overload which throws.
I would suggest you to use this utility struct:
struct stringbuilder
{
std::stringstream ss;
template<typename T>
stringbuilder & operator << (const T &data)
{
ss << data;
return *this;
}
operator std::string() { return ss.str(); }
};
And use it as:
void f(const std::string & s );
int main()
{
char const *const pc = "hello";
f(stringbuilder() << '{' << pc << '}' );
//this is my most favorite line
std::string s = stringbuilder() << 25 << " is greater than " << 5 ;
}
Demo (with few more example) : http://ideone.com/J995r
More on my blog : Create string on the fly just in one line
You could use a proxy object for this; this is a bit of framework, but if you want to use this notation in a lot of places then it may be worth it:
#include <iostream>
#include <sstream>
static void foo( std::string const &s )
{
std::cout << s << std::endl;
}
struct StreamProxy
{
std::stringstream stream;
operator std::string() { return stream.str(); }
};
template <typename T>
StreamProxy &operator<<( StreamProxy &s, T v )
{
s.stream << v;
return s;
}
static StreamProxy make_stream()
{
return StreamProxy();
}
int main()
{
foo( make_stream() << "number = " << 500 );
}
This program prints
number = 500
The idea is to have a little wrapper class which can be implicitely converted into a std::string. The << operator is simply forwarded to the contained std::stringstream. The make_stream() function is strictly speaking not necessary (you could also say StreamProxy(), but I thought it looks a bit nicer.
A couple of options other than the nice proxy solution just presented by Frerich Raabe:
Define a static string stream variable in the header that defines the logging function and use the comma operator in your invocation of the logging function so that this variable is passed rather than the ostream& returned by the stream insertion operator. You can use a logging macro to hide this ugliness. The problem with this solution is that it is a bit on the ugly side, but this is a commonly used approach to logging.
Don't use C++ I/O. Use a varargs C-style solution instead. Pass a format string as the first argument, with the remaining arguments being targets for that format string. A problem with this solution is that even if your compiler is smart enough to ensure that printf and its cousins are safe, the compiler probably won't know that this new function is a part of the printf family. Nonetheless, this is also a commonly used approach.
If you don't mind using macros functions, you can make the logging function accept const string&, and use the following macro
#define build_string(expr) \
(static_cast<ostringstream*>(&(ostringstream().flush() << expr))->str())
And suppose you foo has signature void foo(const string&), you only need the one-liner
foo(build_string("number = " << 500))
This was inspired by James Kanze's answer about static_cast and stringstream.flush. Without the .flush() the above method fails with unexpected output.
Please note that this method should not leak memory, as temporary values, whether in the pointer form or not, are still allocated on the stack and hence destroyed upon return.
Since you're converting to string anyways, why not
void foo(const std::string& s)
{
std::cout << "foo: " << s << std::endl;
}
...
std::stringstream ss;
ss << "number = " << 500;
foo(ss.str());
This is not possible. As the name ostream implies, it is used for output, for writing to it. You could change the parameter to stringstream&. This class has the method str() which returns a std::string for your use.
EDIT I did not read the issue with operator << returning ostream&. So I guess you cannot simply write your statements within the functions argument list but have to write it before.
You can create a small wrapper around std::ostringstream that will convert back to std::string on use, and have the function take a std::string const &. The first approach to this solution can be found in this answer to a different question.
On top of that, you can add support for manipulators (std::hex) if needed.
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.