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