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