Using qi::log¶
Introduction¶
Header: <qi/log.hpp>
Overview¶
Log are hierarchical with ”.” as separator. Each level of hierarchy is called a category.
For example, for an instant messaging service, categories may be:
im.audio
im.audio.input
im.audio.output
im.audio.internal
im.video
im.video.internal
im.http
This allows easy log filtering in external log tools.
There are 7 levels of log:
silent: | Hide logs. |
---|---|
fatal: | Used before the program exit. |
error: | A classical error. |
warning: | Useful to warn user. |
info: | Useful to user information. |
verbose: | Not mandatory but useful to user information. |
debug: | Useful to developer. Not compile on release. |
Writing logs¶
There is a log function for each level except silent. Those functions are basic streams.
std::string msg = "Message to print with number: ";
qiLogFatal("ca.te.go.ry") << msg << 1;
qiLogError("ca.te.go.ry") << msg << 2;
qiLogWarning("ca.te.go.ry") << msg << 3;
qiLogInfo("ca.te.go.ry") << msg << 4;
qiLogVerbose("ca.te.go.ry") << msg << 5;
qiLogDebug("ca.te.go.ry") << msg << 6;
Note
Do not add enlines manually, qi::log automatically adds them at the end of each message.
To avoid typing category each time (and so make mistakes), there is a scope
function to set it globally: qiLogCategory(const char*);
Note
It is always allowed to set a specific category for a message even if a global category is set.
qiLogCategory("ca.te.go.ry")
qiLogFatal() << "foo";
qiLogError() << "foo";
qiLogWarning() << "foo";
qiLogInfo() << "foo";
qiLogVerbose() << "foo";
qiLogDebug() << "foo";
Warning
Do not use qiLogCategory in a header file because it will globally affect the category of all source files who include it. This may cause undesired categories in log reporting.
(A)synchronous logging¶
By default, logs are synchronous. They can be made asynchronous so that the handling of the log output is done in a separate thread.
To make the logs asynchronous, you need to call qi::log::setSynchronousLog.
Even when logs are asynchronous, they are actually being displayed in their request order.
Add/Remove Log Handlers¶
Warning
Log handlers are called synchronously by default, thus they can deadlock your process. The log handler must be careful not to log in its code-path or it will re-enter!
Also, any blocking code (for example, because of networking) in there might slow down your whole process as it will be called very often.
If you want to receive logs from all the processes, you need a LogManager to which you can subscribe, as described in the Subscribe to LogManager to obtain logs section.
The default handler log to console. The color is enable on tty. The handler can be added or deleted. You just need to give a delegate to a log function with the following prototype:
void logfct(const qi::LogLevel verb,
const qi::Clock::time_point date,
const qi::SystemClock::time_point systemDate,
const char *category,
const char *msg,
const char *file = "",
const char *fct = "",
const int line = 0);
Then you can add the handler with addHandler(name, fctLog)
:cpp:`addHandler("nameofloghandler", logfct);`
and remove it with removeHandler(name).
removeHandler("nameofloghandler");
Filtering logs output¶
It is possible to change the output of log in 3 different ways:
- category,
- level,
- context.
Level¶
level via QI_LOG_LEVEL
environment variable.
If QI_LOG_LEVEL
is set to "fatal"
only fatal logs are
displayed.
If QI_LOG_LEVEL
is set to "info"
, fatal, error,
warning and info logs are displayed.
Note
By default, level is set to info.
It is possible to use corresponding number instead of name of levels.
- Silent
- Fatal
- Error
- Warning
- Info
- Verbose
- Debug
Context¶
context are the meta information collected during the creation of log.
These information are:
- Level,
- Date,
- ThreadId,
- Category,
- File,
- Function.
To set context use QI_LOG_CONTEXT
, which is a bit-field.
1: | Level as complete string |
---|---|
2: | Level as a single letter |
4: | Date of emission |
8: | ThreadId |
16: | Category |
32: | File name and line number |
64: | Function name |
128: | End of line |
Useful values of contexts:
26: | Short level + threadId + category |
---|---|
30: | Short level + threadId + date + category |
126: | Short level + threadId + date + category + file + function |
254: | Short level + threadId + date + category + file + function + eol |
Category filtering¶
category can be filtered via QI_LOG_FILTERS
environment variable.
- is used to remove a category, + to add it, : is the separator.
QI_LOG_FILTERS="-im.audio:+im.video"
QI_LOG_FILTERS
support globbing.
QI_LOG_FILTERS="-im*:+im.video*"
It is possible via QI_LOG_FILTERS
to set different level of verbosity
for each category via =.
# set level of verbosity to warning for im* except for im.video to debug.
QI_LOG_FILTERS="+im*=3:+im.video=6"
Warning
Due to this feature, use QI_LOG_LEVEL
with QI_LOG_FILTERS
may
be hazardous.