Logging

This page describes the logging system, as it is in GNU Radio 3.10 and later. For the logging as realized in earlier versions, see Legacy Logging.

= Usage =

Log what you think might be useful. Some fundamental change occurred that you think you'd like to know about later on? Log. An error occurred? Definitely log! A setter method got a value that looks strange, but it's not an error, while probably still worth investigating? Log!

GNU Radio's logging system is very flexible and pretty fast. If you think it makes sense to be able to reconstruct what happened later on, that might be something you want to log (maybe with a low priority, see the section on Levels**.

Never use standard output for logging. GNU Radio's logging system allows for anyone who has special logging needs (e.g. forward all log messages to a central log server, have logs in a graphical environment) to attach to it. Can't do that with,  ,  , or Python's.

Log Message Categories / Levels
The GNU Radio logging system is based on spdlog and hence exposes the same log levels. Use these to denote the severity of your logging message. For example, use  for things that might be interesting for someone observing the operation of your flow graph, use   to notify that something might reasonably be assumed to be wrong and that they need to look into it, and   if something really is wrong and needs to be fixed.

The log levels are ordered, so when you tell the logging system &quot;I don't care about anything less than a warning&quot;, you will not get  messages (and anything below in severity).

The levels are:


 * : Tracing your code's operation. This is mostly for when you're developing an algorithm and need to log specific values that it calculates
 * : Used for debugging purposes, and should not be visible under usual usage.
 * : Information that does not require immediate attention, but might be of interest to someone observing the operation
 * : A warning. Means something might be wrong and it's probably worth looking into it.
 * : An error has occurred. Meaning something definitely is wrong.
 * : An error that cannot be recovered from. For all that concerns your block/functional unit, execution cannot continue sensibly.

Logging in Python
In GNU Radio 3.10, you construct your own logger from. For example, in a block context:

or outside a block

As you can see, we're using the fact that Python has formatted string literals to embed values in log messages. The Python format string syntax  defines how to embed values.

It's generally very straightforward: A formatted string is, where   can contain  , which in turn contain an expression (e.g., a variable name like  , or also formatting instructions):

will apply the  format to the variable. prints a binary representation of the value. prints a hexadecimal representation, wheras  can be used on floating point numbers to express them in exponential notation (  becomes  ). For more information on formats, see the format string syntax.

Logging in C++
If you're writing a block, you will already find  as a member of your block. It is a smart pointer to a logger object. This logger is already set up correctly to log messages with a prefix that quotes your block's alias.

The different log levels are member functions of the logger, so you can log an error using  and a debug message using.

So, in case you need to log a warning, e.g., when a value is invalid and has been replaced, you would follow this example

Outside of blocks, you will have to create your own logger. You simply instantiate a  with the name of the logging &quot;thing&quot; as constructor parameter. An example of that is show below:

Logging Values
Since  is a wrapper around  's logging facilities, it offers the same -based string formatting.

An example of that was shown in  above:

The  get replaced (in their respective order) by the arguments to the logging function.

You can also set the format of fields by using a format specifier syntax very close to Python's format string syntax. For the actual full syntax definition, refer to 's specification.

This being C++, the type of the argument specifies already what type of conversion to use (unlike e.g. libc's, where you need to tell   that an integer needs to be interpreted as an integer), so in most cases, you do not need to specify a format. However, sometimes enforcing a specific notation can be helpful for interpretation.

The format specification follows a colon. Common examples of things that you might want:


 * Formatting floating point in scientific notation:  Here,   causes the number passed in to be represented in scientific notation. Use   instead to only apply for large numbers.
 * Formatting a value with fixed width:  Here, the format specification consists of a space , which is the fill character to be used to pad to the specified length of   characters, and   denotes that the sign should always be printed (not only for negative numbers). Works with numbers just as well as with strings.
 * Formatting data in hexadecimal: : Print using uppercase hexadecimal . Use   for lower case, and use   or   to get a   prefix.
 * Formatting integers as binary: . Use   to get a   prefix.

Logger Construction Cost
While constructing a logger is not very expensive, it's still not something you want to do within a hot loop, as it requires inter-thread coordination. Ideally, you want your entity to hold onto a logger object once it's been created. (This is solved through the  member if you're writing a GNU Radio block. Elsewhere, define your own member if in a class context.)

Logging Cost – Disabled Logging
It's possible to disable logging at compile time (it's not recommended, logging is universally quite useful). Or, that the minimum log level was set to higher than a message's log level, so that, for example  shouldn't actually do anything.

There is an integer comparison at run time that will be incurred by having this logging in the code. Notice, however, that modern CPUs tend to predict that to be false if it happens more often, and even if they didn't, such a comparison is quite cheap (and speculative execution would have continued after the logging in the meantime). Benchmarking showed negligible overhead unless used in tight arithmetic loops. If you are in the rare case that you want to log from such a compute-intense place, you would want to wrap the logging in some preprocessor  magic (or figure out a less invasive place to log).

The format string evaluation only happens when the logging actually takes place. So, even complex logging formats (aside from the code size) do not affect the runtime. (It might, however, affect life time of some values, so it's not free of side effects.)

Logging Cost – Active Logging
is seriously fast. In fact, it beats things like  by orders of magnitude. Especially when logging things that should not happen often (,  or  ), it's probably a good idea to rather log more useful information than less.