xref: /aosp_15_r20/external/pigweed/pw_log/protobuf.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker.. _module-pw_log-protobuf:
2*61c4878aSAndroid Build Coastguard Worker
3*61c4878aSAndroid Build Coastguard Worker-------------------
4*61c4878aSAndroid Build Coastguard WorkerThe pw_log protobuf
5*61c4878aSAndroid Build Coastguard Worker-------------------
6*61c4878aSAndroid Build Coastguard Worker.. pigweed-module-subpage::
7*61c4878aSAndroid Build Coastguard Worker   :name: pw_log
8*61c4878aSAndroid Build Coastguard Worker
9*61c4878aSAndroid Build Coastguard Worker``pw_log`` defines a protocol buffer for storing and transmitting log messages.
10*61c4878aSAndroid Build Coastguard WorkerThe protobuf is optimized to be maximally efficient.
11*61c4878aSAndroid Build Coastguard Worker
12*61c4878aSAndroid Build Coastguard WorkerFields
13*61c4878aSAndroid Build Coastguard Worker======
14*61c4878aSAndroid Build Coastguard WorkerThe ``pw_log`` protobuf is defined in ``log.proto``.
15*61c4878aSAndroid Build Coastguard Worker
16*61c4878aSAndroid Build Coastguard Worker.. literalinclude:: log.proto
17*61c4878aSAndroid Build Coastguard Worker  :language: protobuf
18*61c4878aSAndroid Build Coastguard Worker  :lines: 14-
19*61c4878aSAndroid Build Coastguard Worker
20*61c4878aSAndroid Build Coastguard WorkerTimestamps
21*61c4878aSAndroid Build Coastguard Worker----------
22*61c4878aSAndroid Build Coastguard WorkerTimestamps are specified in implementation-defined ticks. Ticks could be
23*61c4878aSAndroid Build Coastguard Workermilliseconds, microsends, or any arbitrary duration derived from the device’s
24*61c4878aSAndroid Build Coastguard Workerclock.
25*61c4878aSAndroid Build Coastguard Worker
26*61c4878aSAndroid Build Coastguard WorkerFor many applications, the timestamp field can be interpreted based on the prior
27*61c4878aSAndroid Build Coastguard Workerknowledge of the system. For example, ``timestamp`` might be known to be
28*61c4878aSAndroid Build Coastguard Workermilliseconds since boot for one core or microseconds since boot for another.
29*61c4878aSAndroid Build Coastguard Worker
30*61c4878aSAndroid Build Coastguard WorkerIf desired, a project could collect information about clock parameters
31*61c4878aSAndroid Build Coastguard Workerseparately from ``pw_log``, and use that to interpret log timestamps. For
32*61c4878aSAndroid Build Coastguard Workerexample, they may call an RPC that returns a ``pw_chrono`` ``ClockParamters``
33*61c4878aSAndroid Build Coastguard Workerprotobuf. The values from that could be used to interpret timestamp from that
34*61c4878aSAndroid Build Coastguard Workerdevice.
35*61c4878aSAndroid Build Coastguard Worker
36*61c4878aSAndroid Build Coastguard WorkerThe ``pw_log`` proto contains two timestamp fields, only one of which may be set
37*61c4878aSAndroid Build Coastguard Workerat a time:
38*61c4878aSAndroid Build Coastguard Worker
39*61c4878aSAndroid Build Coastguard Worker- ``timestamp`` – Absolute time when message was logged.
40*61c4878aSAndroid Build Coastguard Worker- ``time_since_last_entry`` – When the message was logged, relative
41*61c4878aSAndroid Build Coastguard Worker  to the previously encoded log message. This is used when multiple log entries
42*61c4878aSAndroid Build Coastguard Worker  are sent in a single ``LogEntries`` proto. The previous log entry must use the
43*61c4878aSAndroid Build Coastguard Worker  same time source. If logs with multiple time sources are intermingled in a
44*61c4878aSAndroid Build Coastguard Worker  single ``LogEntries`` proto, they must use an absolute timestamp each time the
45*61c4878aSAndroid Build Coastguard Worker  time source changes.
46*61c4878aSAndroid Build Coastguard Worker
47*61c4878aSAndroid Build Coastguard WorkerOptionally tokenized text fields
48*61c4878aSAndroid Build Coastguard Worker--------------------------------
49*61c4878aSAndroid Build Coastguard WorkerSeveral fields in the ``pw_log`` proto store text. Examples include ``message``,
50*61c4878aSAndroid Build Coastguard Worker``module``, and ``thread``. These fields may contain either plain or tokenized
51*61c4878aSAndroid Build Coastguard Workertext, either of which is represented as a single bytes field. These fields are
52*61c4878aSAndroid Build Coastguard Workermarked with a protocol buffer option so the ``pw_tokenizer.proto`` module can
53*61c4878aSAndroid Build Coastguard Workerdetect and detokenize tokenized fields as appropriate.
54*61c4878aSAndroid Build Coastguard Worker
55*61c4878aSAndroid Build Coastguard WorkerSee :ref:`module-pw_tokenizer-proto` for details.
56*61c4878aSAndroid Build Coastguard Worker
57*61c4878aSAndroid Build Coastguard WorkerPacking and unpacking line_level
58*61c4878aSAndroid Build Coastguard Worker--------------------------------
59*61c4878aSAndroid Build Coastguard WorkerAs a way to minimize on-the-wire log message size, the log level and the line
60*61c4878aSAndroid Build Coastguard Workernumber of a given log statement are packed into a single proto field. There are
61*61c4878aSAndroid Build Coastguard Workerhelpers in ``pw_log/proto_utils.h`` for properly packing and unpacking this
62*61c4878aSAndroid Build Coastguard Workerfield.
63*61c4878aSAndroid Build Coastguard Worker
64*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
65*61c4878aSAndroid Build Coastguard Worker
66*61c4878aSAndroid Build Coastguard Worker   #include "pw_bytes/span.h"
67*61c4878aSAndroid Build Coastguard Worker   #include "pw_log/levels.h"
68*61c4878aSAndroid Build Coastguard Worker   #include "pw_log/proto_utils.h"
69*61c4878aSAndroid Build Coastguard Worker   #include "pw_protobuf/decoder.h"
70*61c4878aSAndroid Build Coastguard Worker
71*61c4878aSAndroid Build Coastguard Worker  bool FilterLog(pw::ConstByteSpan serialized_log) {
72*61c4878aSAndroid Build Coastguard Worker    pw::protobuf::Decoder log_decoder(serialized_log);
73*61c4878aSAndroid Build Coastguard Worker    while (log_decoder.Next().ok()) {
74*61c4878aSAndroid Build Coastguard Worker      if (log_decoder.FieldNumber() == 2) {
75*61c4878aSAndroid Build Coastguard Worker        uint32_t line_and_level;
76*61c4878aSAndroid Build Coastguard Worker        entry_decoder.ReadUint32(&line_and_level);
77*61c4878aSAndroid Build Coastguard Worker        PW_DCHECK(entry_decoder.ok());
78*61c4878aSAndroid Build Coastguard Worker
79*61c4878aSAndroid Build Coastguard Worker        uint8_t level = std::get<1>(pw::log::UnpackLineLevel(line_and_level));
80*61c4878aSAndroid Build Coastguard Worker        if (level < PW_LOG_LEVEL_INFO) {
81*61c4878aSAndroid Build Coastguard Worker          return false;
82*61c4878aSAndroid Build Coastguard Worker        }
83*61c4878aSAndroid Build Coastguard Worker      }
84*61c4878aSAndroid Build Coastguard Worker    }
85*61c4878aSAndroid Build Coastguard Worker
86*61c4878aSAndroid Build Coastguard Worker    return true;
87*61c4878aSAndroid Build Coastguard Worker  }
88*61c4878aSAndroid Build Coastguard Worker
89*61c4878aSAndroid Build Coastguard WorkerLog encoding helpers
90*61c4878aSAndroid Build Coastguard Worker--------------------
91*61c4878aSAndroid Build Coastguard WorkerEncoding logs to the ``log.proto`` format can be performed using the helpers
92*61c4878aSAndroid Build Coastguard Workerprovided in the ``pw_log/proto_utils.h`` header. Separate helpers are provided
93*61c4878aSAndroid Build Coastguard Workerfor encoding tokenized logs and string-based logs.
94*61c4878aSAndroid Build Coastguard Worker
95*61c4878aSAndroid Build Coastguard WorkerThe following example shows a :c:func:`pw_log_tokenized_HandleLog`
96*61c4878aSAndroid Build Coastguard Workerimplementation that encodes the results to a protobuf.
97*61c4878aSAndroid Build Coastguard Worker
98*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp
99*61c4878aSAndroid Build Coastguard Worker
100*61c4878aSAndroid Build Coastguard Worker   #include "pw_log/proto_utils.h"
101*61c4878aSAndroid Build Coastguard Worker
102*61c4878aSAndroid Build Coastguard Worker   extern "C" void pw_log_tokenized_HandleLog(
103*61c4878aSAndroid Build Coastguard Worker       uint32_t payload, const uint8_t data[], size_t size) {
104*61c4878aSAndroid Build Coastguard Worker     pw::log_tokenized::Metadata metadata(payload);
105*61c4878aSAndroid Build Coastguard Worker     std::byte log_buffer[kLogBufferSize];
106*61c4878aSAndroid Build Coastguard Worker
107*61c4878aSAndroid Build Coastguard Worker     Result<ConstByteSpan> result = EncodeTokenizedLog(
108*61c4878aSAndroid Build Coastguard Worker         metadata,
109*61c4878aSAndroid Build Coastguard Worker         pw::as_bytes(pw::span(data, size)),
110*61c4878aSAndroid Build Coastguard Worker         log_buffer);
111*61c4878aSAndroid Build Coastguard Worker     if (result.ok()) {
112*61c4878aSAndroid Build Coastguard Worker       // This makes use of the encoded log proto and is custom per-product.
113*61c4878aSAndroid Build Coastguard Worker       // It should be implemented by the caller and is not in Pigweed.
114*61c4878aSAndroid Build Coastguard Worker       EmitProtoLogEntry(result.value());
115*61c4878aSAndroid Build Coastguard Worker     }
116*61c4878aSAndroid Build Coastguard Worker   }
117