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