xref: /aosp_15_r20/external/pigweed/pw_log/docs.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1.. _module-pw_log:
2
3======
4pw_log
5======
6.. pigweed-module::
7   :name: pw_log
8
9Pigweed's logging module provides facilities for applications to log
10information about the execution of their application. The module is split into
11two components:
12
131. The facade (this module) which is only a macro interface layer
142. The backend, provided elsewhere, that implements the low level logging
15
16``pw_log`` also defines a logging protobuf, helper utilities, and an RPC
17service for efficiently storing and transmitting log messages. See
18:ref:`module-pw_log-protobuf` for details.
19
20--------------
21Usage examples
22--------------
23Here is a typical usage example, showing setting the module name, and using the
24long-form names.
25
26.. code-block:: cpp
27
28   #define PW_LOG_MODULE_NAME "BLE"
29
30   #include "pw_log/log.h"
31
32   int main() {
33     PW_LOG_INFO("Booting...");
34     PW_LOG_DEBUG("CPU temp: %.2f", cpu_temperature);
35     if (BootFailed()) {
36       PW_LOG_CRITICAL("Had trouble booting due to error %d", GetErrorCode());
37       ReportErrorsAndHalt();
38     }
39     PW_LOG_INFO("Successfully booted");
40   }
41
42In ``.cc`` files, it is possible to dispense with the ``PW_`` part of the log
43names and go for shorter log macros. Include ``pw_log/short.h`` or
44``pw_log/shorter.h`` for shorter versions of the macros.
45
46.. warning::
47   The shorter log macros collide with `Abseil's logging API
48   <https://abseil.io/docs/cpp/guides/logging>`_. Do not use them in upstream
49   Pigweed modules, or any code that may depend on Abseil.
50
51.. code-block:: cpp
52
53   #define PW_LOG_MODULE_NAME "BLE"
54
55   #include "pw_log/shorter.h"
56
57   int main() {
58     INF("Booting...");
59     DBG("CPU temp: %.2f", cpu_temperature);
60     if (BootFailed()) {
61       CRT("Had trouble booting due to error %d", GetErrorCode());
62       ReportErrorsAndHalt();
63     }
64     INF("Successfully booted");
65   }
66
67The ``pw_log`` facade also exposes a handful of macros that only apply
68specifically to tokenized logging. See :ref:`module-pw_log-tokenized-args` for
69details.
70
71Layer diagram example: ``stm32f429i-disc1``
72===========================================
73Below is an example diagram showing how the modules connect together for the
74``stm32f429i-disc1`` target, where the ``pw_log`` backend is ``pw_log_basic``.
75``pw_log_basic`` uses the ``pw_sys_io`` module to log in plaintext, which in
76turn outputs to the STM32F429 bare metal backend for ``pw_sys_io``, which is
77``pw_sys_io_baremetal_stm32f429i``.
78
79.. image:: example_layer_diagram.svg
80
81.. _module-pw_log-macros:
82
83Logging macros
84==============
85These are the primary macros for logging information about the functioning of a
86system, intended to be used directly.
87
88.. c:macro:: PW_LOG(level, verbosity, module, flags, fmt, ...)
89
90   This is the primary mechanism for logging.
91
92   *level* - An integer level as defined by ``pw_log/levels.h`` for this log.
93
94   *verbosity* - An integer level as defined by ``pw_log/levels.h`` which is the
95   minimum level which is enabled.
96
97   *module* - A string literal for the module name.
98
99   *flags* - Arbitrary flags the backend can leverage. The semantics of these
100   flags are not defined in the facade, but are instead meant as a general
101   mechanism for communication bits of information to the logging backend.
102   ``pw_log`` reserves 2 flag bits by default, but log backends may provide for
103   more or fewer flag bits.
104
105   Here are some ideas for what a backend might use flags for:
106
107   - Example: ``HAS_PII`` - A log has personally-identifying data
108   - Example: ``HAS_DII`` - A log has device-identifying data
109   - Example: ``RELIABLE_DELIVERY`` - Ask the backend to ensure the log is
110     delivered; this may entail blocking other logs.
111   - Example: ``BEST_EFFORT`` - Don't deliver this log if it would mean blocking
112     or dropping important-flagged logs
113
114   *fmt* - The message to log, which may contain format specifiers like ``%d``
115   or ``%0.2f``.
116
117   Example:
118
119   .. code-block:: cpp
120
121      PW_LOG(PW_LOG_LEVEL_INFO, PW_LOG_LEVEL_DEBUG, PW_LOG_MODULE_NAME, PW_LOG_FLAGS, "Temp is %d degrees", temp);
122      PW_LOG(PW_LOG_LEVEL_ERROR, PW_LOG_LEVEL_DEBUG, PW_LOG_MODULE_NAME, UNRELIABLE_DELIVERY, "It didn't work!");
123
124   .. note::
125
126      ``PW_LOG()`` should not be used frequently; typically only when adding
127      flags to a particular message to mark PII or to indicate delivery
128      guarantees.  For most cases, prefer to use the direct ``PW_LOG_INFO`` or
129      ``PW_LOG_DEBUG`` style macros, which are often implemented more efficiently
130      in the backend.
131
132.. _module-pw_log-levels:
133
134.. c:macro:: PW_LOG_DEBUG(fmt, ...)
135.. c:macro:: PW_LOG_INFO(fmt, ...)
136.. c:macro:: PW_LOG_WARN(fmt, ...)
137.. c:macro:: PW_LOG_ERROR(fmt, ...)
138.. c:macro:: PW_LOG_CRITICAL(fmt, ...)
139
140   Shorthand for ``PW_LOG(<level>, PW_LOG_MODULE_NAME, PW_LOG_FLAGS, fmt, ...)``.
141
142.. c:macro:: PW_LOG_EVERY_N(level, rate, ...)
143
144   A simple rate limit logger which will simply log one out of every N logs.
145
146   *level* - An integer level as defined by ``pw_log/levels.h``.
147
148   *rate* - Rate to reduce logs to, every ``rate``-th log will complete, others
149   will be suppressed.
150
151.. c:macro:: PW_LOG_EVERY_N_DURATION(level, min_interval_between_logs, msg, ...)
152
153   This is a rate-limited form of logging, especially useful for progressive
154   or chatty logs that should be logged periodically, but not on each instance
155   of the logger being called.
156
157   *level* - An integer level as defined by ``pw_log/levels.h``.
158
159   *min_interval_between_logs* - A ``std::chrono::duration`` of the minimum time
160   between logs. Logs attempted before this time duration will be completely
161   dropped.
162   Dropped logs will be counted to add a drop count and calculated rate of the
163   logs.
164
165   *msg* - Formattable log message, as you would pass to the above ``PW_LOG``
166   macro.
167
168   .. note::
169
170      ``PW_LOG_EVERY_N`` is simpler, if you simply need to reduce uniformly
171      periodic logs by a fixed or variable factor not based explicitly on a
172      duration. Each call to the macro will incur a static ``uint32_t`` within
173      the calling context.
174
175      ``PW_LOG_EVERY_N_DURATION`` is able to suppress all logs based on a time
176      interval, suppressing logs logging faster than the desired time interval.
177      Each call to the duration macro will incur a static 16 byte object to
178      track the time interval within the calling context.
179
180   Example:
181
182   .. code-block:: cpp
183
184      // Ensure at least 500ms between transfer parameter logs.
185      chrono::SystemClock::duration rate_limit_ =
186         chrono::SystemClock::for_at_least(std::chrono::milliseconds(500));
187
188      PW_LOG_EVERY_N_DURATION(PW_LOG_LEVEL_INFO,
189                              rate_limit_,
190                              "Transfer %u sending transfer parameters!"
191                              static_cast<unsigned>(session_id_));
192
193--------------------
194Module configuration
195--------------------
196This module has configuration options that globally affect the behavior of
197pw_log via compile-time configuration of this module, see the
198:ref:`module documentation <module-structure-compile-time-configuration>` for
199more details.
200
201.. c:macro:: PW_LOG_LEVEL_DEFAULT
202
203   Controls the default value of ``PW_LOG_LEVEL``. Setting
204   ``PW_LOG_LEVEL_DEFAULT`` will change the behavior of all source files that
205   have not explicitly set ``PW_LOG_LEVEL``. Defaults to ``PW_LOG_LEVEL_DEBUG``.
206
207.. c:macro:: PW_LOG_FLAGS_DEFAULT
208
209   Controls the default value of ``PW_LOG_FLAGS``. Setting
210   ``PW_LOG_FLAGS_DEFAULT`` will change the behavior of all source files that
211   have not explicitly set ``PW_LOG_FLAGS``. Defaults to ``0``.
212
213.. c:macro:: PW_LOG_ENABLE_IF(level, verbosity, flags)
214
215   Filters logs by an arbitrary expression based on ``level``, ``verbosity``,
216   and ``flags``. Source files that define
217   ``PW_LOG_ENABLE_IF(level, verbosity, flags)`` will display if the given
218   expression evaluates true. Defaults to
219   ``((int32_t)(level) >= (int32_t)(verbosity))``.
220
221.. attention::
222
223   At this time, only compile time filtering is supported. In the future, we
224   plan to add support for runtime filtering.
225
226
227Per-source file configuration
228=============================
229This module defines macros that can be overridden to independently control the
230behavior of ``pw_log`` statements for each C or C++ source file. To override
231these macros, add ``#define`` statements for them before including headers.
232
233The option macro definitions must be visible to ``pw_log/log.h`` the first time
234it is included. To handle potential transitive includes, place these
235``#defines`` before all ``#include`` statements. This should only be done in
236source files, not headers. For example:
237
238.. code-block:: cpp
239
240   // Set the pw_log option macros here, before ALL of the #includes.
241   #define PW_LOG_MODULE_NAME "Calibration"
242   #define PW_LOG_LEVEL PW_LOG_LEVEL_WARN
243
244   #include <array>
245   #include <random>
246
247   #include "devices/hal9000.h"
248   #include "pw_log/log.h"
249   #include "pw_rpc/server.h"
250
251   int MyFunction() {
252     PW_LOG_INFO("hello???");
253   }
254
255.. c:macro:: PW_LOG_MODULE_NAME
256
257   A string literal module name to use in logs. Log backends may attach this
258   name to log messages or use it for runtime filtering. Defaults to ``""``.
259
260.. c:macro:: PW_LOG_FLAGS
261
262   Log flags to use for the ``PW_LOG_<level>`` macros. Different flags may be
263   applied when using the ``PW_LOG`` macro directly.
264
265   Log backends use flags to change how they handle individual log messages.
266   Potential uses include assigning logs priority or marking them as containing
267   personal information. Defaults to ``PW_LOG_FLAGS_DEFAULT``.
268
269.. c:macro:: PW_LOG_LEVEL
270
271   Filters logs by level. Source files that define ``PW_LOG_LEVEL`` will display
272   only logs at or above the chosen level. Log statements below this level will
273   be compiled out of optimized builds. Defaults to ``PW_LOG_LEVEL_DEFAULT``.
274
275   Example:
276
277   .. code-block:: cpp
278
279      #define PW_LOG_LEVEL PW_LOG_LEVEL_INFO
280
281      #include "pw_log/log.h"
282
283      void DoSomething() {
284        PW_LOG_DEBUG("This won't be logged at all");
285        PW_LOG_INFO("This is INFO level, and will display");
286        PW_LOG_WARN("This is above INFO level, and will display");
287      }
288
289.. _module-pw_log-logging_attributes:
290
291------------------
292Logging attributes
293------------------
294The logging facade in Pigweed is designed to facilitate the capture of at least
295the following attributes:
296
297- *Level* - The log level; for example, INFO, DEBUG, ERROR, etc. Typically an
298  integer
299- *Flags* - Bitset for e.g. RELIABLE_DELIVERY, or HAS_PII, or BEST_EFFORT
300- *File* - The file where the log was triggered
301- *Line* - The line number in the file where the log line occured
302- *Function* - What function the log comes from. This is expensive in binary
303  size to use!
304- *Module* - The user-defined module name for the log statement; e.g. “BLE” or
305  “BAT”
306- *Message* - The message itself; with % format arguments
307- *Arguments* - The format arguments to message
308- *Thread* - For devices running with an RTOS, capturing the thread is very
309  useful
310- *Others* - Processor security level? Maybe Thread is a good proxy for this
311
312Each backend may decide to capture different attributes to balance the tradeoff
313between call site code size, call site run time, wire format size, logging
314complexity, and more.
315
316.. _module-pw_log-circular-deps:
317
318----------------------------------------------
319Avoiding circular dependencies with ``PW_LOG``
320----------------------------------------------
321Because logs are so widely used, including in low-level libraries, it is
322common for the ``pw_log`` backend to cause circular dependencies. Because of
323this, log backends may avoid declaring explicit dependencies, instead relying
324on include paths to access header files.
325
326GN
327==
328In GN, the ``pw_log`` backend's full implementation with true dependencies is
329made available through the ``$dir_pw_log:impl`` group. When ``pw_log_BACKEND``
330is set, ``$dir_pw_log:impl`` must be listed in the ``pw_build_LINK_DEPS``
331variable. See :ref:`module-pw_build-link-deps`.
332
333In the ``pw_log``, the backend's full implementation is placed in the
334``$pw_log_BACKEND.impl`` target. ``$dir_pw_log:impl`` depends on this
335backend target. The ``$pw_log_BACKEND.impl`` target may be an empty group if
336the backend target can use its dependencies directly without causing circular
337dependencies.
338
339In order to break dependency cycles, the ``pw_log_BACKEND`` target may need
340to directly provide dependencies through include paths only, rather than GN
341``public_deps``. In this case, GN header checking can be disabled with
342``check_includes = false``.
343
344.. _module-pw_log-bazel-backend_impl:
345
346Bazel
347=====
348In Bazel, log backends may avoid cyclic dependencies by placing the full
349implementation in an ``impl`` target, like ``//pw_log_tokenized:impl``. The
350``//pw_log:backend_impl`` label flag should be set to the ``impl`` target
351required by the log backend used by the platform.
352
353You must add a dependency on the ``@pigweed//pw_log:backend_impl`` target to
354any binary using ``pw_log``.
355
356See :ref:`docs-build_system-bazel_link-extra-lib` for a general discussion of
357cyclic dependencies in low-level libraries in Bazel.
358
359----------------------
360Google Logging Adapter
361----------------------
362Pigweed provides a minimal C++ stream-style Google Log set of adapter
363macros around PW_LOG under ``pw_log/glog_adapter.h`` for compatibility with
364non-embedded code. While it is effective for porting server code to
365microcontrollers quickly, we do not advise embedded projects use that approach
366unless absolutely necessary.
367
368Configuration
369==============
370
371.. c:macro:: PW_LOG_CFG_GLOG_BUFFER_SIZE_BYTES
372
373   The size of the stack-allocated buffer used by the Google Logging (glog)
374   macros. This only affects the glog macros provided through pw_log/glog.h.
375
376   Pigweed strongly recommends sticking to printf-style logging instead
377   of C++ stream-style Google Log logging unless absolutely necessary. The glog
378   macros are only provided for compatibility with non-embedded code. See
379   :ref:`module-pw_log-design-discussion` for more details.
380
381   Undersizing this buffer will result in truncated log messages.
382
383-----------------
384Design discussion
385-----------------
386
387.. _module-pw_log-design-discussion:
388
389Why not use C++ style stream logging operators like Google Log?
390===============================================================
391There are multiple reasons to avoid the C++ stream logging style in embedded,
392but the biggest reason is that C++ stream logging defeats log tokenization. By
393having the string literals broken up between ``<<`` operators, tokenization
394becomes impossible with current language features.
395
396Consider this example use of Google Log:
397
398.. code-block:: cpp
399
400   LOG(INFO) << "My temperature is " << temperature << ". State: " << state;
401
402This log statement has two string literals. It might seem like one could convert
403move to tokenization:
404
405.. code-block:: cpp
406
407   LOG(INFO) << TOKEN("My temperature is ") << temperature << TOKEN(". State: ") << state;
408
409However, this doesn't work. The key problem is that the tokenization system
410needs to allocate the string in a linker section that is excluded from the
411final binary, but is in the final ELF executable (and so can be extracted).
412Since there is no way to declare a string or array in a different section in
413the middle of an experession in C++, it is not possible to tokenize an
414expression like the above.
415
416In contrast, the ``printf``-style version is a single statement with a single
417string constant, which can be expanded by the preprocessor (as part of
418``pw_tokenizer``) into a constant array in a special section.
419
420.. code-block:: cpp
421
422   // Note: LOG_INFO can be tokenized behind the macro; transparent to users.
423   PW_LOG_INFO("My temperature is %d. State: %s", temperature, state);
424
425Additionally, while Pigweed is mostly C++, it a practical reality that at times
426projects using Pigweed will need to log from third-party libraries written in
427C. Thus, we also wanted to retain C compatibility.
428
429In summary, printf-style logging is better for Pigweed's target audience
430because it:
431
432- works with tokenization
433- is C compatibile
434- has smaller call sites
435
436See also :ref:`module-pw_log_tokenized` for details on leveraging Pigweed's
437tokenizer module for logging.
438
439See also :ref:`module-pw_tokenizer` for details on Pigweed's tokenizer,
440which is useful for more than just logging.
441
442Why does the facade use header redirection instead of C functions?
443==================================================================
444Without header redirection, it is not possible to do sophisticated macro
445transforms in the backend. For example, to apply tokenization to log strings,
446the backend must define the handling macros. Additionally, compile-time
447filtering by log level or flags is not possible without header redirection.
448While it may be possible to do the filtering in the facade, that would imply
449having the same filtering implementation for all log handling, which is a
450restriction we want to avoid.
451
452Why is the module name done as a preprocessor define rather than an argument?
453=============================================================================
454APIs are a balance between power and ease of use. In the practical cases we
455have seen over the years, most translation units only need to log to one
456module, like ``"BLE"``, ``"PWR"``, ``"BAT"`` and so on. Thus, adding the
457argument to each macro call seemed like too much. On the other hand, flags are
458something that are typically added on a per-log-statement basis, and is why the
459flags are added on a per-call basis (though hidden through the high-level
460macros).
461
462--------------
463pw_log in Java
464--------------
465``pw_log`` provides a thin Java logging class that uses Google's `Flogger
466<https://google.github.io/flogger/>`_ API. The purpose of this wrapper is to
467support logging on platforms that do not support Flogger. The main
468implementation in ``pw_log/java/main`` simply wraps a
469``com.google.common.flogger.FluentLogger``. An implementation that logs to
470Android's ``android.util.Log`` instead is provided in
471``pw_log/java/android_main``.
472
473----------------
474pw_log in Python
475----------------
476``pw_log`` provides utilities to decode ``LogEntries`` and the encapsulated
477``LogEntry`` proto messages.
478
479The ``Log`` class represents a decoded ``LogEntry`` in a human-readable and
480consumable fashion.
481
482The ``LogStreamDecoder`` offers APIs to decode ``LogEntries`` and ``LogEntry``
483while tracking and logging log drops. It requires a ``decoded_log_handler`` to
484pass decoded logs to. This class can also be customized to use an optional token
485database if the message, module and thread names are tokenized; a custom
486timestamp parser; and optional message parser for any extra message parsing.
487``pw_log`` includes examples for customizing the ``LogStreamDecoder``:
488``timestamp_parser_ns_since_boot`` parses the timestamp number from nanoseconds
489since boot to an HH:MM::SS string, ``log_decoded_log`` emits a decoded ``Log``
490to the provided logger in a format known to ``pw console``, and
491``pw_status_code_to_name`` searches the decoded log message for a matching
492pattern encapsulating the status code number and replaces it with the status
493name.
494
495Python API
496==========
497
498pw_log.log_decoder
499------------------
500.. automodule:: pw_log.log_decoder
501    :members: Log, LogStreamDecoder
502    :undoc-members:
503    :show-inheritance:
504
505.. toctree::
506   :hidden:
507   :maxdepth: 1
508
509   protobuf
510   tokenized_args
511   Backends <backends>
512