proxygen
Log Handlers

The LogHandler class defines the interface for classes that wish to be notified of log messages.

LogHandler objects can be attached to specific log categories to be notified about log messages sent to that category or any of its children categories. Attaching a LogHandler to the root category will cause it to be notified about every enabled log message.

Built-in Log Handlers

The logging library currently provides a few basic built-in LogHandler implementations.

stream Handler Type

In the configuration settings, you can use the stream type to define a log handler that will write to stdout or stderr. The stream property of the log handler specifies which stream to write to. For example, the following defines a handler named myhandler that writes to stderr

1 myhandler=stream:stream=stderr

file Handler Type

A file handler type is also provided that appends log messages to a file on disk. The path option controls which file to write to. For example:

1 myhandler=file:path=/var/log/my.log

However, note that the file handler is currently not registered by default by folly::initLogging(). This log handler allows appending to arbitrary files based on the configuration settings. You should only enable this handler type if you trust the source of your configuration string. (For instance, this handler is potentially unsafe if your program runs with elevated privileges but users with lower privilege levels can write to your configuration file.)

The following code snippet can be used to explicitly enable this log handler type. It can be called before initLogging() to support the file handler type in the configuration string passed to initLogging().

1 folly::LoggerDB::get()->registerHandlerFactory(
2  std::make_unique<folly::FileHandlerFactory>());

Handler Options

The built-in handler types also accept several options to control their behavior. These include:

async

The async option controls whether log messages should be written asynchronously in a separate thread (when async is true) or immediately in the thread that generated the log messages (when async is false).

This mainly affects the behavior when log messages are being generated faster than they can be written to the output file or stream:

  • Using async=true will ensure that your program never blocks waiting to write the messages. Instead, the handler will start dropping log messages when this occurs. When it is able to catch up it will emit a message indicating how many messages were dropped.
  • Using async=false will ensure that no log messages are dropped, at the expense of blocking your program's normal processing until the log messages can be written.

One additional consideration is that async=false will ensure that all log messages have been flushed if your program crashes. With async=true it is possible to lose some recent messages on program crash. For instance, if one thread logs a message and then dereferences a null pointer, async=false will ensure that the log message has been flushed before the thread can proceed to dereference the null pointer. However with async=true the logging I/O thread may not have flushed the log message by the time the thread that generated the message crashes.

With async=true, the max_buffer_size option controls how much log data may buffered in memory before dropping new log messages. This option specifies the maximum number of bytes of unflushed log data to keep. New log messages that would trigger this limit to be exceeded will be discarded. (Log messages are either entirely kept or discarded; partial messages are never kept.)

formatter

The formatter parameter controls how log messages should be formatted.

Currently the only built-in log formatter is glog, which formats log messages similarly to glog. Additional formatters may be added in the future, and it is also possible to implement your own LogFormatter class.

Default Handler Configuration

By default initLogging() creates a single log handler named default. This log handler is installed on the root log category, and logs all messages to stderr using a message format similar to that used by glog.

This default log handler has the async option disabled by default. This means that initLogging() will not spawn a separate logging I/O thread by default. However, log messages may delay normal program processing if they are being generated faster than they can be written to stderr.

High performance programs that want to avoid performance hiccups caused by logging may wish to enable the async option on the default log handler. This can easily be changed with the logging configuration string. For instance, the following string sets the root category's log level to WARN and enables the async option on the default log handler:

1 WARN; default:async=true

Custom Log Handlers

It is possible to define your own custom LogHandler class should you choose to. The LogHandlerFactory API enables you to create your own custom LogHandler types from configuration settings parsed by parseLogConfig(). You can use LoggerDB::get()->registerHandlerFactory() to register your own custom log handler type.

StandardLogHandler

The StandardLogHandler class is an implementation of LogHandler that splits log message processing into two steps: formatting the message to a string, and then writing that string somewhere.

It uses a LogFormatter class to perform the message formatting, and a LogWriter class to write the formatted message.

You can provide only a custom LogFormatter or LogWriter implementation if you want to customize one of these two steps without providing a full LogHandler implementation of your own.

The StandardLogHandlerFactory class can then be used to implement your own custom LogHandlerFactory that creates a StandardLogHandler with your custom log formatter or writer type.