roq-logging#

Logging is always to stdout and stderr.

Format#

The output format is similar to that used by GLOG.

I0812 03:41:59.012292 120952 producer.cpp:405] Write 1048576 byte(s) (consumed=133169712 produced=20410983 ratio=0.15)
  • The first letter indicates

    • I=INFO

    • W=WARNING

    • E=ERROR

    • C=CRITICAL (=FATAL)

  • Next four letters indicate month (08=August) and day of month (12)

  • Then follows the UTC timestamp with microsecond precision

  • Then follows the thread ID

  • Then follows the filename and line number from which the logging originated

    • The filename does not include the path only to keep the log line shorter

  • Then follows the right square bracket to separate informational content from the actual log message

  • Then the log message

Environment Variables#

Defining ROQ_v instructs the logger to set the verbosity level.

Setting ROQ_v=0 will report verbosity level 0. Setting ROQ_v=1 will report verbosity level 0 and 1. And so on.

The default verbosity level is 0 (if the variable has not been defined).

The following log types will always be reported: FATAL, ERROR, WARNING and INFO.

Performance and Latency#

The logger is synchronous if the program is associated with a terminal.

The logger is asynchronous if the program does not have an associated terminal, e.g. if managed by systemd or Docker.

Asynchronous logging is critical for latency sensitive applications: the unpredictable write operations are completely isolated.

Note

All logging involves extra latency due to formatting of the log message. However, formatting has a mostly predictable latency profile. The most unpredictable part of logging is the interaction with file descriptors; hence the offloading to a secondary thread. Also, using the verbosity level is a way of avoiding even the cost of formatting.

Conventions#

These are not strict rules, only guidelines

  • ROQ_v=0 for truly latency sensitive applications with virtually no logging.

  • ROQ_v=1 for a reasonably latency sensitive application with some support for operational investigations.

  • ROQ_v=2, ROQ_v=3, etc. when debugging issues.

Note

Although a human readable log may not be generated for ROQ_v=0, a binary event log is always generated (also on a secondary thread). The event log captures all important events required for operational investigations. However, there is obviously more work involved with extracting the information compared to simply reading a log file. All this to say that operational support is still possible when using ROQ_v=0.

log::critical#

log::fatal(...)

Indicative of a violated assumption.

The default action is log a backtrace and abort the program. (A core dump might be generated at this point).

log::warn#

log::warn(...)

Useful for e.g. debugging performance issues (could be a warning about latency).

The convention is to log warnings when something unusual happens, e.g. bad data, disconnects, etc.

log::info, log::info<0>#

log::info(...)

Indicate normal progress of the program.

The convention is to log relevant information until a latency sensitive program path is running.

These log messages will always be created and should therefore kept to a minimum for any latency sensitive code.

log::info<1>#

log::info<1>(...)

Used for important messages, e.g. roq::CreateOrder and roq::OrderUpdate.

It should be possible to turn these off (ROQ_v=0) for truly latency sensitive applications. However, it is normally desirable to log these messages for operational support.

log::info<2>#

log::info<2>(...)

Used for non-important messages.

log::info<3>#

log::info<3>(...)

Frequent and non-important messages, e.g. roq::MarketByPriceUpdate.

log::info<4>#

log::info<4>(...)

Low level debugging, e.g. heartbeat, transport, etc.