Let's suppose that we have several levels of logging: trace, debug, info, error.
I was wondering if there is a way to write the following code:
enum log_level = {trace, debug, info, error};
log_level global_log_level = info;
void log(log_level level, string& message){
if (level >= global_log_level){
std::cout << message << std::endl;
}
}
string create_message(){
...
}
log_level level = debug;
log (level, create_message());
without create_message being called if level is smaller that global_severity_level. Indeed, create_message can be quite long, and no matter what it creates a string. If there are a lot of "debug" logs, those ones can become a substantial overhead when running in non-debug mode.
I know it is possible to do so if the function "log" is a macro, calling create_message() only if severity > minimal_severity; but isn't there another way to do this without macros?
EDIT
In the above, I didn't specify create_message, because it could be anything, in particular:
log(level, "Created object " + my_object.getName());
In this case, is there a way to write log such that the full string is not created, in a relatively transparent way for the programmer calling log?
Many thanks
Similar to #sftrabbit, but as suggested by #ipc.
Use a template to avoid the std::function machinery, and the compiler may be able to inline this and thus it hopefully will end up being faster.
template< typename F >
void log(log_level level, F message_creator){
if (level >= global_log_level){
std::cout << message_creator() << std::endl;
}
}
There are several alternatives. An interesting one is to pass create_message as a std::function<std::string()> and call it from within log:
void log(log_level level, std::function<std::string()> message_creator){
if (level >= global_log_level){
std::cout << message_creator() << std::endl;
}
}
Then you would call it like so:
log(level, create_message);
This can work with arbitrary expressions as arguments if you wrap them in a lambda:
log(level, [&](){ return "Created object " + my_object.getName(); });
If you really don't want to argument to be evaluated at all (as you've described in the comments), then you'll need to check the level outside of the call:
if (level >= global_log_level) {
log(level, create_message());
}
#sftrabbit answer is prefered. But just if you dont want to change log(), you can call it:
log (level, (level >= global_log_level)? create_message() : "");
You can create a macro
#define log(level, message) { \
if(level >= global_log_level) {\
cout << message; }}
Now if you call log(debug, create_message()); create_message will be called only if debug level is the desired one.
Related
I have a macro function which works as you would expect:
#define PRECONDITION(testBool) ( !(testBool) ? \
( fprintf(stderr, "%s:%i: Precondition '%s' failed.\n", \
__FILE__, __LINE__, #testBool), \
exit(1) ) : void(sizeof(0)) )
This is great, since I can create nice assertions:
PRECONDITION(5 > 6); // prints "<file>:<line>: Precondition '5 > 6' failed."
While this works, I'm trying to learn a better and more modern way of doing this,
using constexpr, so I can have type safety, use std::err <<.
However, I have not been able to find a source stating how to do this / whether or not it
is actually possible, so I ask here. What I image is something along the lines of:
constexpr void PRECONDITION(bool testBool)
{
if(testBool) { return; }
std::cerr << __SOME_MAGIC__ << ":" << __SOME_MAGIC__ << ":"
<< "Precondition '" << __SOME_MAGIC__ << "' failed." << std::endl;
}
Is it possible to achieve this behaviour?
Short answer: No.
Long answer: Macro expansion is just a textual transform of the source code. Once transformed by macro definitions, source code is "given" to the compiler to compile it. So, macros are expanded before compiler has even started doing its job while constexpr functions are executed on compile time. Therefore, macros and constexpr expressions are 2 different things.
Let's say I have a project with many functions. For debugging purpopses, I want each one of them print out a diagnostic message (or a few) when called:
int f(int arg) {
cerr << "f() called with argument" << arg << endl;
int ret = 42;
cerr << "f() returned " << ret << endl;
return ret;
}
and so on. In one function, there may be as many as five to six messages printed out on cerr. I want to be able to disable them unless a debug flag (like NDEBUG) is set. One thing I could do is wrap each cerr statement with an if-statement.
#ifdef NDEBUG
const bool DEBUG_ON = true;
#else
const bool DEBUG_ON = false;
#endif
int f(int arg) {
if (DEBUG_ON) {
cerr << "f() called with argument" << arg << endl;
}
int ret = 42;
if (DEBUG_ON) {
cerr << "f() returned " << ret << endl;
}
return ret;
}
But it can get really tedious and, in the end, virtually unreadable with a couple dozens of such statements. My idea was to replace cerr with a custom object with an overloaded << operator which would send any arguments passed to it "into the void" like this:
class NullOutStream {
public:
NullOutStream operator<<(...) {
return *this;
}
};
NullOutStream debug_out;
#ifdef NDEBUG
#define debug_out cerr
#else
#define debug_out debug_out
#endif
Although it works perfectly, it doesn't seem very elegant. Is there a standard/nicer way to accomplish this?
There is no "standard" way to do this. There are many logging/assertion libraries that deal with similar issues, and there are different approaches to solve this. A few things to keep in mind:
It may or may not be desirable to keep the side effects of your log statement (as yours does). For example, if you did something like this:
debug_out << ++i;
This would increment i no matter whether you are in debug mode or not. This is probably desirable in this case. Conversely, if you do this:
debug_out << some_object.expensive_to_string_operation();
This would call expensive_to_string_operation() even when you are not in debug mode. This is probably not desirable in this case.
This would not happen if you used printf-style debug macro, e.g. something like this:
#ifdef NDEBUG
#define logf(...)
#else
#define logf(...) printf(__VA_ARGS__)
#endif
The reason being that when in non-debug mode, the arguments would be removed by the preprocessor.
You may want to do other things before or after each log statement, e.g. record a time stamp, flush a log file etc. It is possible to do this with streams by using destructor tricks, but it is more complicated to implement. It is much easier to do this using a function call, e.g. something like this:
#define log(msg) printf("%s: %s\n", timestamp(), msg)
You may want to record file name / line number with your logs. Again, this is easier to do with a function call than with a stream.
Streams may be better if you want custom formatting by object type - the printf interface doesn't lend itself to that very well.
I would recommend to have a look at some existing logging libraries to get an idea of different approaches. I suggest looking at Google's glog library because it has an interesting combination of using streams while retaining the ability to do 'per call' things (e.g. record time stamps, line numbers etc).
I wrote my own logger that I can use as follows:
LOG("This is the number five: " << 5 << ".");
I'd like to write an error checking method that simply takes a return code, checks if it's an error, and if so prints an error message
Thus, I'd like to turn:
if(result == -1)
{
LOG("ERROR! We got a result of: " << result << ".");
// Do some other stuff
}
into:
checkForError(result, "ERROR! We got a result of: " << result << ".");
void checkForError(int result, SomeStringType message)
{
if(result == -1)
{
LOG(message);
// Do some other stuff
}
}
is this possible? I've tried passing it as a char*, a std:string, and as a stringstream, but I can't seem to get it to work correctly
Is there any way to do this so I'm simply concatenating the error message in the call to the function?
Yes, it's possible. You could do it like this:
#define LOG(X) \
do { \
std::ostringstream log_stream; \
log_stream << X; \
LOG::log_internal(log_stream.str()); \
} while (0)
where LOG::log_internal might be declared in your logger header like
struct LOG {
static void log_internal(const std::string &);
};
The main drawback of this is that it's not the most hygienic macro ever -- if the argument X contains semicolons, then you could have additional statements executed inside the macro's scope, and there won't be a compiler error. This macro is far from cryptic though in my opinion, and fortunately you don't actually have to worry about an attacker performing SQL-injection-esque attacks against your macros.
I use loggers that basically look like this in my projects, and I learned to do it this way from other projects. (Actually the one I use is a little more developed, it also passes __FILE__ and __LINE__ to the LOG::log_internal function, and there's log channels and log levels which may or may not be active etc. etc...)
I'm working on a small C++11 application (an SDL2 game) and i'm having a hard time "porting" some of my object-oriented knowledge from PHP/Java to C++. For example, in order to create an elegant error logging approach, i would create a class with various adapters and centralize logging there. I already did that in C++, but i have no idea on how my classes should be using the Logger class.
In Java and PHP, i would use dependency injection, and put the Logger as a class member variable in them. But in C++, what's the proper way? I don't really think that going static would be nice.
Oh man.
To me logging is similar to date/time handling: the basic case is trivial, but anything more than trivial is extremely complicated: no middle ground.
Let me advise you to look into a general purpose logging library such as Pantheios or Boost.Log.
The reason why I advice for this approach as opposed to making "your own effort", is that I know first hand how the "logging situation" goes:
you start with a simple "write to file" or "write to screen"
then you need to also log to another device
then you want to filter out severity levels
then you want to send your logs via pipes
then you want to turn off logging
And it all becomes very, very difficult, and the logging classes start polluting your code.
So, like I said: based on my limited experience, I would encourage you to look into the suggested libraries.
Good luck.
Edit: Boost.Log examples
Just for completeness of the post (refer to page for details).
Trivial case:
#include <boost/log/trivial.hpp>
int main(int, char*[]) {
BOOST_LOG_TRIVIAL(trace) << "A trace severity message";
BOOST_LOG_TRIVIAL(debug) << "A debug severity message";
BOOST_LOG_TRIVIAL(info) << "An informational severity message";
BOOST_LOG_TRIVIAL(warning) << "A warning severity message";
BOOST_LOG_TRIVIAL(error) << "An error severity message";
BOOST_LOG_TRIVIAL(fatal) << "A fatal severity message";
return 0;
}
One approach would be to pass a reference to a logger object around function calls. However, logging is a sort of an orthogonal aspect to application logic, so that explicitly passing that logger and having it as a member quickly becomes a nuisance and only adds artificial complexity.
I prefer having one global logger in the application. Modules can create its own loggers as child loggers of the main logger forming a hierarchy (I think this is similar to Python logging module) and control its output sink and verbosity independently if necessary.
I always use something like this:
class Log
{
public:
Log()
: m_filename( "dafault.log" )
{}
// if you wanna give other names eventually...
Log( const std::string & p_filename )
: m_filename( p_filename )
{}
virtual ~Log()
{
// implement your writeToFile() with std::ofstream
writeToFile( m_filename, m_stream, true );
}
template< typename T >
Log & operator<<( const T & p_value )
{
m_stream << p_value;
return *this;
}
private:
std::string m_filename;
std::ostringstream m_stream;
};
So this way I am able to log like this:
Log() << "My message in the log with numbers " << 1 << 2 << 3 << " and so on...";
Log( "other.log" ) << "Log in another file eventually...";
My current approach is to use a kind of dependency injection, using C++ strengths instead of magic. It does not require on anything specific to C++11 (except that __thread which is an extension could be replaced by thread_local if you wished to be Standard).
class LoggerEngine {
public:
static LoggerEngine* Current() { return CurrentE; }
virtual bool isActive(Level) { return true; }
virtual void log(char const* function,
char const* file,
int line,
std::string message) = 0;
// cuz' decorators rock
LoggerEngine* previous() const { return _previous; }
protected:
LoggerEngine(): _previous(CurrentE) { CurrentE = this; }
~LoggerEngine() { CurrentE = _previous; }
private:
static __thread LoggerEngine* CurrentE;
LoggerEngine* const _previous;
}; // class LoggerEngine
// in some .cpp file:
__thread LoggerEngine* LoggerEngine::CurrentE = 0;
And then, provide macros (to capture function, file and line):
#define LOG(L_, Message_) \
do { if (LoggerEngine* e = LoggerEngine::Current() and e->isActive(L_)) { \
std::ostringstream _28974986589657165; \
_28974986589657165 << Message_; \
e->log(__func__, __FILE__, __LINE__, _28974986589657165.str()); \
}} while(0);
However it could certainly be made better by using shims instead, because even though it prevents any computation in case the level is not active it still requires formatting of the full message (and the necessary memory allocation) even if it is going to truncate the message anyway (for example because it uses fixed-size buffers) and does not easily allow customization of the formatting.
The combination of stacking engines (and popping them off automatically using RAII) with thread-local behavior is really pretty neat. Most code only ever see an interface, without having to thread it by (cool when you have 4/5 different engines), and any level of the stack can switch the engine to something more appropriate.
There is one caveat, as is, no logging occurs before a first Engine is defined. For this reason I've often thought of defaulting to writing to the console if no engine is setup but... I've mostly changed my style to avoid computation before main is called since I cannot dependency-inject during this phase (and it's awkward if an exception fires...)
Usage is like this:
void benchmark() {
LOG(INFO, "Hello, World!");
Timer t;
{
MySinkLogger const _; (void)_; // a logger with "isActive" always false
for (size_t i = 0; i != 10000; ++i) {
LOG(INFO, "Flood!");
}
}
LOG(INFO, "Elapsed: " << t.elapsed());
}
int main() {
MyFileLoggerEngine const _("somefile.log"); (void)_; // a file logger
benchmark();
}
And normally this could create a file "somefile.log" containing:
2013-10-03T18:38:04.645512 mylaptop INFO <test.cpp#42> Hello, World!
2013-10-03T18:38:04.865765 mylaptop INFO <test.cpp#47> Elapsed: 0.220213s
In my program I want to use asserts that show an error message. Apart from the well known workarounds for C and C++ there's the "real" solution as BOOST offers BOOST_ASSERT_MSG( expr, msg ) (see also assert() with message)
But a static message isn't enough for me, I also want to show sometimes the failed variables, e.g. in a case like
BOOST_ASSERT_MSG( length >= 0, "No positive length found! It is " << length )
As you can see I'd like to format the message "string" as an stringstream or ostream as that'd allow me to easily show custom types (assuming I've defined the relevant formating function).
The problem here is that BOOST_ASSERT_MSG is by default requiring a char const * so that's not compatible.
Is there a way to redefine / overload assertion_failed_msg() in such a way that using a stream as message will work? How?
(My naive approach failed as the compiler first wanted to do an operator<<("foo",bar) on the message itself...)
You could define your own macro
#define ASSERT_WITH_MSG(cond, msg) do \
{ if (!(cond)) { std::ostringstream str; str << msg; std::cerr << str.str(); std::abort(); } \
} while(0)
It's relatively trivial to achieve this.
BOOST_ASSERT_MSG( length >= 0, (std::stringstream() << "No positive length found! It is " << length).str().c_str() )
Here is a solution that doesn't rely on macros. Instead, it uses a tiny bit of templating and lambda syntax.
template<typename Fn>
void assert_fn( bool expr, Fn fn) {
if (!expr) {
fn();
abort();
}
}
The argument fn can be any callable.
For instance you can call it like so:
assert_fn( a==b, [&](){ cout << "Assertion failed: a="<< a <<
" is different from but b=" << b << endl; } );
The advantage is that the output is that you are not calling abort explicitly and the output is fully customizable. The this advantage, of course, are the seven extra characters of lambda function boilerplate: [&](){} )
I use the BOOST_ASSERT_MSG with my own wrapper around it, so that specifying the assert message with multiple operator<< seems less complex.
#if defined ASSERT_ENABLED
#define ASSERT(cond, msg) {\
if(!(cond))\
{\
std::stringstream str;\
str << msg;\
BOOST_ASSERT_MSG(cond, str.str().c_str());\
}\
}
#else
#define ASSERT(...)
#endif
usage example, provide custom message like you are outputting to cout:
ASSERT(execSize == (_oldSize - remaining), "execSize : " << execSize << ", _oldSize : " << _oldSize << ", remaining : " << remaining);
What it does is, if ASSERT_ENABLED is defined,enable the assertion messages. if(!(cond)) part is optimization, which avoids the costly string operations specified by macro parameter msg, if cond is true
If you are working on Windows only, you can take a look to assert macro. Under the hood it uses _wassert. You can write your own assert macro using it. For instance in my case if I get some point, I want to show assert without conditions:
#ifdef DEBUG
const std::wstring assert_msg = /* build the string here */;
_wassert(assert_msg.c_str(), _CRT_WIDE(__FILE__), (unsigned)(__LINE__));
#endif
I think on other OS you can do the same trick, just take look at assert macro.