You are here

Logging

Primary tabs

GNUnet is able to log its activity, mostly for the purposes of debugging the program at various levels.

gnunet_common.h defines several log levels:

ERROR
for errors (really problematic situations, often leading to crashes)
WARNING
for warnings (troubling situations that might have negative consequences, although not fatal)
INFO
for various information. Used somewhat rarely, as GNUnet statistics is used to hold and display most of the information that users might find interesting.
DEBUG
for debugging. Does not produce much output on normal builds, but when extra logging is enabled at compile time, a staggering amount of data is outputted under this log level.

Normal builds of GNUnet (configured with --enable-logging[=yes]) are supposed to log nothing under DEBUG level. The --enable-logging=verbose configure option can be used to create a build with all logging enabled. However, such build will produce large amounts of log data, which is inconvenient when one tries to hunt down a specific problem.

To mitigate this problem, GNUnet provides facilities to apply a filter to reduce the logs:

Logging by default
When no log levels are configured in any other way (see below), GNUnet will default to the WARNING log level. This mostly applies to GNUnet command line utilities, services and daemons; tests will always set log level to WARNING or, if --enable-logging=verbose was passed to configure, to DEBUG. The default level is suggested for normal operation.
The -L option
Most GNUnet executables accept an "-L loglevel" or "--log=loglevel" option. If used, it makes the process set a global log level to "loglevel". Thus it is possible to run some processes with -L DEBUG, for example, and others with -L ERROR to enable specific settings to diagnose problems with a particular process.
Configuration files.
Because GNUnet service and deamon processes are usually launched by gnunet-arm, it is not possible to pass different custom command line options directly to every one of them. The options passed to gnunet-arm only affect gnunet-arm and not the rest of GNUnet. However, one can specify a configuration key "OPTIONS" in the section that corresponds to a service or a daemon, and put a value of "-L loglevel" there. This will make the respective service or daemon set its log level to "loglevel" (as the value of OPTIONS will be passed as a command-line argument).

To specify the same log level for all services without creating separate "OPTIONS" entries in the configuration for each one, the user can specify a config key "GLOBAL_POSTFIX" in the [arm] section of the configuration file. The value of GLOBAL_POSTFIX will be appended to all command lines used by the ARM service to run other services. It can contain any option valid for all GNUnet commands, thus in particular the "-L loglevel" option. The ARM service itself is, however, unaffected by GLOBAL_POSTFIX; to set log level for it, one has to specify "OPTIONS" key in the [arm] section.

Environment variables.
Setting global per-process log levels with "-L loglevel" does not offer sufficient log filtering granularity, as one service will call interface libraries and supporting libraries of other GNUnet services, potentially producing lots of debug log messages from these libraries. Also, changing the config file is not always convenient (especially when running the GNUnet test suite).
To fix that, and to allow GNUnet to use different log filtering at runtime without re-compiling the whole source tree, the log calls were changed to be configurable at run time. To configure them one has to define environment variables "GNUNET_FORCE_LOGFILE", "GNUNET_LOG" and/or "GNUNET_FORCE_LOG":
  • "GNUNET_LOG" only affects the logging when no global log level is configured by any other means (that is, the process does not explicitly set its own log level, there are no "-L loglevel" options on command line or in configuration files), and can be used to override the default WARNING log level.
  • "GNUNET_FORCE_LOG" will completely override any other log configuration options given.
  • "GNUNET_FORCE_LOGFILE" will completely override the location of the file to log messages to. It should contain a relative or absolute file name. Setting GNUNET_FORCE_LOGFILE is equivalent to passing "--log-file=logfile" or "-l logfile" option (see below). It supports "[]" format in file names, but not "{}" (see below).

Because environment variables are inherited by child processes when they are launched, starting or re-starting the ARM service with these variables will propagate them to all other services.

"GNUNET_LOG" and "GNUNET_FORCE_LOG" variables must contain a specially formatted logging definition string, which looks like this:

[component];[file];[function];[from_line[-to_line]];loglevel[/component...]

That is, a logging definition consists of definition entries, separated by slashes ('/'). If only one entry is present, there is no need to add a slash to its end (although it is not forbidden either).
All definition fields (component, file, function, lines and loglevel) are mandatory, but (except for the loglevel) they can be empty. An empty field means "match anything". Note that even if fields are empty, the semicolon (';') separators must be present.
The loglevel field is mandatory, and must contain one of the log level names (ERROR, WARNING, INFO or DEBUG).
The lines field might contain one non-negative number, in which case it matches only one line, or a range "from_line-to_line", in which case it matches any line in the interval [from_line;to_line] (that is, including both start and end line).
GNUnet mostly defaults component name to the name of the service that is implemented in a process ('transport', 'core', 'peerinfo', etc), but logging calls can specify custom component names using GNUNET_log_from.
File name and function name are provided by the compiler (__FILE__ and __FUNCTION__ built-ins).

Component, file and function fields are interpreted as non-extended regular expressions (GNU libc regex functions are used). Matching is case-sensitive, ^ and $ will match the beginning and the end of the text. If a field is empty, its contents are automatically replaced with a ".*" regular expression, which matches anything. Matching is done in the default way, which means that the expression matches as long as it's contained anywhere in the string. Thus "GNUNET_" will match both "GNUNET_foo" and "BAR_GNUNET_BAZ". Use '^' and/or '$' to make sure that the expression matches at the start and/or at the end of the string.
The semicolon (';') can't be escaped, and GNUnet will not use it in component names (it can't be used in function names and file names anyway).

Every logging call in GNUnet code will be (at run time) matched against the log definitions passed to the process. If a log definition fields are matching the call arguments, then the call log level is compared the the log level of that definition. If the call log level is less or equal to the definition log level, the call is allowed to proceed. Otherwise the logging call is forbidden, and nothing is logged. If no definitions matched at all, GNUnet will use the global log level or (if a global log level is not specified) will default to WARNING (that is, it will allow the call to proceed, if its level is less or equal to the global log level or to WARNING).

That is, definitions are evaluated from left to right, and the first matching definition is used to allow or deny the logging call. Thus it is advised to place narrow definitions at the beginning of the logdef string, and generic definitions - at the end.

Whether a call is allowed or not is only decided the first time this particular call is made. The evaluation result is then cached, so that any attempts to make the same call later will be allowed or disallowed right away. Because of that runtime log level evaluation should not significantly affect the process performance.
Log definition parsing is only done once, at the first call to GNUNET_log_setup () made by the process (which is usually done soon after it starts).

At the moment of writing there is no way to specify logging definitions from configuration files, only via environment variables.

At the moment GNUnet will stop processing a log definition when it encounters an error in definition formatting or an error in regular expression syntax, and will not report the failure in any way.

Examples

GNUNET_FORCE_LOG=";;;;DEBUG" gnunet-arm -s
Start GNUnet process tree, running all processes with DEBUG level (one should be careful with it, as log files will grow at alarming rate!)
GNUNET_FORCE_LOG="core;;;;DEBUG" gnunet-arm -s
Start GNUnet process tree, running the core service under DEBUG level (everything else will use configured or default level).
GNUNET_FORCE_LOG=";gnunet-service-transport_validation.c;;;DEBUG" gnunet-arm -s
Start GNUnet process tree, allowing any logging calls from gnunet-service-transport_validation.c (everything else will use configured or default level).
GNUNET_FORCE_LOG="fs;gnunet-service-fs_push.c;;;DEBUG" gnunet-arm -s
Start GNUnet process tree, allowing any logging calls from gnunet-gnunet-service-fs_push.c (everything else will use configured or default level).
GNUNET_FORCE_LOG=";;GNUNET_NETWORK_socket_select;;DEBUG" gnunet-arm -s
Start GNUnet process tree, allowing any logging calls from the GNUNET_NETWORK_socket_select function (everything else will use configured or default level).
GNUNET_FORCE_LOG="transport.*;;.*send.*;;DEBUG/;;;;WARNING" gnunet-arm -s
Start GNUnet process tree, allowing any logging calls from the components that have "transport" in their names, and are made from function that have "send" in their names. Everything else will be allowed to be logged only if it has WARNING level.

On Windows, one can use batch files to run GNUnet processes with special environment variables, without affecting the whole system. Such batch file will look like this:

set GNUNET_FORCE_LOG=;;do_transmit;;DEBUG
gnunet-arm -s

(note the absence of double quotes in the environment variable definition, as opposed to earlier examples, which use the shell).
Another limitation, on Windows, GNUNET_FORCE_LOGFILE MUST be set in order to GNUNET_FORCE_LOG to work.

Log files

GNUnet can be told to log everything into a file instead of stderr (which is the default) using the "--log-file=logfile" or "-l logfile" option. This option can also be passed via command line, or from the "OPTION" and "GLOBAL_POSTFIX" configuration keys (see above). The file name passed with this option is subject to GNUnet filename expansion. If specified in "GLOBAL_POSTFIX", it is also subject to ARM service filename expansion, in particular, it may contain "{}" (left and right curly brace) sequence, which will be replaced by ARM with the name of the service. This is used to keep logs from more than one service separate, while only specifying one template containing "{}" in GLOBAL_POSTFIX.

As part of a secondary file name expansion, the first occurrence of "[]" sequence ("left square brace" followed by "right square brace") in the file name will be replaced with a process identifier or the process when it initializes its logging subsystem. As a result, all processes will log into different files. This is convenient for isolating messages of a particular process, and prevents I/O races when multiple processes try to write into the file at the same time. This expansion is done independently of "{}" expansion that ARM service does (see above).

The log file name that is specified via "-l" can contain format characters from the 'strftime' function family. For example, "%Y" will be replaced with the current year. Using "basename-%Y-%m-%d.log" would include the current year, month and day in the log file. If a GNUnet process runs for long enough to need more than one log file, it will eventually clean up old log files. Currently, only the last three log files (plus the current log file) are preserved. So once the fifth log file goes into use (so after 4 days if you use "%Y-%m-%d" as above), the first log file will be automatically deleted. Note that if your log file name only contains "%Y", then log files would be kept for 4 years and the logs from the first year would be deleted once year 5 begins. If you do not use any date-related string format codes, logs would never be automatically deleted by GNUnet.