xref: /aosp_15_r20/external/pigweed/pw_log_rpc/docs.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker:tocdepth: 4
2*61c4878aSAndroid Build Coastguard Worker
3*61c4878aSAndroid Build Coastguard Worker.. _module-pw_log_rpc:
4*61c4878aSAndroid Build Coastguard Worker
5*61c4878aSAndroid Build Coastguard Worker==========
6*61c4878aSAndroid Build Coastguard Workerpw_log_rpc
7*61c4878aSAndroid Build Coastguard Worker==========
8*61c4878aSAndroid Build Coastguard WorkerAn RPC-based logging solution for Pigweed with log filtering and log drops
9*61c4878aSAndroid Build Coastguard Workerreporting -- coming soon!
10*61c4878aSAndroid Build Coastguard Worker
11*61c4878aSAndroid Build Coastguard Worker.. warning::
12*61c4878aSAndroid Build Coastguard Worker  This module is under construction and might change in the future.
13*61c4878aSAndroid Build Coastguard Worker
14*61c4878aSAndroid Build Coastguard Worker-----------
15*61c4878aSAndroid Build Coastguard WorkerRPC Logging
16*61c4878aSAndroid Build Coastguard Worker-----------
17*61c4878aSAndroid Build Coastguard Worker
18*61c4878aSAndroid Build Coastguard WorkerHow to Use
19*61c4878aSAndroid Build Coastguard Worker==========
20*61c4878aSAndroid Build Coastguard Worker1. Set up RPC
21*61c4878aSAndroid Build Coastguard Worker-------------
22*61c4878aSAndroid Build Coastguard WorkerSet up RPC for your target device. Basic deployments run RPC over a UART, with
23*61c4878aSAndroid Build Coastguard WorkerHDLC on top for framing. See :ref:`module-pw_rpc` for details on how to enable
24*61c4878aSAndroid Build Coastguard Worker``pw_rpc``.
25*61c4878aSAndroid Build Coastguard Worker
26*61c4878aSAndroid Build Coastguard Worker2. Set up tokenized logging (optional)
27*61c4878aSAndroid Build Coastguard Worker--------------------------------------
28*61c4878aSAndroid Build Coastguard WorkerSet up the :ref:`module-pw_log_tokenized` log backend.
29*61c4878aSAndroid Build Coastguard Worker
30*61c4878aSAndroid Build Coastguard Worker3. Connect the tokenized logging handler to the MultiSink
31*61c4878aSAndroid Build Coastguard Worker---------------------------------------------------------
32*61c4878aSAndroid Build Coastguard WorkerCreate a :ref:`MultiSink <module-pw_multisink>` instance to buffer log entries.
33*61c4878aSAndroid Build Coastguard WorkerThen, make the log backend handler, :c:func:`pw_log_tokenized_HandleLog`, encode
34*61c4878aSAndroid Build Coastguard Workerlog entries in the ``log::LogEntry`` format, and add them to the ``MultiSink``.
35*61c4878aSAndroid Build Coastguard Worker
36*61c4878aSAndroid Build Coastguard Worker4. Create log drains and filters
37*61c4878aSAndroid Build Coastguard Worker--------------------------------
38*61c4878aSAndroid Build Coastguard WorkerCreate an ``RpcLogDrainMap`` with one ``RpcLogDrain`` for each RPC channel used
39*61c4878aSAndroid Build Coastguard Workerto stream logs. Optionally, create a ``FilterMap`` with ``Filter`` objects with
40*61c4878aSAndroid Build Coastguard Workerdifferent IDs. Provide these map to the ``LogService`` and register the latter
41*61c4878aSAndroid Build Coastguard Workerwith the application's RPC service. The ``RpcLogDrainMap`` provides a convenient
42*61c4878aSAndroid Build Coastguard Workerway to access and maintain each ``RpcLogDrain``. Attach each ``RpcLogDrain`` to
43*61c4878aSAndroid Build Coastguard Workerthe ``MultiSink``. Optionally, set the ``RpcLogDrain`` callback to decide if a
44*61c4878aSAndroid Build Coastguard Workerlog should be kept or dropped. This callback can be ``Filter::ShouldDropLog``.
45*61c4878aSAndroid Build Coastguard Worker
46*61c4878aSAndroid Build Coastguard Worker5. Flush the log drains in the background
47*61c4878aSAndroid Build Coastguard Worker-----------------------------------------
48*61c4878aSAndroid Build Coastguard WorkerDepending on the product's requirements, create a thread to flush all
49*61c4878aSAndroid Build Coastguard Worker``RpcLogDrain``\s or one thread per drain. The thread(s) must continuously call
50*61c4878aSAndroid Build Coastguard Worker``RpcLogDrain::Flush()`` to pull entries from the ``MultiSink`` and send them to
51*61c4878aSAndroid Build Coastguard Workerthe log listeners. Alternatively, use ``RpcLogDrain::Trickle`` to control the
52*61c4878aSAndroid Build Coastguard Workerrate of log entries streamed. Optionally, set up a callback to notify the
53*61c4878aSAndroid Build Coastguard Workerthread(s) when a drain is open.
54*61c4878aSAndroid Build Coastguard Worker
55*61c4878aSAndroid Build Coastguard WorkerLogging over RPC diagrams
56*61c4878aSAndroid Build Coastguard Worker=========================
57*61c4878aSAndroid Build Coastguard Worker
58*61c4878aSAndroid Build Coastguard WorkerSample RPC logs request
59*61c4878aSAndroid Build Coastguard Worker-----------------------
60*61c4878aSAndroid Build Coastguard WorkerThe log listener, e.g. a computer, requests logs via RPC. The log service
61*61c4878aSAndroid Build Coastguard Workerreceives the request and sets up the corresponding ``RpcLogDrain`` to start the
62*61c4878aSAndroid Build Coastguard Workerlog stream.
63*61c4878aSAndroid Build Coastguard Worker
64*61c4878aSAndroid Build Coastguard Worker.. mermaid::
65*61c4878aSAndroid Build Coastguard Worker
66*61c4878aSAndroid Build Coastguard Worker  graph TD
67*61c4878aSAndroid Build Coastguard Worker    computer[Computer]-->pw_rpc;
68*61c4878aSAndroid Build Coastguard Worker    pw_rpc-->log_service[LogService];
69*61c4878aSAndroid Build Coastguard Worker    log_service-->rpc_log_drain_pc[RpcLogDrain<br>streams to<br>computer];;
70*61c4878aSAndroid Build Coastguard Worker
71*61c4878aSAndroid Build Coastguard WorkerSample logging over RPC
72*61c4878aSAndroid Build Coastguard Worker------------------------
73*61c4878aSAndroid Build Coastguard WorkerLogs are streamed via RPC to a computer, and to another log listener. There can
74*61c4878aSAndroid Build Coastguard Workeralso be internal log readers, i.e. ``MultiSink::Drain``\s, attached to the
75*61c4878aSAndroid Build Coastguard Worker``MultiSink``, such as a writer to persistent memory, for example.
76*61c4878aSAndroid Build Coastguard Worker
77*61c4878aSAndroid Build Coastguard Worker.. mermaid::
78*61c4878aSAndroid Build Coastguard Worker
79*61c4878aSAndroid Build Coastguard Worker  graph TD
80*61c4878aSAndroid Build Coastguard Worker    source1[Source 1]-->log_api[pw_log API];
81*61c4878aSAndroid Build Coastguard Worker    source2[Source 2]-->log_api;
82*61c4878aSAndroid Build Coastguard Worker    log_api-->log_backend[Log backend];
83*61c4878aSAndroid Build Coastguard Worker    log_backend-->multisink[MultiSink];
84*61c4878aSAndroid Build Coastguard Worker    multisink-->drain[MultiSink::Drain];
85*61c4878aSAndroid Build Coastguard Worker    multisink-->rpc_log_drain_pc[RpcLogDrain<br>streams to<br>computer];
86*61c4878aSAndroid Build Coastguard Worker    multisink-->rpc_log_drain_other[RpcLogDrain<br>streams to<br>other log listener];
87*61c4878aSAndroid Build Coastguard Worker    drain-->other_consumer[Other log consumer<br>e.g. persistent memory];
88*61c4878aSAndroid Build Coastguard Worker    rpc_log_drain_pc-->pw_rpc;
89*61c4878aSAndroid Build Coastguard Worker    rpc_log_drain_other-->pw_rpc;
90*61c4878aSAndroid Build Coastguard Worker    pw_rpc-->computer[Computer];
91*61c4878aSAndroid Build Coastguard Worker    pw_rpc-->other_listener[Other log<br>listener];
92*61c4878aSAndroid Build Coastguard Worker
93*61c4878aSAndroid Build Coastguard WorkerRelation to pw_log and pw_log_tokenized
94*61c4878aSAndroid Build Coastguard Worker=======================================
95*61c4878aSAndroid Build Coastguard Worker``pw_log_rpc`` is often used in combination with ``pw_log`` and
96*61c4878aSAndroid Build Coastguard Worker``pw_log_tokenized``. The diagram below shows the order of execution after
97*61c4878aSAndroid Build Coastguard Workerinvoking a ``pw_log`` macro.
98*61c4878aSAndroid Build Coastguard Worker
99*61c4878aSAndroid Build Coastguard Worker.. mermaid::
100*61c4878aSAndroid Build Coastguard Worker
101*61c4878aSAndroid Build Coastguard Worker   flowchart TD
102*61c4878aSAndroid Build Coastguard Worker     project["`**your project code**`"]
103*61c4878aSAndroid Build Coastguard Worker     --> pw_log["`**pw_log**
104*61c4878aSAndroid Build Coastguard Worker                  *facade*`"]
105*61c4878aSAndroid Build Coastguard Worker     --> token_backend["`**pw_log_tokenized**
106*61c4878aSAndroid Build Coastguard Worker                         *backend for pw_log*`"]
107*61c4878aSAndroid Build Coastguard Worker     --> token_facade["`**pw_log_tokenized:handler**
108*61c4878aSAndroid Build Coastguard Worker                        *facade*`"]
109*61c4878aSAndroid Build Coastguard Worker     --> custom_backend["`**your custom code**
110*61c4878aSAndroid Build Coastguard Worker                          *backend for pw_log_tokenized:handler*`"]
111*61c4878aSAndroid Build Coastguard Worker     --> pw_log_rpc["`**pw_log_rpc**`"];
112*61c4878aSAndroid Build Coastguard Worker
113*61c4878aSAndroid Build Coastguard Worker* See :ref:`docs-module-structure-facades` for an explanation of facades and
114*61c4878aSAndroid Build Coastguard Worker  backends.
115*61c4878aSAndroid Build Coastguard Worker* See ``pw_log_tokenized_HandleLog()`` and ``pw_log_tokenized_HandleMessageVaList()``
116*61c4878aSAndroid Build Coastguard Worker  in ``//pw_system/log_backend.cc`` for an example of how :ref:`module-pw_system`
117*61c4878aSAndroid Build Coastguard Worker  implements ``your custom code (pw_log_tokenized backend)``.
118*61c4878aSAndroid Build Coastguard Worker
119*61c4878aSAndroid Build Coastguard WorkerComponents Overview
120*61c4878aSAndroid Build Coastguard Worker===================
121*61c4878aSAndroid Build Coastguard WorkerLogEntry and LogEntries
122*61c4878aSAndroid Build Coastguard Worker-----------------------
123*61c4878aSAndroid Build Coastguard WorkerRPC logging uses ``LogEntry`` to encapsulate each entry's data, such as level,
124*61c4878aSAndroid Build Coastguard Workertimestamp, and message. ``LogEntries`` can hold multiple instances of
125*61c4878aSAndroid Build Coastguard Worker``LogEntry`` to send more data using fewer transmissions. The ``LogEntries`` has
126*61c4878aSAndroid Build Coastguard Workeran optional field for the first message's sequence ID that corresponds to the
127*61c4878aSAndroid Build Coastguard Workercount of each ``LogEntry`` that passes the log filter and is sent. A client can
128*61c4878aSAndroid Build Coastguard Workeruse this sequence ID and the number of messages in a ``LogEntries`` to figure
129*61c4878aSAndroid Build Coastguard Workerout if logs were dropped during transmission.
130*61c4878aSAndroid Build Coastguard Worker
131*61c4878aSAndroid Build Coastguard WorkerRPC log service
132*61c4878aSAndroid Build Coastguard Worker---------------
133*61c4878aSAndroid Build Coastguard WorkerThe ``LogService`` class is an RPC service that provides a way to request a log
134*61c4878aSAndroid Build Coastguard Workerstream sent via RPC and configure log filters. Thus, it helps avoid
135*61c4878aSAndroid Build Coastguard Workerusing a different protocol for logs and RPCs over the same interface(s).
136*61c4878aSAndroid Build Coastguard WorkerIt requires a ``RpcLogDrainMap`` to assign stream writers and delegate the
137*61c4878aSAndroid Build Coastguard Workerlog stream flushing to the user's preferred method, as well as a ``FilterMap``
138*61c4878aSAndroid Build Coastguard Workerto retrieve and modify filters. The client may also stop streaming the logs by
139*61c4878aSAndroid Build Coastguard Workercalling ``Cancel()`` or ``RequestCompletion()`` using the ``RawClientReader``
140*61c4878aSAndroid Build Coastguard Workerinterface. Note that ``Cancel()`` may lead to dropped logs. To prevent dropped
141*61c4878aSAndroid Build Coastguard Workerlogs use ``RequestCompletion()`` and enable :c:macro:`PW_RPC_COMPLETION_REQUEST_CALLBACK`
142*61c4878aSAndroid Build Coastguard Workere.g. ``-DPW_RPC_COMPLETION_REQUEST_CALLBACK=1``.
143*61c4878aSAndroid Build Coastguard WorkerIf ``PW_RPC_COMPLETION_REQUEST_CALLBACK`` is not enabled, RequestCompletion()
144*61c4878aSAndroid Build Coastguard Workercall will not stop the logging stream.
145*61c4878aSAndroid Build Coastguard Worker
146*61c4878aSAndroid Build Coastguard WorkerRpcLogDrain
147*61c4878aSAndroid Build Coastguard Worker-----------
148*61c4878aSAndroid Build Coastguard WorkerAn ``RpcLogDrain`` reads from the ``MultiSink`` instance that buffers logs, then
149*61c4878aSAndroid Build Coastguard Workerpacks, and sends the retrieved log entries to the log listener. One
150*61c4878aSAndroid Build Coastguard Worker``RpcLogDrain`` is needed for each log listener. An ``RpcLogDrain`` needs a
151*61c4878aSAndroid Build Coastguard Workerthread to continuously call ``Flush()`` to maintain the log stream. A thread can
152*61c4878aSAndroid Build Coastguard Workermaintain multiple log streams, but it must not be the same thread used by the
153*61c4878aSAndroid Build Coastguard WorkerRPC server, to avoid blocking it.
154*61c4878aSAndroid Build Coastguard Worker
155*61c4878aSAndroid Build Coastguard WorkerEach ``RpcLogDrain`` is identified by a known RPC channel ID and requires a
156*61c4878aSAndroid Build Coastguard Worker``rpc::RawServerWriter`` to write the packed multiple log entries. This writer
157*61c4878aSAndroid Build Coastguard Workeris assigned by the ``LogService::Listen`` RPC.
158*61c4878aSAndroid Build Coastguard Worker
159*61c4878aSAndroid Build Coastguard Worker``RpcLogDrain``\s can also be provided an open RPC writer, to constantly stream
160*61c4878aSAndroid Build Coastguard Workerlogs without the need to request them. This is useful in cases where the
161*61c4878aSAndroid Build Coastguard Workerconnection to the client is dropped silently because the log stream can continue
162*61c4878aSAndroid Build Coastguard Workerwhen reconnected without the client requesting logs again if the error handling
163*61c4878aSAndroid Build Coastguard Workeris set to ``kIgnoreWriterErrors`` otherwise the writer will be closed.
164*61c4878aSAndroid Build Coastguard Worker
165*61c4878aSAndroid Build Coastguard WorkerAn ``RpcLogDrain`` must be attached to a ``MultiSink`` containing multiple
166*61c4878aSAndroid Build Coastguard Worker``log::LogEntry``\s. When ``Flush`` is called, the drain acquires the
167*61c4878aSAndroid Build Coastguard Worker``rpc::RawServerWriter`` 's write buffer, grabs one ``log::LogEntry`` from the
168*61c4878aSAndroid Build Coastguard Workermultisink, encodes it into a ``log::LogEntries`` stream, and repeats the process
169*61c4878aSAndroid Build Coastguard Workeruntil the write buffer is full. Then the drain calls
170*61c4878aSAndroid Build Coastguard Worker``rpc::RawServerWriter::Write`` to flush the write buffer and repeats the
171*61c4878aSAndroid Build Coastguard Workerprocess until all the entries in the ``MultiSink`` are read or an error is
172*61c4878aSAndroid Build Coastguard Workerfound.
173*61c4878aSAndroid Build Coastguard Worker
174*61c4878aSAndroid Build Coastguard WorkerThe user must provide a buffer large enough for the largest entry in the
175*61c4878aSAndroid Build Coastguard Worker``MultiSink`` while also accounting for the interface's Maximum Transmission
176*61c4878aSAndroid Build Coastguard WorkerUnit (MTU). If the ``RpcLogDrain`` finds a drop message count as it reads the
177*61c4878aSAndroid Build Coastguard Worker``MultiSink`` it will insert a message in the stream with the drop message
178*61c4878aSAndroid Build Coastguard Workercount in the log proto dropped optional field. The receiving end can display the
179*61c4878aSAndroid Build Coastguard Workercount with the logs if desired.
180*61c4878aSAndroid Build Coastguard Worker
181*61c4878aSAndroid Build Coastguard WorkerRpcLogDrainMap
182*61c4878aSAndroid Build Coastguard Worker--------------
183*61c4878aSAndroid Build Coastguard WorkerProvides a convenient way to access all or a single ``RpcLogDrain`` by its RPC
184*61c4878aSAndroid Build Coastguard Workerchannel ID.
185*61c4878aSAndroid Build Coastguard Worker
186*61c4878aSAndroid Build Coastguard WorkerRpcLogDrainThread
187*61c4878aSAndroid Build Coastguard Worker-----------------
188*61c4878aSAndroid Build Coastguard WorkerThe module includes a sample thread that flushes each drain sequentially.
189*61c4878aSAndroid Build Coastguard Worker``RpcLogDrainThread`` takes an encoding buffer span at construction.
190*61c4878aSAndroid Build Coastguard Worker``RpcLogDrainThreadWithBuffer`` takes a template parameter for the buffer size,
191*61c4878aSAndroid Build Coastguard Workerwhich must be large enough to fit at least one log entry.
192*61c4878aSAndroid Build Coastguard Worker
193*61c4878aSAndroid Build Coastguard WorkerFuture work might replace this with enqueueing the flush work on a work queue.
194*61c4878aSAndroid Build Coastguard WorkerThe user can also choose to have different threads flushing individual
195*61c4878aSAndroid Build Coastguard Worker``RpcLogDrain``\s with different priorities.
196*61c4878aSAndroid Build Coastguard Worker
197*61c4878aSAndroid Build Coastguard WorkerWhen creating a ``RpcLogDrainThread``, the thread can be configured to
198*61c4878aSAndroid Build Coastguard Workerrate limit logs by introducing a limit to how many logs can be flushed from
199*61c4878aSAndroid Build Coastguard Workereach sink before a configurable sleep period begins to give the sinks time to
200*61c4878aSAndroid Build Coastguard Workerhandle the flushed logs. For example, if the rate limiting is configured to 2
201*61c4878aSAndroid Build Coastguard Workerlog bundles per flush with minimum delay of 100ms between flushes, the logging
202*61c4878aSAndroid Build Coastguard Workerthread will send at most 20 log bundles per second over each sink. Log bundle
203*61c4878aSAndroid Build Coastguard Workersize is dictated by the size of the encode buffer provided to the
204*61c4878aSAndroid Build Coastguard WorkerRpcLogDrainThread.
205*61c4878aSAndroid Build Coastguard Worker
206*61c4878aSAndroid Build Coastguard WorkerRate limiting is helpful in cases where transient bursts of high volumes of logs
207*61c4878aSAndroid Build Coastguard Workercause transport buffers to saturate. By rate limiting the RPC log drain, the
208*61c4878aSAndroid Build Coastguard Workertransport buffers are given time to send data. As long as the average logging
209*61c4878aSAndroid Build Coastguard Workerrate is significantly less than the rate limit imposed by the
210*61c4878aSAndroid Build Coastguard Worker``RpcLogDrainThread``, the logging pipeline should be more resilient high
211*61c4878aSAndroid Build Coastguard Workervolume log bursts.
212*61c4878aSAndroid Build Coastguard Worker
213*61c4878aSAndroid Build Coastguard WorkerRate limiting log drains is particularly helpful for systems that collect logs
214*61c4878aSAndroid Build Coastguard Workerto a multisink in bulk when communications aren't available (e.g. collecting
215*61c4878aSAndroid Build Coastguard Workerearly boot logs until the logging thread starts). If a very full log buffer is
216*61c4878aSAndroid Build Coastguard Workersuddenly flushed to the sinks without rate limiting, it's possible to overwhelm
217*61c4878aSAndroid Build Coastguard Workerthe output buffers if they don't have sufficient headroom.
218*61c4878aSAndroid Build Coastguard Worker
219*61c4878aSAndroid Build Coastguard Worker.. note::
220*61c4878aSAndroid Build Coastguard Worker  Introducing a logging drain rate limit will increase logging latency, but
221*61c4878aSAndroid Build Coastguard Worker  usually not by much. It's important to tune the rate limit configuration to
222*61c4878aSAndroid Build Coastguard Worker  ensure it doesn't unnecessarily introduce a logging bottleneck or
223*61c4878aSAndroid Build Coastguard Worker  significantly increase latency.
224*61c4878aSAndroid Build Coastguard Worker
225*61c4878aSAndroid Build Coastguard WorkerCalling ``OpenUnrequestedLogStream()`` is a convenient way to set up a log
226*61c4878aSAndroid Build Coastguard Workerstream that is started without the need to receive an RCP request for logs.
227*61c4878aSAndroid Build Coastguard Worker
228*61c4878aSAndroid Build Coastguard WorkerThe ``RpcLogDrainThread`` sets up a callback for each drain, to be notified when
229*61c4878aSAndroid Build Coastguard Workera drain is opened and flushing must resume.
230*61c4878aSAndroid Build Coastguard Worker
231*61c4878aSAndroid Build Coastguard Worker---------
232*61c4878aSAndroid Build Coastguard WorkerLog Drops
233*61c4878aSAndroid Build Coastguard Worker---------
234*61c4878aSAndroid Build Coastguard WorkerUnfortunately, logs can be dropped and not reach the destination. This module
235*61c4878aSAndroid Build Coastguard Workerexpects to cover all cases and be able to notify the user of log drops when
236*61c4878aSAndroid Build Coastguard Workerpossible. Logs can be dropped when
237*61c4878aSAndroid Build Coastguard Worker
238*61c4878aSAndroid Build Coastguard Worker- They don't pass a filter. This is the expected behavior, so filtered logs will
239*61c4878aSAndroid Build Coastguard Worker  not be tracked as dropped logs.
240*61c4878aSAndroid Build Coastguard Worker- The drains are too slow to keep up. In this case, the ring buffer is full of
241*61c4878aSAndroid Build Coastguard Worker  undrained entries; when new logs come in, old entries are dropped. The log
242*61c4878aSAndroid Build Coastguard Worker  stream will contain a ``LogEntry`` message with the number of dropped logs.
243*61c4878aSAndroid Build Coastguard Worker  E.g.
244*61c4878aSAndroid Build Coastguard Worker
245*61c4878aSAndroid Build Coastguard Worker      Dropped 15 logs due to slow reader
246*61c4878aSAndroid Build Coastguard Worker
247*61c4878aSAndroid Build Coastguard Worker- There is an error creating or adding a new log entry, and the ring buffer is
248*61c4878aSAndroid Build Coastguard Worker  notified that the log had to be dropped. The log stream will contain a
249*61c4878aSAndroid Build Coastguard Worker  ``LogEntry`` message with the number of dropped logs.
250*61c4878aSAndroid Build Coastguard Worker  E.g.
251*61c4878aSAndroid Build Coastguard Worker
252*61c4878aSAndroid Build Coastguard Worker      Dropped 15 logs due to slow reader
253*61c4878aSAndroid Build Coastguard Worker
254*61c4878aSAndroid Build Coastguard Worker- A log entry is too large for the stack buffer. The log stream will contain
255*61c4878aSAndroid Build Coastguard Worker  an error message with the drop count. Provide a log buffer that fits the
256*61c4878aSAndroid Build Coastguard Worker  largest entry added to the MultiSink to avoid this error.
257*61c4878aSAndroid Build Coastguard Worker  E.g.
258*61c4878aSAndroid Build Coastguard Worker
259*61c4878aSAndroid Build Coastguard Worker      Dropped 1 log due to stack buffer too small
260*61c4878aSAndroid Build Coastguard Worker
261*61c4878aSAndroid Build Coastguard Worker- A log entry is too large for the outbound buffer. The log stream will contain
262*61c4878aSAndroid Build Coastguard Worker  an error message with the drop count. Provide a log buffer that fits the
263*61c4878aSAndroid Build Coastguard Worker  largest entry added to the MultiSink to avoid this error.
264*61c4878aSAndroid Build Coastguard Worker  E.g.
265*61c4878aSAndroid Build Coastguard Worker
266*61c4878aSAndroid Build Coastguard Worker      Dropped 1 log due to outbound buffer too small
267*61c4878aSAndroid Build Coastguard Worker
268*61c4878aSAndroid Build Coastguard Worker- There are detected errors transmitting log entries. The log stream will
269*61c4878aSAndroid Build Coastguard Worker  contain a ``LogEntry`` with an error message and the number of dropped logs
270*61c4878aSAndroid Build Coastguard Worker  the next time the stream is flushed only if the drain's error handling is set
271*61c4878aSAndroid Build Coastguard Worker  to close the stream on error.
272*61c4878aSAndroid Build Coastguard Worker  E.g.
273*61c4878aSAndroid Build Coastguard Worker
274*61c4878aSAndroid Build Coastguard Worker      Dropped 10 logs due to writer error
275*61c4878aSAndroid Build Coastguard Worker
276*61c4878aSAndroid Build Coastguard Worker- There are undetected errors transmitting or receiving log entries, such as an
277*61c4878aSAndroid Build Coastguard Worker  interface interruption. Clients can calculate the number of logs lost in
278*61c4878aSAndroid Build Coastguard Worker  transit using the sequence ID and number of entries in each stream packet.
279*61c4878aSAndroid Build Coastguard Worker  E.g.
280*61c4878aSAndroid Build Coastguard Worker
281*61c4878aSAndroid Build Coastguard Worker      Dropped 50 logs due to transmission error
282*61c4878aSAndroid Build Coastguard Worker
283*61c4878aSAndroid Build Coastguard WorkerThe drop count is combined when possible, and reported only when an entry, that
284*61c4878aSAndroid Build Coastguard Workerpasses any filters, is going to be sent.
285*61c4878aSAndroid Build Coastguard Worker
286*61c4878aSAndroid Build Coastguard Worker-------------
287*61c4878aSAndroid Build Coastguard WorkerLog Filtering
288*61c4878aSAndroid Build Coastguard Worker-------------
289*61c4878aSAndroid Build Coastguard WorkerA ``Filter`` anywhere in the path of a ``LogEntry`` proto, for example, in the
290*61c4878aSAndroid Build Coastguard Worker``PW_LOG*`` macro implementation, or in an ``RpcLogDrain`` if using RPC logging.
291*61c4878aSAndroid Build Coastguard WorkerThe log filtering service provides read and modify access to the ``Filter``\s
292*61c4878aSAndroid Build Coastguard Workerregistered in the ``FilterMap``.
293*61c4878aSAndroid Build Coastguard Worker
294*61c4878aSAndroid Build Coastguard WorkerHow to Use
295*61c4878aSAndroid Build Coastguard Worker==========
296*61c4878aSAndroid Build Coastguard Worker1. Set up RPC
297*61c4878aSAndroid Build Coastguard Worker-------------
298*61c4878aSAndroid Build Coastguard WorkerSet up RPC for your target device. See :ref:`module-pw_rpc` for details.
299*61c4878aSAndroid Build Coastguard Worker
300*61c4878aSAndroid Build Coastguard Worker2. Create ``Filter``\s
301*61c4878aSAndroid Build Coastguard Worker----------------------
302*61c4878aSAndroid Build Coastguard WorkerProvide each ``Filter`` with its own container for the ``FilterRules`` as big as
303*61c4878aSAndroid Build Coastguard Workerthe number of rules desired. These rules can be pre-poluated.
304*61c4878aSAndroid Build Coastguard Worker
305*61c4878aSAndroid Build Coastguard Worker3. Create a ``FilterMap`` and ``FilterService``
306*61c4878aSAndroid Build Coastguard Worker-----------------------------------------------
307*61c4878aSAndroid Build Coastguard WorkerSet up the ``FilterMap`` with the filters than can be modified with the
308*61c4878aSAndroid Build Coastguard Worker``FilterService``. Register the service with the RPC server.
309*61c4878aSAndroid Build Coastguard Worker
310*61c4878aSAndroid Build Coastguard Worker4. Use RPCs to retrieve and modify filter rules
311*61c4878aSAndroid Build Coastguard Worker-----------------------------------------------
312*61c4878aSAndroid Build Coastguard Worker
313*61c4878aSAndroid Build Coastguard WorkerComponents Overview
314*61c4878aSAndroid Build Coastguard Worker===================
315*61c4878aSAndroid Build Coastguard WorkerFilter::Rule
316*61c4878aSAndroid Build Coastguard Worker------------
317*61c4878aSAndroid Build Coastguard WorkerContains a set of values that are compared against a log when set. All
318*61c4878aSAndroid Build Coastguard Workerconditions must be met for the rule to be met.
319*61c4878aSAndroid Build Coastguard Worker
320*61c4878aSAndroid Build Coastguard Worker- ``action``: drops or keeps the log if the other conditions match.
321*61c4878aSAndroid Build Coastguard Worker  The rule is ignored when inactive.
322*61c4878aSAndroid Build Coastguard Worker
323*61c4878aSAndroid Build Coastguard Worker- ``any_flags_set``: the condition is met if this value is 0 or the log has any
324*61c4878aSAndroid Build Coastguard Worker  of these flags set.
325*61c4878aSAndroid Build Coastguard Worker
326*61c4878aSAndroid Build Coastguard Worker- ``level_greater_than_or_equal``: the condition is met when the log level is
327*61c4878aSAndroid Build Coastguard Worker  greater than or equal to this value.
328*61c4878aSAndroid Build Coastguard Worker
329*61c4878aSAndroid Build Coastguard Worker- ``module_equals``: the condition is met if this byte array is empty, or the
330*61c4878aSAndroid Build Coastguard Worker  log module equals the contents of this byte array.
331*61c4878aSAndroid Build Coastguard Worker
332*61c4878aSAndroid Build Coastguard Worker- ``thread_equals``: the condition is met if this byte array is empty or the
333*61c4878aSAndroid Build Coastguard Worker  log thread equals the contents of this byte array.
334*61c4878aSAndroid Build Coastguard Worker
335*61c4878aSAndroid Build Coastguard WorkerFilter
336*61c4878aSAndroid Build Coastguard Worker------
337*61c4878aSAndroid Build Coastguard WorkerEncapsulates a collection of zero or more ``Filter::Rule``\s and has
338*61c4878aSAndroid Build Coastguard Workeran ID used to modify or retrieve its contents.
339*61c4878aSAndroid Build Coastguard Worker
340*61c4878aSAndroid Build Coastguard WorkerFilterMap
341*61c4878aSAndroid Build Coastguard Worker---------
342*61c4878aSAndroid Build Coastguard WorkerProvides a convenient way to retrieve register filters by ID.
343*61c4878aSAndroid Build Coastguard Worker
344*61c4878aSAndroid Build Coastguard Worker----------------------------
345*61c4878aSAndroid Build Coastguard WorkerLogging with filters example
346*61c4878aSAndroid Build Coastguard Worker----------------------------
347*61c4878aSAndroid Build Coastguard WorkerThe following code shows a sample setup to defer the log handling to the
348*61c4878aSAndroid Build Coastguard Worker``RpcLogDrainThread`` to avoid having the log streaming block at the log
349*61c4878aSAndroid Build Coastguard Workercallsite.
350*61c4878aSAndroid Build Coastguard Worker
351*61c4878aSAndroid Build Coastguard Workermain.cc
352*61c4878aSAndroid Build Coastguard Worker=======
353*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
354*61c4878aSAndroid Build Coastguard Worker
355*61c4878aSAndroid Build Coastguard Worker   #include "foo/log.h"
356*61c4878aSAndroid Build Coastguard Worker   #include "pw_log/log.h"
357*61c4878aSAndroid Build Coastguard Worker   #include "pw_thread/detached_thread.h"
358*61c4878aSAndroid Build Coastguard Worker   #include "pw_thread_stl/options.h"
359*61c4878aSAndroid Build Coastguard Worker
360*61c4878aSAndroid Build Coastguard Worker   namespace {
361*61c4878aSAndroid Build Coastguard Worker
362*61c4878aSAndroid Build Coastguard Worker   void RegisterServices() {
363*61c4878aSAndroid Build Coastguard Worker     pw::rpc::system_server::Server().RegisterService(foo::log::log_service);
364*61c4878aSAndroid Build Coastguard Worker     pw::rpc::system_server::Server().RegisterService(foo::log::filter_service);
365*61c4878aSAndroid Build Coastguard Worker   }
366*61c4878aSAndroid Build Coastguard Worker   }  // namespace
367*61c4878aSAndroid Build Coastguard Worker
368*61c4878aSAndroid Build Coastguard Worker   int main() {
369*61c4878aSAndroid Build Coastguard Worker     PW_LOG_INFO("Deferred logging over RPC example");
370*61c4878aSAndroid Build Coastguard Worker     pw::rpc::system_server::Init();
371*61c4878aSAndroid Build Coastguard Worker     RegisterServices();
372*61c4878aSAndroid Build Coastguard Worker     pw::thread::DetachedThread(pw::thread::stl::Options(), foo::log::log_thread);
373*61c4878aSAndroid Build Coastguard Worker     pw::rpc::system_server::Start();
374*61c4878aSAndroid Build Coastguard Worker     return 0;
375*61c4878aSAndroid Build Coastguard Worker   }
376*61c4878aSAndroid Build Coastguard Worker
377*61c4878aSAndroid Build Coastguard Workerfoo/log.cc
378*61c4878aSAndroid Build Coastguard Worker==========
379*61c4878aSAndroid Build Coastguard WorkerExample of a log backend implementation, where logs enter the ``MultiSink`` and
380*61c4878aSAndroid Build Coastguard Workerlog drains and filters are set up.
381*61c4878aSAndroid Build Coastguard Worker
382*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
383*61c4878aSAndroid Build Coastguard Worker
384*61c4878aSAndroid Build Coastguard Worker   #include "foo/log.h"
385*61c4878aSAndroid Build Coastguard Worker
386*61c4878aSAndroid Build Coastguard Worker   #include <array>
387*61c4878aSAndroid Build Coastguard Worker   #include <cstdint>
388*61c4878aSAndroid Build Coastguard Worker
389*61c4878aSAndroid Build Coastguard Worker   #include "pw_chrono/system_clock.h"
390*61c4878aSAndroid Build Coastguard Worker   #include "pw_log/proto_utils.h"
391*61c4878aSAndroid Build Coastguard Worker   #include "pw_log_rpc/log_filter.h"
392*61c4878aSAndroid Build Coastguard Worker   #include "pw_log_rpc/log_filter_map.h"
393*61c4878aSAndroid Build Coastguard Worker   #include "pw_log_rpc/log_filter_service.h"
394*61c4878aSAndroid Build Coastguard Worker   #include "pw_log_rpc/log_service.h"
395*61c4878aSAndroid Build Coastguard Worker   #include "pw_log_rpc/rpc_log_drain.h"
396*61c4878aSAndroid Build Coastguard Worker   #include "pw_log_rpc/rpc_log_drain_map.h"
397*61c4878aSAndroid Build Coastguard Worker   #include "pw_log_rpc/rpc_log_drain_thread.h"
398*61c4878aSAndroid Build Coastguard Worker   #include "pw_rpc_system_server/rpc_server.h"
399*61c4878aSAndroid Build Coastguard Worker   #include "pw_sync/interrupt_spin_lock.h"
400*61c4878aSAndroid Build Coastguard Worker   #include "pw_sync/lock_annotations.h"
401*61c4878aSAndroid Build Coastguard Worker   #include "pw_sync/mutex.h"
402*61c4878aSAndroid Build Coastguard Worker
403*61c4878aSAndroid Build Coastguard Worker   namespace foo::log {
404*61c4878aSAndroid Build Coastguard Worker   namespace {
405*61c4878aSAndroid Build Coastguard Worker   constexpr size_t kLogBufferSize = 5000;
406*61c4878aSAndroid Build Coastguard Worker   // Tokenized logs are typically 12-24 bytes.
407*61c4878aSAndroid Build Coastguard Worker   constexpr size_t kMaxMessageSize = 32;
408*61c4878aSAndroid Build Coastguard Worker   // kMaxLogEntrySize should be less than the MTU of the RPC channel output used
409*61c4878aSAndroid Build Coastguard Worker   // by the provided server writer.
410*61c4878aSAndroid Build Coastguard Worker   constexpr size_t kMaxLogEntrySize =
411*61c4878aSAndroid Build Coastguard Worker       pw::log_rpc::RpcLogDrain::kMinEntrySizeWithoutPayload + kMaxMessageSize;
412*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, kLogBufferSize> multisink_buffer;
413*61c4878aSAndroid Build Coastguard Worker
414*61c4878aSAndroid Build Coastguard Worker   // To save RAM, share the mutex, since drains will be managed sequentially.
415*61c4878aSAndroid Build Coastguard Worker   pw::sync::Mutex shared_mutex;
416*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, kMaxEntrySize> client1_buffer
417*61c4878aSAndroid Build Coastguard Worker       PW_GUARDED_BY(shared_mutex);
418*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, kMaxEntrySize> client2_buffer
419*61c4878aSAndroid Build Coastguard Worker       PW_GUARDED_BY(shared_mutex);
420*61c4878aSAndroid Build Coastguard Worker   std::array<pw::log_rpc::RpcLogDrain, 2> drains = {
421*61c4878aSAndroid Build Coastguard Worker       pw::log_rpc::RpcLogDrain(
422*61c4878aSAndroid Build Coastguard Worker           1,
423*61c4878aSAndroid Build Coastguard Worker           client1_buffer,
424*61c4878aSAndroid Build Coastguard Worker           shared_mutex,
425*61c4878aSAndroid Build Coastguard Worker           RpcLogDrain::LogDrainErrorHandling::kIgnoreWriterErrors),
426*61c4878aSAndroid Build Coastguard Worker       pw::log_rpc::RpcLogDrain(
427*61c4878aSAndroid Build Coastguard Worker           2,
428*61c4878aSAndroid Build Coastguard Worker           client2_buffer,
429*61c4878aSAndroid Build Coastguard Worker           shared_mutex,
430*61c4878aSAndroid Build Coastguard Worker           RpcLogDrain::LogDrainErrorHandling::kIgnoreWriterErrors),
431*61c4878aSAndroid Build Coastguard Worker   };
432*61c4878aSAndroid Build Coastguard Worker
433*61c4878aSAndroid Build Coastguard Worker   pw::sync::InterruptSpinLock log_encode_lock;
434*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, kMaxLogEntrySize> log_encode_buffer
435*61c4878aSAndroid Build Coastguard Worker       PW_GUARDED_BY(log_encode_lock);
436*61c4878aSAndroid Build Coastguard Worker
437*61c4878aSAndroid Build Coastguard Worker   std::array<Filter::Rule, 2> logs_to_host_filter_rules;
438*61c4878aSAndroid Build Coastguard Worker   std::array<Filter::Rule, 2> logs_to_server_filter_rules{{
439*61c4878aSAndroid Build Coastguard Worker       {
440*61c4878aSAndroid Build Coastguard Worker           .action = Filter::Rule::Action::kKeep,
441*61c4878aSAndroid Build Coastguard Worker           .level_greater_than_or_equal = pw::log::FilterRule::Level::INFO_LEVEL,
442*61c4878aSAndroid Build Coastguard Worker       },
443*61c4878aSAndroid Build Coastguard Worker       {
444*61c4878aSAndroid Build Coastguard Worker           .action = Filter::Rule::Action::kDrop,
445*61c4878aSAndroid Build Coastguard Worker       },
446*61c4878aSAndroid Build Coastguard Worker   }};
447*61c4878aSAndroid Build Coastguard Worker   std::array<Filter, 2> filters{
448*61c4878aSAndroid Build Coastguard Worker       Filter(pw::as_bytes(pw::span("HOST", 4)), logs_to_host_filter_rules),
449*61c4878aSAndroid Build Coastguard Worker       Filter(pw::as_bytes(pw::span("WEB", 3)), logs_to_server_filter_rules),
450*61c4878aSAndroid Build Coastguard Worker   };
451*61c4878aSAndroid Build Coastguard Worker   pw::log_rpc::FilterMap filter_map(filters);
452*61c4878aSAndroid Build Coastguard Worker
453*61c4878aSAndroid Build Coastguard Worker   extern "C" void pw_log_tokenized_HandleLog(
454*61c4878aSAndroid Build Coastguard Worker       uint32_t metadata, const uint8_t message[], size_t size_bytes) {
455*61c4878aSAndroid Build Coastguard Worker     int64_t timestamp =
456*61c4878aSAndroid Build Coastguard Worker         pw::chrono::SystemClock::now().time_since_epoch().count();
457*61c4878aSAndroid Build Coastguard Worker     std::lock_guard lock(log_encode_lock);
458*61c4878aSAndroid Build Coastguard Worker     pw::Result<pw::ConstByteSpan> encoded_log_result =
459*61c4878aSAndroid Build Coastguard Worker       pw::log::EncodeTokenizedLog(
460*61c4878aSAndroid Build Coastguard Worker           metadata, message, size_bytes, timestamp, log_encode_buffer);
461*61c4878aSAndroid Build Coastguard Worker
462*61c4878aSAndroid Build Coastguard Worker     if (!encoded_log_result.ok()) {
463*61c4878aSAndroid Build Coastguard Worker       GetMultiSink().HandleDropped();
464*61c4878aSAndroid Build Coastguard Worker       return;
465*61c4878aSAndroid Build Coastguard Worker     }
466*61c4878aSAndroid Build Coastguard Worker     GetMultiSink().HandleEntry(encoded_log_result.value());
467*61c4878aSAndroid Build Coastguard Worker   }
468*61c4878aSAndroid Build Coastguard Worker   }  // namespace
469*61c4878aSAndroid Build Coastguard Worker
470*61c4878aSAndroid Build Coastguard Worker   pw::log_rpc::RpcLogDrainMap drain_map(drains);
471*61c4878aSAndroid Build Coastguard Worker   pw::log_rpc::RpcLogDrainThread log_thread(GetMultiSink(), drain_map);
472*61c4878aSAndroid Build Coastguard Worker   pw::log_rpc::LogService log_service(drain_map);
473*61c4878aSAndroid Build Coastguard Worker   pw::log_rpc::FilterService filter_service(filter_map);
474*61c4878aSAndroid Build Coastguard Worker
475*61c4878aSAndroid Build Coastguard Worker   pw::multisink::MultiSink& GetMultiSink() {
476*61c4878aSAndroid Build Coastguard Worker     static pw::multisink::MultiSink multisink(multisink_buffer);
477*61c4878aSAndroid Build Coastguard Worker     return multisink;
478*61c4878aSAndroid Build Coastguard Worker   }
479*61c4878aSAndroid Build Coastguard Worker   }  // namespace foo::log
480*61c4878aSAndroid Build Coastguard Worker
481*61c4878aSAndroid Build Coastguard WorkerLogging in other source files
482*61c4878aSAndroid Build Coastguard Worker-----------------------------
483*61c4878aSAndroid Build Coastguard WorkerTo defer logging, other source files must simply include ``pw_log/log.h`` and
484*61c4878aSAndroid Build Coastguard Workeruse the :ref:`module-pw_log` APIs, as long as the source set that includes
485*61c4878aSAndroid Build Coastguard Worker``foo/log.cc`` is setup as the log backend.
486*61c4878aSAndroid Build Coastguard Worker
487*61c4878aSAndroid Build Coastguard Worker--------------------
488*61c4878aSAndroid Build Coastguard Workerpw_log_rpc in Python
489*61c4878aSAndroid Build Coastguard Worker--------------------
490*61c4878aSAndroid Build Coastguard Worker``pw_log_rpc`` provides client utilities for dealing with RPC logging.
491*61c4878aSAndroid Build Coastguard Worker
492*61c4878aSAndroid Build Coastguard WorkerThe ``LogStreamHandler`` offers APIs to start a log stream: ``start_logs``,
493*61c4878aSAndroid Build Coastguard Workerto handle RPC stream errors: ``handle_log_stream_error``, and RPC stream
494*61c4878aSAndroid Build Coastguard Workercompleted events: ``handle_log_stream_completed``. It uses a provided
495*61c4878aSAndroid Build Coastguard Worker``LogStreamDecoder`` to delegate log parsing to.
496*61c4878aSAndroid Build Coastguard Worker
497*61c4878aSAndroid Build Coastguard WorkerPython API
498*61c4878aSAndroid Build Coastguard Worker==========
499*61c4878aSAndroid Build Coastguard Worker
500*61c4878aSAndroid Build Coastguard Workerpw_log_rpc.rpc_log_stream
501*61c4878aSAndroid Build Coastguard Worker-------------------------
502*61c4878aSAndroid Build Coastguard Worker.. automodule:: pw_log_rpc.rpc_log_stream
503*61c4878aSAndroid Build Coastguard Worker    :members: LogStreamHandler
504*61c4878aSAndroid Build Coastguard Worker    :undoc-members:
505*61c4878aSAndroid Build Coastguard Worker    :show-inheritance:
506