proxygen
|
This is a flexible logging library for C++, targeted primarily at debug logging support. It supports hierarchical log categories to easily control debug log levels. It also aims to have minimal performance overhead for disabled log statements, making it possible to keep debug log statements throughout the code base, even in performance critical sections. This allows debug log messages to be easily turned on for particular areas of the code at runtime when necessary to help debug an issue, without having to worry about the overhead of log messages during normal use.
All log messages get logged to a particular log category. Log category names are hierarchical, separated by periods. For instance, folly.io
and folly.futures
are both sub-categories of folly
. folly.io.async
is a sub-category of folly.io
. The root category's name is the empty string.
When a message is logged to a given category, an admittance check is performed to see if the log message should be enabled. The admittance check compares the log level of the message against the effective level of that category.
By default the effective level of a category is the minimum of its level and the level set for any of its parent categories. This means that when you increase the log verbosity for a particular category you automatically turn up the verbosity for the entire tree of children categories underneath it.
For example, setting the log level for the folly
category to WARN
means that log messages to any sub-category under folly
will be admitted if they have a level of WARN
or higher. If the level for folly.io
is DEBUG
, then messages to all categories under folly.io
will admit DEBUG
and higher messages, while the rest of the categories folly
under folly would admit WARN
and higher messages.
However, you can also configure specific log categories to turn off inheritance of their parent log levels. This allows you to increase the log verbosity for a large category tree, but still use a lower verbosity for specific sub-categories. For example, if the folly
category's level is set to DEBUG
, but you disable level inheritance for folly.futures
, the folly.futures
level will not use it's parent's DEBUG
log level, and will only consider the level set locally on this category.
Once a log message is admitted, it is processed by the LogCategory
where it was logged, as well as by all parent log categories, up to the root.
LogHandler
objects can be attached to a log category. When a log message is received at a given log category it will be given to all LogHandler
objects attached to that category.
LogHandler
objects can perform arbitrary actions based on the log message. They may write the message to a local file, print it to stderr
or stdout
, or send the message to a remote logging service.
LogHandlers
may perform their own additional log level check, but by default LogHandlers
process all messages received at the category they are attached to.
The goal of this logging library is to provide a flexible, easy to use logging mechanism that allows debug log statements to be used liberally throughout a code base.
There are two primary design goals for this library:
While there are a number of other logging libraries for C++, none of the ones I have seen fulfill both criteria. The Google logging library (glog) satisfies the first goal, but not the second. Most of the other log libraries I have examined satisfy the second goal, but not the first.
In particular, for item 1, disabled log statements should boil down to a single conditional check. Arguments for the log message should not be evaluated if the log message is not enabled. Unfortunately, this generally means that logging must be done using preprocessor macros.
Item 2 largely boils down to having hierarchical logging categories, to allow easily turning log levels up and down for specific sections of the code base. For instance, this allows a service to enable a higher log level for its primary functionality, while having slightly lower levels for libraries that it depends on.
Beyond the primary goals mentioned above, this log library does have some other advantages over glog:
folly::format()
to generate formatted log messagesTwo separate mechanisms are provided for formatting log messages: basic concatenation of arguments into string (using folly::to<std::string>()
), and more flexible formatting using folly::format()
. This provides convenient and type-safe mechanisms for formatting log messages.
This makes it safer to safer to log arbitrary input data, without worrying if the data may contain potentially malicious terminal escape sequences.
For instance, this helps avoid vulnerabilities like CVE-2013-1862 and CVE-2009-4496.
The LogMessage class indicates if the message contains internal newlines, making it easier for handlers to add a log header to each line of the message, avoiding subsequent lines that do not start with the correct log header.