aboutsummaryrefslogtreecommitdiff
path: root/pw_log_string/docs.rst
blob: b4a67efcfb218fc64580d4a9a1fa82f0682ab72e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
.. _module-pw_log_string:

=============
pw_log_string
=============
``pw_log_string`` is a partial backend for ``pw_log``. This backend fowards the
``PW_LOG_*`` macros to the ``pw_log_string:handler`` facade which is backed by
a C API. ``pw_log_string:handler`` does not implement the full C API, leaving
projects to provide their own implementation of
``pw_log_string_HandleMessageVaList``. See ``pw_log_basic`` for a similar
``pw_log`` backend that also provides an implementation.

As this module passes the log message, file name, and module name as a string to
the handler function, it's relatively expensive and not well suited for
space-constrained devices. This module is oriented towards usage on a host
(e.g. a simulated device).

Note that ``pw_log_string:handler`` may be used even when it's not used
as the backend for ``pw_log`` via ``pw_log_string``. For example it can be
useful to mix tokenized and string based logging in case you have a C ABI where
tokenization can not be used on the other side.

.. _module-pw_log_string-get-started-gn:

----------------
Get started (GN)
----------------
This section outlines how to implement a ``pw_log_string`` backend in a
GN-based project.

.. note::
   The example code was written for a :ref:`host <target-host>` target running
   on Linux.

Invoke a logging macro
======================
Call one of the :ref:`pw_log macros <module-pw_log-macros>` in your project
code:

.. code-block:: cpp
   :emphasize-lines: 9

   /* //src/app.cc */

   #include <unistd.h>

   #include "pw_log/log.h"

   int main() {
       while (true) {
           PW_LOG_INFO("Hello, world!");
           sleep(5);
       }
       return 0;
   }

Implement the logging function
==============================
Implement :cpp:func:`pw_log_string_HandleMessageVaList()` in C. Macros like
:cpp:func:`PW_LOG()` hand off the actual logging implementation to this
function.

The function signature of your implementation must match the one specified by
Pigweed.

The example code below just logs most of the available information to
``stdout``:

.. code-block:: c

   /* //src/pw_log_string_backend.c */

   #include <stdio.h>
   #include <stdarg.h>

   void 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) {
       printf("Entering custom pw_log_string backend...\n");
       printf("%d\n", level);
       printf("%u\n", flags);
       printf("%s\n", module_name);
       printf("%s\n", file_name);
       printf("%d\n", line_number);
       printf("%s\n", message);
       if (args) { /* Do something with your args here... */ }
       printf("Exiting custom pw_log_string backend...\n\n");
   }

What exactly ``pw_log_string_HandleMessageVaList()`` should do is entirely up to
the implementation. The log handler in ``pw_log_basic`` is one example, but it's
also possible to encode as protobuf and send over a TCP port, write to a file,
or even blink an LED to log as morse code.

Create source sets
==================
.. _source set: https://gn.googlesource.com/gn/+/main/docs/reference.md#c_language-source_sets

Use ``pw_source_set`` to create a `source set`_ for your logging
implementation. Do not use GN's built-in ``source_set`` feature.

.. code-block:: python

   # //src/BUILD.gn

   ...

   pw_source_set("pw_log_string_backend") {
       sources = [ "pw_log_string_backend.c" ]
   }

   pw_source_set("pw_log_string_backend.impl") {
       sources = []
   }

   ...

.. _//pw_log/BUILD.gn: https://cs.opensource.google/pigweed/pigweed/+/main:pw_log/BUILD.gn

The empty ``pw_log_string_backend.impl`` source set prevents circular
dependencies. See the comment for ``group("impl")`` in `//pw_log/BUILD.gn`_
for more context.

Configure backends
==================
Update your target toolchain configuration file:

* Set ``pw_log_BACKEND`` to ``dir_pw_log_string``
* Point ``pw_log_string_HANDLER_BACKEND`` to your source set that implements
  :cpp:func:`pw_log_string_HandleMessageVaList()`
* Update :ref:`pw_build_LINK_DEPS <module-pw_build-link-deps>` to include
  ``"$dir_pw_log:impl"`` and ``"$dir_pw_log_string:handler:impl"``

.. code-block:: python
   :emphasize-lines: 11,12,14,15

   # //targets/my_target/target_toolchains.gni

   ...

   my_target = {
     ...
     my_toolchain = {
       name = "my_toolchain"
       defaults = {
         ...
         pw_log_BACKEND = dir_pw_log_string
         pw_log_string_HANDLER_BACKEND = "//src:pw_log_string_backend"
         pw_build_LINK_DEPS = [
           "$dir_pw_log:impl",
           "$dir_pw_log_string:handler.impl",
           ...
         ]
         ...
       }
     }
   }

   ...


(Optional) Implement message handler
====================================
Optionally provide your own implementation of ``PW_LOG_STRING_HANDLE_MESSAGE``
which invokes ``pw_log_string_HANDLER_BACKEND`` with your selected arguments.

-------------
API reference
-------------
.. 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)