The result of a few hours is this: https://github.com/carlonluca/LightLogger. I'm using it on Windows/Linux/Mac OS/iOS/Android. This is an overview:
- Simple: include the header and build.
- Logging to Android results in logs sent to logcat (consider having a look at logcat-colorize, pretty project: https://bitbucket.org/brunobraga/logcat-colorize).
- Supports the usual feature of log levels.
- Supports coloring of logs: coloring is implemented using ANSI Escape sequences on Linux and MacOS. On Windows I disabled it, but you can enable if you're using something like cygwin or similar. For iOS I use XcodeColors, a great project: https://github.com/robbiehanson/XcodeColors. So a specific implementation is reserved for that platform.
- Selecting debug levels with a macro at build-time enables/disables logs. Compiler optimizations should, in most cases, simply strip logs entirely from the binary, resulting in no/minimal overhead.
- It is possible to reimplement the "sink" of the logs by reimplementing an output.
- I preferred the printf way of formatting logs to the stream implementation. Anyway I tried to provide both. The usage of a "null sink" when logs are disabled should, together with compiler optimizations, make the overhead minimal.
- Each log is flushed to avoid issues related to buffering. This might increase the overhead, but it is simple to remove it.
- On Windows/Linux/iOS a stack trace function is also available to show the current call stack.
- Should be entirely thread-safe.
- Each log can be associated to a tag; I commonly use this with grep to filter logs by module.
How to Use
Just include in your sources and you're done. Most useful functions are those level-based:inline bool log_info_t_v(const char* log_tag, const char* format, va_list args);
inline bool log_info_t(const char* log_tag, const char* format, ...);
inline bool log_info_v(const char* format, va_list args);
inline bool log_info(const char* format, ...);
These functions work differently according to the platform: on Android send INFO logs to logcat, on iOS print colored text to Xcode (and thus the XcodeColors plugin is needed if you keep colors enabled), on Windows simply print text and on Mac OS/Linux print text with ANSI colors to the shell. I use the return type to do something like:
if (!condition)
return log_warn("Ooops, something bad happened, returning failure.");
These functions are "wrappers" for the LC_Log template. You choose a delegate and call:
LC_Log
LC_Log
or use the default logger:
LC_LogDef(...).printf(...);
LC_LogDef(...) << "Some stream based " << "text.";
For specific cases I also needed to write text with specific attributes in the past, so I added something like:
inline bool log_formatted_t_v(
const char* log_tag,
LC_LogAttrib a,
LC_LogColor c,
const char* format,
va_list args
);
inline bool log_formatted_t(
const char* log_tag,
LC_LogAttrib a,
LC_LogColor c,
const char* format,
...
);
inline bool log_formatted_v(
const char* format,
va_list args
);
inline bool log_formatted(
LC_LogAttrib a,
LC_LogColor c,
const char* format,
...
);
inline bool log_formatted(
LC_LogColor c,
const char* format,
...
);
There are a few macros I use to configure for each project: COLORING_ENABLED to enable colors, BUILD_LOG_LEVEL_* to set the logging verbosity and XCODE_COLORING_ENABLED to enable/disable XcodeColors support.
In github you'll find Qt, iOS/XCode and Android sample projects.
How it Works
Pretty simple: wrapper functions like log_info(...) use the template class LC_Log- LC_Output2Std: outputs to standard output, adding ANSI escape codes.
- LC_Output2FILE: write the logs to file (no escape codes here).
- LC_OutputAndroid: implements logging to logcat.
- LC_Output2XCodeColors: implements logging using XcodeColors format.