1.. _module-pw_log_string: 2 3============= 4pw_log_string 5============= 6``pw_log_string`` is a partial backend for ``pw_log``. This backend fowards the 7``PW_LOG_*`` macros to the ``pw_log_string:handler`` facade which is backed by 8a C API. ``pw_log_string:handler`` does not implement the full C API, leaving 9projects to provide their own implementation of 10``pw_log_string_HandleMessageVaList``. See ``pw_log_basic`` for a similar 11``pw_log`` backend that also provides an implementation. 12 13As this module passes the log message, file name, and module name as a string to 14the handler function, it's relatively expensive and not well suited for 15space-constrained devices. This module is oriented towards usage on a host 16(e.g. a simulated device). 17 18Note that ``pw_log_string:handler`` may be used even when it's not used 19as the backend for ``pw_log`` via ``pw_log_string``. For example it can be 20useful to mix tokenized and string based logging in case you have a C ABI where 21tokenization can not be used on the other side. 22 23.. _module-pw_log_string-get-started-gn: 24 25---------------- 26Get started (GN) 27---------------- 28This section outlines how to implement a ``pw_log_string`` backend in a 29GN-based project. 30 31.. note:: 32 The example code was written for a :ref:`host <target-host>` target running 33 on Linux. 34 35Invoke a logging macro 36====================== 37Call one of the :ref:`pw_log macros <module-pw_log-macros>` in your project 38code: 39 40.. code-block:: cpp 41 :emphasize-lines: 9 42 43 /* //src/app.cc */ 44 45 #include <unistd.h> 46 47 #include "pw_log/log.h" 48 49 int main() { 50 while (true) { 51 PW_LOG_INFO("Hello, world!"); 52 sleep(5); 53 } 54 return 0; 55 } 56 57Implement the logging function 58============================== 59Implement :cpp:func:`pw_log_string_HandleMessageVaList()` in C. Macros like 60:cpp:func:`PW_LOG()` hand off the actual logging implementation to this 61function. 62 63The function signature of your implementation must match the one specified by 64Pigweed. 65 66The example code below just logs most of the available information to 67``stdout``: 68 69.. code-block:: c 70 71 /* //src/pw_log_string_backend.c */ 72 73 #include <stdio.h> 74 #include <stdarg.h> 75 76 void pw_log_string_HandleMessageVaList(int level, 77 unsigned int flags, 78 const char* module_name, 79 const char* file_name, 80 int line_number, 81 const char* message, 82 va_list args) { 83 printf("Entering custom pw_log_string backend...\n"); 84 printf("%d\n", level); 85 printf("%u\n", flags); 86 printf("%s\n", module_name); 87 printf("%s\n", file_name); 88 printf("%d\n", line_number); 89 printf("%s\n", message); 90 if (args) { /* Do something with your args here... */ } 91 printf("Exiting custom pw_log_string backend...\n\n"); 92 } 93 94What exactly ``pw_log_string_HandleMessageVaList()`` should do is entirely up to 95the implementation. The log handler in ``pw_log_basic`` is one example, but it's 96also possible to encode as protobuf and send over a TCP port, write to a file, 97or even blink an LED to log as morse code. 98 99Create source sets 100================== 101.. _source set: https://gn.googlesource.com/gn/+/main/docs/reference.md#c_language-source_sets 102 103Use ``pw_source_set`` to create a `source set`_ for your logging 104implementation. Do not use GN's built-in ``source_set`` feature. 105 106.. code-block:: python 107 108 # //src/BUILD.gn 109 110 ... 111 112 pw_source_set("pw_log_string_backend") { 113 sources = [ "pw_log_string_backend.c" ] 114 } 115 116 pw_source_set("pw_log_string_backend.impl") { 117 sources = [] 118 } 119 120 ... 121 122.. _//pw_log/BUILD.gn: https://cs.opensource.google/pigweed/pigweed/+/main:pw_log/BUILD.gn 123 124The empty ``pw_log_string_backend.impl`` source set prevents circular 125dependencies. See the comment for ``group("impl")`` in `//pw_log/BUILD.gn`_ 126for more context. 127 128Configure backends 129================== 130Update your target toolchain configuration file: 131 132* Set ``pw_log_BACKEND`` to ``dir_pw_log_string`` 133* Point ``pw_log_string_HANDLER_BACKEND`` to your source set that implements 134 :cpp:func:`pw_log_string_HandleMessageVaList()` 135* Update :ref:`pw_build_LINK_DEPS <module-pw_build-link-deps>` to include 136 ``"$dir_pw_log:impl"`` and ``"$dir_pw_log_string:handler:impl"`` 137 138.. code-block:: python 139 :emphasize-lines: 11,12,14,15 140 141 # //targets/my_target/target_toolchains.gni 142 143 ... 144 145 my_target = { 146 ... 147 my_toolchain = { 148 name = "my_toolchain" 149 defaults = { 150 ... 151 pw_log_BACKEND = dir_pw_log_string 152 pw_log_string_HANDLER_BACKEND = "//src:pw_log_string_backend" 153 pw_build_LINK_DEPS = [ 154 "$dir_pw_log:impl", 155 "$dir_pw_log_string:handler.impl", 156 ... 157 ] 158 ... 159 } 160 } 161 } 162 163 ... 164 165 166(Optional) Implement message handler 167==================================== 168Optionally provide your own implementation of ``PW_LOG_STRING_HANDLE_MESSAGE`` 169which invokes ``pw_log_string_HANDLER_BACKEND`` with your selected arguments. 170 171``assert`` wrapper 172================== 173A wrapper for ``assert`` is provided that redirects calls to the ``pw_log_string`` 174handler. This can be used to replace all usage of ``assert`` in a Newlib binary 175at link time. 176 177------------- 178API reference 179------------- 180.. doxygenfunction:: pw_log_string_HandleMessageVaList(int level, unsigned int flags, const char* module_name, const char* file_name, int line_number, const char* message, va_list args) 181