This patch adds confiugurable delay when starting log processing thread. Signed-off-by: Emil Obalski <emil.obalski@nordicsemi.no>
822 lines
33 KiB
ReStructuredText
822 lines
33 KiB
ReStructuredText
.. _logging_api:
|
|
|
|
Logging
|
|
#######
|
|
|
|
.. contents::
|
|
:local:
|
|
:depth: 2
|
|
|
|
The logging API provides a common interface to process messages issued by
|
|
developers. Messages are passed through a frontend and are then
|
|
processed by active backends.
|
|
Custom frontend and backends can be used if needed.
|
|
Default configuration uses built-in frontend and UART backend.
|
|
|
|
Summary of the logging features:
|
|
|
|
- Deferred logging reduces the time needed to log a message by shifting time
|
|
consuming operations to a known context instead of processing and sending
|
|
the log message when called.
|
|
- Multiple backends supported (up to 9 backends).
|
|
- Custom frontend supported.
|
|
- Compile time filtering on module level.
|
|
- Run time filtering independent for each backend.
|
|
- Additional run time filtering on module instance level.
|
|
- Timestamping with user provided function.
|
|
- Dedicated API for dumping data.
|
|
- Dedicated API for handling transient strings.
|
|
- Panic support - in panic mode logging switches to blocking, synchronous
|
|
processing.
|
|
- Printk support - printk message can be redirected to the logging.
|
|
- Design ready for multi-domain/multi-processor system.
|
|
|
|
Logging v2 introduces following changes:
|
|
|
|
- Option to use 64 bit timestamp
|
|
- Support for logging floating point variables
|
|
- Support for logging variables extending size of a machine word (64 bit values
|
|
on 32 bit architectures)
|
|
- Remove the need for special treatment of ``%s`` format specifier
|
|
- Extend API for dumping data to accept formatted string
|
|
- Improve memory utilization. More log messages fit in the logging buffer in
|
|
deferred mode.
|
|
- Log message is no longer fragmented. It is self-contained block of memory which
|
|
simplifies out of domain handling (e.g. offline processing)
|
|
- Improved performance when logging from user space
|
|
- Improved performance when logging to full buffer and message are dropped.
|
|
- Slightly degrade performance in normal circumstances due to the fact that
|
|
allocation from ring buffer is more complex than from memslab.
|
|
- No change in logging API
|
|
- Logging backend API exteded with function for processing v2 messages.
|
|
|
|
Logging API is highly configurable at compile time as well as at run time. Using
|
|
Kconfig options (see :ref:`logging_kconfig`) logs can be gradually removed from
|
|
compilation to reduce image size and execution time when logs are not needed.
|
|
During compilation logs can be filtered out on module basis and severity level.
|
|
|
|
Logs can also be compiled in but filtered on run time using dedicate API. Run
|
|
time filtering is independent for each backend and each source of log messages.
|
|
Source of log messages can be a module or specific instance of the module.
|
|
|
|
There are four severity levels available in the system: error, warning, info
|
|
and debug. For each severity level the logging API (:zephyr_file:`include/logging/log.h`)
|
|
has set of dedicated macros. Logger API also has macros for logging data.
|
|
|
|
For each level following set of macros are available:
|
|
|
|
- ``LOG_X`` for standard printf-like messages, e.g. :c:macro:`LOG_ERR`.
|
|
- ``LOG_HEXDUMP_X`` for dumping data, e.g. :c:macro:`LOG_HEXDUMP_WRN`.
|
|
- ``LOG_INST_X`` for standard printf-like message associated with the
|
|
particular instance, e.g. :c:macro:`LOG_INST_INF`.
|
|
- ``LOG_INST_HEXDUMP_X`` for dumping data associated with the particular
|
|
instance, e.g. :c:macro:`LOG_HEXDUMP_INST_DBG`
|
|
|
|
There are two configuration categories: configurations per module and global
|
|
configuration. When logging is enabled globally, it works for modules. However,
|
|
modules can disable logging locally. Every module can specify its own logging
|
|
level. The module must define the :c:macro:`LOG_LEVEL` macro before using the
|
|
API. Unless a global override is set, the module logging level will be honored.
|
|
The global override can only increase the logging level. It cannot be used to
|
|
lower module logging levels that were previously set higher. It is also possible
|
|
to globally limit logs by providing maximal severity level present in the
|
|
system, where maximal means lowest severity (e.g. if maximal level in the system
|
|
is set to info, it means that errors, warnings and info levels are present but
|
|
debug messages are excluded).
|
|
|
|
Each module which is using the logging must specify its unique name and
|
|
register itself to the logging. If module consists of more than one file,
|
|
registration is performed in one file but each file must define a module name.
|
|
|
|
Logger's default frontend is designed to be thread safe and minimizes time needed
|
|
to log the message. Time consuming operations like string formatting or access to the
|
|
transport are not performed by default when logging API is called. When logging
|
|
API is called a message is created and added to the list. Dedicated,
|
|
configurable buffer for pool of log messages is used. There are 2 types of messages:
|
|
standard and hexdump. Each message contain source ID (module or instance ID and
|
|
domain ID which might be used for multiprocessor systems), timestamp and
|
|
severity level. Standard message contains pointer to the string and arguments.
|
|
Hexdump message contains copied data and string.
|
|
|
|
.. _logging_kconfig:
|
|
|
|
Global Kconfig Options
|
|
**********************
|
|
|
|
These options can be found in the following path :zephyr_file:`subsys/logging/Kconfig`.
|
|
|
|
:kconfig:`CONFIG_LOG`: Global switch, turns on/off the logging.
|
|
|
|
Mode of operations:
|
|
|
|
:kconfig:`CONFIG_LOG_MODE_DEFERRED`: Deferred mode.
|
|
|
|
:kconfig:`CONFIG_LOG2_MODE_DEFERRED`: Deferred mode v2.
|
|
|
|
:kconfig:`CONFIG_LOG_MODE_IMMEDIATE`: Immediate (synchronous) mode.
|
|
|
|
:kconfig:`CONFIG_LOG2_MODE_IMMEDIATE`: Immediate (synchronous) mode v2.
|
|
|
|
:kconfig:`CONFIG_LOG_MODE_MINIMAL`: Minimal footprint mode.
|
|
|
|
Filtering options:
|
|
|
|
:kconfig:`CONFIG_LOG_RUNTIME_FILTERING`: Enables runtime reconfiguration of the
|
|
filtering.
|
|
|
|
:kconfig:`CONFIG_LOG_DEFAULT_LEVEL`: Default level, sets the logging level
|
|
used by modules that are not setting their own logging level.
|
|
|
|
:kconfig:`CONFIG_LOG_OVERRIDE_LEVEL`: It overrides module logging level when
|
|
it is not set or set lower than the override value.
|
|
|
|
:kconfig:`CONFIG_LOG_MAX_LEVEL`: Maximal (lowest severity) level which is
|
|
compiled in.
|
|
|
|
Processing options:
|
|
|
|
:kconfig:`CONFIG_LOG_MODE_OVERFLOW`: When new message cannot be allocated,
|
|
oldest one are discarded.
|
|
|
|
:kconfig:`CONFIG_LOG_BLOCK_IN_THREAD`: If enabled and new log message cannot
|
|
be allocated thread context will block for up to
|
|
:kconfig:`CONFIG_LOG_BLOCK_IN_THREAD_TIMEOUT_MS` or until log message is
|
|
allocated.
|
|
|
|
:kconfig:`CONFIG_LOG_PRINTK`: Redirect printk calls to the logging.
|
|
|
|
:kconfig:`CONFIG_LOG_PRINTK_MAX_STRING_LENGTH`: Maximal string length that can
|
|
be processed by printk. Longer strings are trimmed.
|
|
|
|
:kconfig:`CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD`: When number of buffered log
|
|
messages reaches the threshold dedicated thread (see :c:func:`log_thread_set`)
|
|
is waken up. If :kconfig:`CONFIG_LOG_PROCESS_THREAD` is enabled then this
|
|
threshold is used by the internal thread.
|
|
|
|
:kconfig:`CONFIG_LOG_PROCESS_THREAD`: When enabled, logging thread is created
|
|
which handles log processing.
|
|
|
|
:kconfig:`CONFIG_LOG_PROCESS_THREAD_STARTUP_DELAY_MS`: Delay in milliseconds
|
|
after which logging thread is started.
|
|
|
|
:kconfig:`CONFIG_LOG_BUFFER_SIZE`: Number of bytes dedicated for the message pool.
|
|
Single message capable of storing standard log with up to 3 arguments or hexdump
|
|
message with 12 bytes of data take 32 bytes. In v2 it indicates buffer size
|
|
dedicated for circular packet buffer.
|
|
|
|
:kconfig:`CONFIG_LOG_DETECT_MISSED_STRDUP`: Enable detection of missed transient
|
|
strings handling.
|
|
|
|
:kconfig:`CONFIG_LOG_STRDUP_MAX_STRING`: Longest string that can be duplicated
|
|
using log_strdup().
|
|
|
|
:kconfig:`CONFIG_LOG_STRDUP_BUF_COUNT`: Number of buffers in the pool used by
|
|
log_strdup().
|
|
|
|
:kconfig:`CONFIG_LOG_DOMAIN_ID`: Domain ID. Valid in multi-domain systems.
|
|
|
|
:kconfig:`CONFIG_LOG_FRONTEND`: Redirect logs to a custom frontend.
|
|
|
|
:kconfig:`CONFIG_LOG_TIMESTAMP_64BIT`: 64 bit timestamp.
|
|
|
|
Formatting options:
|
|
|
|
:kconfig:`CONFIG_LOG_FUNC_NAME_PREFIX_ERR`: Prepend standard ERROR log messages
|
|
with function name. Hexdump messages are not prepended.
|
|
|
|
:kconfig:`CONFIG_LOG_FUNC_NAME_PREFIX_WRN`: Prepend standard WARNING log messages
|
|
with function name. Hexdump messages are not prepended.
|
|
|
|
:kconfig:`CONFIG_LOG_FUNC_NAME_PREFIX_INF`: Prepend standard INFO log messages
|
|
with function name. Hexdump messages are not prepended.
|
|
|
|
:kconfig:`CONFIG_LOG_FUNC_NAME_PREFIX_DBG`: Prepend standard DEBUG log messages
|
|
with function name. Hexdump messages are not prepended.
|
|
|
|
:kconfig:`CONFIG_LOG_BACKEND_SHOW_COLOR`: Enables coloring of errors (red)
|
|
and warnings (yellow).
|
|
|
|
:kconfig:`CONFIG_LOG_BACKEND_FORMAT_TIMESTAMP`: If enabled timestamp is
|
|
formatted to *hh:mm:ss:mmm,uuu*. Otherwise is printed in raw format.
|
|
|
|
Backend options:
|
|
|
|
:kconfig:`CONFIG_LOG_BACKEND_UART`: Enabled build-in UART backend.
|
|
|
|
.. _log_usage:
|
|
|
|
Usage
|
|
*****
|
|
|
|
Logging in a module
|
|
===================
|
|
|
|
In order to use logging in the module, a unique name of a module must be
|
|
specified and module must be registered using :c:macro:`LOG_MODULE_REGISTER`.
|
|
Optionally, a compile time log level for the module can be specified as the
|
|
second parameter. Default log level (:kconfig:`CONFIG_LOG_DEFAULT_LEVEL`) is used
|
|
if custom log level is not provided.
|
|
|
|
.. code-block:: c
|
|
|
|
#include <logging/log.h>
|
|
LOG_MODULE_REGISTER(foo, CONFIG_FOO_LOG_LEVEL);
|
|
|
|
If the module consists of multiple files, then ``LOG_MODULE_REGISTER()`` should
|
|
appear in exactly one of them. Each other file should use
|
|
:c:macro:`LOG_MODULE_DECLARE` to declare its membership in the module.
|
|
Optionally, a compile time log level for the module can be specified as
|
|
the second parameter. Default log level (:kconfig:`CONFIG_LOG_DEFAULT_LEVEL`)
|
|
is used if custom log level is not provided.
|
|
|
|
.. code-block:: c
|
|
|
|
#include <logging/log.h>
|
|
/* In all files comprising the module but one */
|
|
LOG_MODULE_DECLARE(foo, CONFIG_FOO_LOG_LEVEL);
|
|
|
|
In order to use logging API in a function implemented in a header file
|
|
:c:macro:`LOG_MODULE_DECLARE` macro must be used in the function body
|
|
before logging API is called. Optionally, a compile time log level for the module
|
|
can be specified as the second parameter. Default log level
|
|
(:kconfig:`CONFIG_LOG_DEFAULT_LEVEL`) is used if custom log level is not
|
|
provided.
|
|
|
|
.. code-block:: c
|
|
|
|
#include <logging/log.h>
|
|
|
|
static inline void foo(void)
|
|
{
|
|
LOG_MODULE_DECLARE(foo, CONFIG_FOO_LOG_LEVEL);
|
|
|
|
LOG_INF("foo");
|
|
}
|
|
|
|
Dedicated Kconfig template (:zephyr_file:`subsys/logging/Kconfig.template.log_config`)
|
|
can be used to create local log level configuration.
|
|
|
|
Example below presents usage of the template. As a result CONFIG_FOO_LOG_LEVEL
|
|
will be generated:
|
|
|
|
.. code-block:: none
|
|
|
|
module = FOO
|
|
module-str = foo
|
|
source "subsys/logging/Kconfig.template.log_config"
|
|
|
|
Logging in a module instance
|
|
============================
|
|
|
|
In case of modules which are multi-instance and instances are widely used
|
|
across the system enabling logs will lead to flooding. Logger provide the tools
|
|
which can be used to provide filtering on instance level rather than module
|
|
level. In that case logging can be enabled for particular instance.
|
|
|
|
In order to use instance level filtering following steps must be performed:
|
|
|
|
- a pointer to specific logging structure is declared in instance structure.
|
|
:c:macro:`LOG_INSTANCE_PTR_DECLARE` is used for that.
|
|
|
|
.. code-block:: c
|
|
|
|
#include <logging/log_instance.h>
|
|
|
|
struct foo_object {
|
|
LOG_INSTANCE_PTR_DECLARE(log);
|
|
uint32_t id;
|
|
}
|
|
|
|
- module must provide macro for instantiation. In that macro, logging instance
|
|
is registered and log instance pointer is initialized in the object structure.
|
|
|
|
.. code-block:: c
|
|
|
|
#define FOO_OBJECT_DEFINE(_name) \
|
|
LOG_INSTANCE_REGISTER(foo, _name, CONFIG_FOO_LOG_LEVEL) \
|
|
struct foo_object _name = { \
|
|
LOG_INSTANCE_PTR_INIT(log, foo, _name) \
|
|
}
|
|
|
|
Note that when logging is disabled logging instance and pointer to that instance
|
|
are not created.
|
|
|
|
In order to use the instance logging API in a source file, a compile-time log
|
|
level must be set using :c:macro:`LOG_LEVEL_SET`.
|
|
|
|
.. code-block:: c
|
|
|
|
LOG_LEVEL_SET(CONFIG_FOO_LOG_LEVEL);
|
|
|
|
void foo_init(foo_object *f)
|
|
{
|
|
LOG_INST_INF(f->log, "Initialized.");
|
|
}
|
|
|
|
In order to use the instance logging API in a header file, a compile-time log
|
|
level must be set using :c:macro:`LOG_LEVEL_SET`.
|
|
|
|
.. code-block:: c
|
|
|
|
static inline void foo_init(foo_object *f)
|
|
{
|
|
LOG_LEVEL_SET(CONFIG_FOO_LOG_LEVEL);
|
|
|
|
LOG_INST_INF(f->log, "Initialized.");
|
|
}
|
|
|
|
Controlling the logging
|
|
=======================
|
|
|
|
Logging can be controlled using API defined in
|
|
:zephyr_file:`include/logging/log_ctrl.h`. Logger must be initialized before it can be
|
|
used. Optionally, user can provide function which returns timestamp value. If
|
|
not provided, :c:macro:`k_cycle_get_32` is used for timestamping.
|
|
:c:func:`log_process` function is used to trigger processing of one log
|
|
message (if pending). Function returns true if there is more messages pending.
|
|
|
|
Following snippet shows how logging can be processed in simple forever loop.
|
|
|
|
.. code-block:: c
|
|
|
|
#include <log_ctrl.h>
|
|
|
|
void main(void)
|
|
{
|
|
log_init();
|
|
|
|
while (1) {
|
|
if (log_process() == false) {
|
|
/* sleep */
|
|
}
|
|
}
|
|
}
|
|
|
|
If logs are processed from a thread then it is possible to enable a feature
|
|
which will wake up processing thread when certain amount of log messages are
|
|
buffered (see :kconfig:`CONFIG_LOG_PROCESS_TRIGGER_THRESHOLD`). It is also
|
|
possible to enable internal logging thread (see :kconfig:`CONFIG_LOG_PROCESS_THREAD`).
|
|
In that case, logging thread is initialized and log messages are processed implicitly.
|
|
|
|
.. _logging_panic:
|
|
|
|
Logging panic
|
|
*************
|
|
|
|
In case of error condition system usually can no longer rely on scheduler or
|
|
interrupts. In that situation deferred log message processing is not an option.
|
|
Logger controlling API provides a function for entering into panic mode
|
|
(:c:func:`log_panic`) which should be called in such situation.
|
|
|
|
When :c:func:`log_panic` is called, _panic_ notification is sent to all active
|
|
backends. Once all backends are notified, all buffered messages are flushed. Since
|
|
that moment all logs are processed in a blocking way.
|
|
|
|
.. _log_architecture:
|
|
|
|
Architecture
|
|
************
|
|
|
|
Logging consists of 3 main parts:
|
|
|
|
- Frontend
|
|
- Core
|
|
- Backends
|
|
|
|
Log message is generated by a source of logging which can be a module or
|
|
instance of a module.
|
|
|
|
Default Frontend
|
|
================
|
|
|
|
Default frontend is engaged when logging API is called in a source of logging (e.g.
|
|
:c:macro:`LOG_INF`) and is responsible for filtering a message (compile and run
|
|
time), allocating buffer for the message, creating the message and committing that
|
|
message. Since logging API can be called in an interrupt, frontend is optimized
|
|
to log the message as fast as possible.
|
|
|
|
Log message v1
|
|
--------------
|
|
|
|
Each log message consists of one or more fixed size chunks allocated from the
|
|
pool of fixed size buffers (:ref:`memory_slabs_v2`). Message head chunk
|
|
contains log entry details like: source ID, timestamp, severity level and the
|
|
data (string pointer and arguments or raw data). Message contains also a
|
|
reference counter which indicates how many users still uses this message. It is
|
|
used to return message to the pool once last user indicates that it can be
|
|
freed. If more than 3 arguments or 12 bytes of raw data is used in the log then
|
|
log message is formed from multiple chunks which are linked together. When
|
|
message body is filled it is put into the list.
|
|
When log processing is triggered, a message is removed from the list of pending
|
|
messages. If runtime filtering is disabled, the message is passed to all
|
|
active backends, otherwise the message is passed to only those backends that
|
|
have requested messages from that particular source (based on the source ID in
|
|
the message), and severity level. Once all backends are iterated, the message
|
|
is considered processed, but the message may still be in use by a backend.
|
|
Because message is allocated from a pool, it is not mandatory to sequentially
|
|
free messages. Processing by the backends is asynchronous and memory is freed
|
|
when last user indicates that message can be freed. It also means that improper
|
|
backend implementation may lead to pool drought.
|
|
|
|
Log message v2
|
|
--------------
|
|
|
|
Log message v2 contains message descriptor (source, domain and level), timestamp,
|
|
formatted string details (see :ref:`cbprintf_packaging`) and optional data.
|
|
Log messages v2 are stored in a continuous block of memory (contrary to v1).
|
|
Memory is allocated from a circular packet buffer (:ref:`mpsc_pbuf`). It has
|
|
few consequences:
|
|
|
|
* Each message is self-contained, continuous block of memory thus it is suited
|
|
for copying the message (e.g. for offline processing).
|
|
* Memory is better utilized because fixed size chunks are not used.
|
|
* Messages must be sequentially freed. Backend processing is synchronous. Backend
|
|
can make a copy for deferred processing.
|
|
|
|
Log message has following format:
|
|
|
|
+------------------+----------------------------------------------------+
|
|
| Message Header | 2 bits: MPSC packet buffer header |
|
|
| +----------------------------------------------------+
|
|
| | 1 bit: Trace/Log message flag |
|
|
| +----------------------------------------------------+
|
|
| | 3 bits: Domain ID |
|
|
| +----------------------------------------------------+
|
|
| | 3 bits: Level |
|
|
| +----------------------------------------------------+
|
|
| | 10 bits: Cbprintf Package Length |
|
|
| +----------------------------------------------------+
|
|
| | 12 bits: Data length |
|
|
| +----------------------------------------------------+
|
|
| | 1 bit: Reserved |
|
|
| +----------------------------------------------------+
|
|
| | pointer: Pointer to the source descriptor [#l0]_ |
|
|
| +----------------------------------------------------+
|
|
| | 32 or 64 bits: Timestamp [#l0]_ |
|
|
| +----------------------------------------------------+
|
|
| | Optional padding [#l1]_ |
|
|
+------------------+----------------------------------------------------+
|
|
| Cbprintf | Header |
|
|
| +----------------------------------------------------+
|
|
| | package | Arguments |
|
|
| | (optional) +----------------------------------------------------+
|
|
| | Appended strings |
|
|
+------------------+----------------------------------------------------+
|
|
| Hexdump data (optional) |
|
|
+------------------+----------------------------------------------------+
|
|
| Alignment padding (optional) |
|
|
+------------------+----------------------------------------------------+
|
|
|
|
.. rubric:: Footnotes
|
|
|
|
.. [#l0] Depending on the platform and the timestamp size fields may be swapped.
|
|
.. [#l1] It may be required for cbprintf package alignment
|
|
|
|
Log message allocation
|
|
----------------------
|
|
|
|
It may happen that frontend cannot allocate a message. It happens if system is
|
|
generating more log messages than it can process in certain time frame. There
|
|
are two strategies to handle that case:
|
|
|
|
- No overflow - new log is dropped if space for a message cannot be allocated.
|
|
- Overflow - oldest pending messages are freed, until new message can be
|
|
allocated. Enabled by :kconfig:`CONFIG_LOG_MODE_OVERFLOW`. Note that it degrades
|
|
performance thus it is recommended to adjust buffer size and amount of enabled
|
|
logs to limit dropping.
|
|
|
|
.. _logging_runtime_filtering:
|
|
|
|
Run-time filtering
|
|
------------------
|
|
|
|
If run-time filtering is enabled, then for each source of logging a filter
|
|
structure in RAM is declared. Such filter is using 32 bits divided into ten 3
|
|
bit slots. Except *slot 0*, each slot stores current filter for one backend in
|
|
the system. *Slot 0* (bits 0-2) is used to aggregate maximal filter setting for
|
|
given source of logging. Aggregate slot determines if log message is created
|
|
for given entry since it indicates if there is at least one backend expecting
|
|
that log entry. Backend slots are examined when message is processed by the core
|
|
to determine if message is accepted by the given backend. Contrary to compile
|
|
time filtering, binary footprint is increased because logs are compiled in.
|
|
|
|
In the example below backend 1 is set to receive errors (*slot 1*) and backend
|
|
2 up to info level (*slot 2*). Slots 3-9 are not used. Aggregated filter
|
|
(*slot 0*) is set to info level and up to this level message from that
|
|
particular source will be buffered.
|
|
|
|
+------+------+------+------+-----+------+
|
|
|slot 0|slot 1|slot 2|slot 3| ... |slot 9|
|
|
+------+------+------+------+-----+------+
|
|
| INF | ERR | INF | OFF | ... | OFF |
|
|
+------+------+------+------+-----+------+
|
|
|
|
Custom Frontend
|
|
===============
|
|
|
|
Custom frontend is enabled using :kconfig:`CONFIG_LOG_FRONTEND`. Logs are redirected
|
|
to functions declared in :zephyr_file:`include/logging/log_frontend.h`.
|
|
This may be required in very time-sensitive cases, but most of the logging
|
|
features cannot be used then, which includes default frontend, core and all
|
|
backends features.
|
|
|
|
.. _logging_strings:
|
|
|
|
Logging strings
|
|
===============
|
|
|
|
Logging v1
|
|
----------
|
|
|
|
Since log message contains only the value of the argument, when ``%s`` is used
|
|
only the address of a string is stored. Because a string variable argument could
|
|
be transient, allocated on the stack, or modifiable, logger provides a mechanism
|
|
and a dedicated buffer pool to hold copies of strings. The buffer size and count
|
|
is configurable (see :kconfig:`CONFIG_LOG_STRDUP_MAX_STRING` and
|
|
:kconfig:`CONFIG_LOG_STRDUP_BUF_COUNT`).
|
|
|
|
If a string argument is transient, the user must call :c:func:`log_strdup` to
|
|
duplicate the passed string into a buffer from the pool. See the examples below.
|
|
If a strdup buffer cannot be allocated, a warning message is logged and an error
|
|
code returned indicating :kconfig:`CONFIG_LOG_STRDUP_BUF_COUNT` should be
|
|
increased. Buffers are freed together with the log message.
|
|
|
|
.. code-block:: c
|
|
|
|
char local_str[] = "abc";
|
|
|
|
LOG_INF("logging transient string: %s", log_strdup(local_str));
|
|
local_str[0] = '\0'; /* String can be modified, logger will use duplicate."
|
|
|
|
When :kconfig:`CONFIG_LOG_DETECT_MISSED_STRDUP` is enabled logger will scan
|
|
each log message and report if string format specifier is found and string
|
|
address is not in read only memory section or does not belong to memory pool
|
|
dedicated to string duplicates. It indictes that :c:func:`log_strdup` is
|
|
missing in a call to log a message, such as ``LOG_INF``.
|
|
|
|
Logging v2
|
|
----------
|
|
|
|
String arguments are handled by :ref:`cbprintf_packaging` thus no special action
|
|
is required.
|
|
|
|
Logging backends
|
|
================
|
|
|
|
Logging backends are registered using :c:macro:`LOG_BACKEND_DEFINE`. The macro
|
|
creates an instance in the dedicated memory section. Backends can be dynamically
|
|
enabled (:c:func:`log_backend_enable`) and disabled. When
|
|
:ref:`logging_runtime_filtering` is enabled, :c:func:`log_filter_set` can be used
|
|
to dynamically change filtering of a module logs for given backend. Module is
|
|
identified by source ID and domain ID. Source ID can be retrieved if source name
|
|
is known by iterating through all registered sources.
|
|
|
|
Logging supports up to 9 concurrent backends. Log message is passed to the
|
|
each backend in processing phase. Additionally, backend is notfied when logging
|
|
enter panic mode with :c:func:`log_backend_panic`. On that call backend should
|
|
switch to synchronous, interrupt-less operation or shut down itself if that is
|
|
not supported. Occasionally, logging may inform backend about number of dropped
|
|
messages with :c:func:`log_backend_dropped`. Message processing API is version
|
|
specific.
|
|
|
|
Logging v1
|
|
----------
|
|
|
|
Logging backend interface contains following functions for processing:
|
|
|
|
- :c:func:`log_backend_put` - backend gets log message in deferred mode.
|
|
- :c:func:`log_backend_put_sync_string` - backend gets log message with formatted
|
|
string message in the immediate mode.
|
|
- :c:func:`log_backend_put_sync_hexdump` - backend gets log message with hexdump
|
|
message in the immediate mode.
|
|
|
|
The log message contains a reference counter tracking how many backends are
|
|
processing the message. On receiving a message backend must claim it by calling
|
|
:c:func:`log_msg_get` on that message which increments a reference counter.
|
|
Once message is processed, backend puts back the message
|
|
(:c:func:`log_msg_put`) decrementing a reference counter. On last
|
|
:c:func:`log_msg_put`, when reference counter reaches 0, message is returned
|
|
to the pool. It is up to the backend how message is processed.
|
|
|
|
.. note::
|
|
|
|
The message pool can be starved if a backend does not call
|
|
:c:func:`log_msg_put` when it is done processing a message. The logging
|
|
core has no means to force messages back to the pool if they're still marked
|
|
as in use (with a non-zero reference counter).
|
|
|
|
.. code-block:: c
|
|
|
|
#include <log_backend.h>
|
|
|
|
void put(const struct log_backend *const backend,
|
|
struct log_msg *msg)
|
|
{
|
|
log_msg_get(msg);
|
|
|
|
/* message processing */
|
|
|
|
log_msg_put(msg);
|
|
}
|
|
|
|
Logging v2
|
|
----------
|
|
|
|
:c:func:`log_backend_msg2_process` is used for processing message. It is common for
|
|
standard and hexdump messages because log message v2 hold string with arguments
|
|
and data. It is also common for deferred and immediate logging.
|
|
|
|
Message formatting
|
|
------------------
|
|
|
|
Logging provides set of function that can be used by the backend to format a
|
|
message. Helper functions are available in :zephyr_file:`include/logging/log_output.h`.
|
|
|
|
Example message formatted using :c:func:`log_output_msg_process` or
|
|
:c:func:`log_output_msg2_process`.
|
|
|
|
.. code-block:: console
|
|
|
|
[00:00:00.000,274] <info> sample_instance.inst1: logging message
|
|
|
|
|
|
.. _logging_guide_dictionary:
|
|
|
|
Dictionary-based Logging
|
|
========================
|
|
|
|
Dictionary-based logging, instead of human readable texts, outputs the log
|
|
messages in binary format. This binary format encodes arguments to formatted
|
|
strings in their native storage formats which can be more compact than their
|
|
text equivalents. For statically defined strings (including the format
|
|
strings and any string arguments), references to the ELF file are encoded
|
|
instead of the whole strings. A dictionary created at build time contains
|
|
the mappings between these references and the actual strings. This allows
|
|
the offline parser to obtain the strings from the dictionary to parse
|
|
the log messages. This binary format allows a more compact representation
|
|
of log messages in certain scenarios. However, this requires the use of
|
|
an offline parser and is not as intuitive to use as text-based log messages.
|
|
|
|
Note that ``long double`` is not supported by Python's ``struct`` module.
|
|
Therefore, log messages with ``long double`` will not display the correct
|
|
values.
|
|
|
|
|
|
Configuration
|
|
-------------
|
|
|
|
Here are kconfig options related to dictionary-based logging:
|
|
|
|
- :kconfig:`CONFIG_LOG_DICTIONARY_SUPPORT` enables dictionary-based logging
|
|
support. This should be selected by the backends which require it.
|
|
|
|
- The UART backend can be used for dictionary-based logging. These are
|
|
additional config for the UART backend:
|
|
|
|
- :kconfig:`CONFIG_LOG_BACKEND_UART_OUTPUT_DICTIONARY_HEX` tells
|
|
the UART backend to output hexadecimal characters for dictionary based
|
|
logging. This is useful when the log data needs to be captured manually
|
|
via terminals and consoles.
|
|
|
|
- :kconfig:`CONFIG_LOG_BACKEND_UART_OUTPUT_DICTIONARY_BIN` tells
|
|
the UART backend to output binary data.
|
|
|
|
|
|
Usage
|
|
-----
|
|
|
|
When dictionary-based logging is enabled via enabling related logging backends,
|
|
a JSON database file, named :file:`log_dictionary.json`, will be created
|
|
in the build directory. This database file contains information for the parser
|
|
to correctly parse the log data. Note that this database file only works
|
|
with the same build, and cannot be used for any other builds.
|
|
|
|
To use the log parser:
|
|
|
|
.. code-block:: console
|
|
|
|
./scripts/logging/dictionary/log_parser.py <build dir>/log_dictionary.json <log data file>
|
|
|
|
The parser takes two required arguments, where the first one is the full path
|
|
to the JSON database file, and the second part is the file containing log data.
|
|
Add an optional argument ``--hex`` to the end if the log data file contains
|
|
hexadecimal characters
|
|
(e.g. when ``CONFIG_LOG_BACKEND_UART_OUTPUT_DICTIONARY_HEX=y``). This tells
|
|
the parser to convert the hexadecimal characters to binary before parsing.
|
|
|
|
Please refer to :ref:`logging_dictionary_sample` on how to use the log parser.
|
|
|
|
|
|
|
|
Limitations and recommendations
|
|
*******************************
|
|
|
|
Logging v1
|
|
==========
|
|
|
|
The are following limitations:
|
|
|
|
* Strings as arguments (*%s*) require special treatment (see
|
|
:ref:`logging_strings`).
|
|
* Logging double and float variables is not possible because arguments are
|
|
word size.
|
|
* Variables larger than word size cannot be logged.
|
|
* Number of arguments in the string is limited to 15.
|
|
|
|
Logging v2
|
|
==========
|
|
|
|
Solves major limitations of v1. However, in order to get most of the logging
|
|
capabilities following recommendations shall be followed:
|
|
|
|
* Enable :kconfig:`CONFIG_LOG_SPEED` to slightly speed up deferred logging at the
|
|
cost of slight increase in memory footprint.
|
|
* Compiler with C11 ``_Generic`` keyword support is recommended. Logging
|
|
performance is significantly degraded without it. See :ref:`cbprintf_packaging`.
|
|
* When ``_Generic`` is supported, during compilation it is determined which
|
|
packaging method shall be used: static or runtime. It is done by searching for
|
|
any string pointers in the argument list. If string pointer is used with
|
|
format specifier other than string, e.g. ``%p``, it is recommended to cast it
|
|
to ``void *``.
|
|
|
|
.. code-block:: c
|
|
|
|
LOG_WRN("%s", str);
|
|
LOG_WRN("%p", (void *)str);
|
|
|
|
Benchmark
|
|
*********
|
|
|
|
Benchmark numbers from :zephyr_file:`tests/subsys/logging/log_benchmark` performed
|
|
on ``qemu_x86``. It is a rough comparison to give general overview. Overall,
|
|
logging v2 improves in most a the areas with the biggest improvement in logging
|
|
from userspace. It is at the cost of larger memory footprint for a log message.
|
|
|
|
+--------------------------------------------+----------------+------------------+----------------+
|
|
| Feature | v1 | v2 | Summary |
|
|
+============================================+================+==================+================+
|
|
| Kernel logging | 7us | 7us [#f0]_/11us | No significant |
|
|
| | | | change |
|
|
+--------------------------------------------+----------------+------------------+----------------+
|
|
| User logging | 86us | 13us | **Strongly |
|
|
| | | | improved** |
|
|
+--------------------------------------------+----------------+------------------+----------------+
|
|
| kernel logging with overwrite | 23us | 10us [#f0]_/15us | **Improved** |
|
|
+--------------------------------------------+----------------+------------------+----------------+
|
|
| Logging transient string | 16us | 42us | **Degraded** |
|
|
+--------------------------------------------+----------------+------------------+----------------+
|
|
| Logging transient string from user | 111us | 50us | **Improved** |
|
|
+--------------------------------------------+----------------+------------------+----------------+
|
|
| Memory utilization [#f1]_ | 416 | 518 | Slightly |
|
|
| | | | improved |
|
|
+--------------------------------------------+----------------+------------------+----------------+
|
|
| Memory footprint (test) [#f2]_ | 3.2k | 2k | **Improved** |
|
|
+--------------------------------------------+----------------+------------------+----------------+
|
|
| Memory footprint (application) [#f3]_ | 6.2k | 3.5k | **Improved** |
|
|
+--------------------------------------------+----------------+------------------+----------------+
|
|
| Message footprint [#f4]_ | 15 bytes | 47 [#f0]_/32 | **Degraded** |
|
|
| | | bytes | |
|
|
+--------------------------------------------+----------------+------------------+----------------+
|
|
|
|
.. rubric:: Benchmark details
|
|
|
|
.. [#f0] :kconfig:`CONFIG_LOG_SPEED` enabled.
|
|
|
|
.. [#f1] Number of log messages with various number of arguments that fits in 2048
|
|
bytes dedicated for logging.
|
|
|
|
.. [#f2] Logging subsystem memory footprint in :zephyr_file:`tests/subsys/logging/log_benchmark`
|
|
where filtering and formatting features are not used.
|
|
|
|
.. [#f3] Logging subsystem memory footprint in :zephyr_file:`samples/subsys/logging/logger`.
|
|
|
|
.. [#f4] Avarage size of a log message (excluding string) with 2 arguments on ``Cortex M3``
|
|
|
|
API Reference
|
|
*************
|
|
|
|
Logger API
|
|
==========
|
|
|
|
.. doxygengroup:: log_api
|
|
|
|
Logger control
|
|
==============
|
|
|
|
.. doxygengroup:: log_ctrl
|
|
|
|
Log message
|
|
===========
|
|
|
|
.. doxygengroup:: log_msg
|
|
|
|
Logger backend interface
|
|
========================
|
|
|
|
.. doxygengroup:: log_backend
|
|
|
|
Logger output formatting
|
|
========================
|
|
|
|
.. doxygengroup:: log_output
|