xref: /aosp_15_r20/external/pigweed/pw_log/log.proto (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker// Copyright 2021 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker//
3*61c4878aSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker// use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker// the License at
6*61c4878aSAndroid Build Coastguard Worker//
7*61c4878aSAndroid Build Coastguard Worker//     https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker//
9*61c4878aSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker// License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker// the License.
14*61c4878aSAndroid Build Coastguard Worker
15*61c4878aSAndroid Build Coastguard Workersyntax = "proto3";
16*61c4878aSAndroid Build Coastguard Worker
17*61c4878aSAndroid Build Coastguard Workerpackage pw.log;
18*61c4878aSAndroid Build Coastguard Worker
19*61c4878aSAndroid Build Coastguard Workerimport "pw_protobuf_protos/common.proto";
20*61c4878aSAndroid Build Coastguard Workerimport "pw_tokenizer_proto/options.proto";
21*61c4878aSAndroid Build Coastguard Worker
22*61c4878aSAndroid Build Coastguard Workeroption java_outer_classname = "Log";
23*61c4878aSAndroid Build Coastguard Worker
24*61c4878aSAndroid Build Coastguard Worker// A log message and metadata. Logs come in a few different forms:
25*61c4878aSAndroid Build Coastguard Worker//
26*61c4878aSAndroid Build Coastguard Worker//  1. A tokenized log message (recommended for production)
27*61c4878aSAndroid Build Coastguard Worker//  2. A non-tokenized log message (good for development)
28*61c4878aSAndroid Build Coastguard Worker//  3. A "log missed" tombstone, indicating that some logs were dropped
29*61c4878aSAndroid Build Coastguard Worker//
30*61c4878aSAndroid Build Coastguard Worker// Size analysis for tokenized log messages, including each field's proto tag:
31*61c4878aSAndroid Build Coastguard Worker//
32*61c4878aSAndroid Build Coastguard Worker//  - message     - 6-12 bytes; depending on number and value of arguments
33*61c4878aSAndroid Build Coastguard Worker//  - line_level  - 3 bytes; 4 bytes if line > 2048 (uncommon)
34*61c4878aSAndroid Build Coastguard Worker//  - timestamp   - 3 bytes; assuming delta encoding
35*61c4878aSAndroid Build Coastguard Worker//  - thread      - 2-6 bytes; depending on whether value is a token or string
36*61c4878aSAndroid Build Coastguard Worker//
37*61c4878aSAndroid Build Coastguard Worker// Adding the fields gives the total proto message size:
38*61c4878aSAndroid Build Coastguard Worker//
39*61c4878aSAndroid Build Coastguard Worker//    6-12 bytes - log
40*61c4878aSAndroid Build Coastguard Worker//    9-15 bytes - log + level + line
41*61c4878aSAndroid Build Coastguard Worker//   12-18 bytes - log + level + line + timestamp
42*61c4878aSAndroid Build Coastguard Worker//
43*61c4878aSAndroid Build Coastguard Worker// An analysis of a project's log token database revealed the following
44*61c4878aSAndroid Build Coastguard Worker// distribution of the number of arguments to log messages:
45*61c4878aSAndroid Build Coastguard Worker//
46*61c4878aSAndroid Build Coastguard Worker//   # args   # messages
47*61c4878aSAndroid Build Coastguard Worker//     0         2,700
48*61c4878aSAndroid Build Coastguard Worker//     1         2,400
49*61c4878aSAndroid Build Coastguard Worker//     2         1,200
50*61c4878aSAndroid Build Coastguard Worker//     3+        1,000
51*61c4878aSAndroid Build Coastguard Worker//
52*61c4878aSAndroid Build Coastguard Worker// Note: The below proto makes some compromises compared to what one might
53*61c4878aSAndroid Build Coastguard Worker// expect for a "clean" proto design, in order to shave bytes off of the
54*61c4878aSAndroid Build Coastguard Worker// messages. It is critical that the log messages are as small as possible to
55*61c4878aSAndroid Build Coastguard Worker// enable storing more logs in limited memory. This is why, for example, there
56*61c4878aSAndroid Build Coastguard Worker// is no separate "DroppedLog" type, or a "TokenizedLog" and "StringLog", which
57*61c4878aSAndroid Build Coastguard Worker// would add at least 2 extra bytes per message
58*61c4878aSAndroid Build Coastguard Workermessage LogEntry {
59*61c4878aSAndroid Build Coastguard Worker  // The log message, which may be tokenized.
60*61c4878aSAndroid Build Coastguard Worker  //
61*61c4878aSAndroid Build Coastguard Worker  // If tokenized logging is used, implementations may encode metadata in the
62*61c4878aSAndroid Build Coastguard Worker  // log message rather than as separate proto fields. This reduces the size of
63*61c4878aSAndroid Build Coastguard Worker  // the protobuf with no overhead.
64*61c4878aSAndroid Build Coastguard Worker  //
65*61c4878aSAndroid Build Coastguard Worker  // The standard format for encoding metadata in the log message is defined by
66*61c4878aSAndroid Build Coastguard Worker  // the pw_log_tokenized module. The message and metadata are encoded as
67*61c4878aSAndroid Build Coastguard Worker  // key-value pairs using ■ and ♦ as delimiters. For example:
68*61c4878aSAndroid Build Coastguard Worker  //
69*61c4878aSAndroid Build Coastguard Worker  //  ■msg♦This is the log message: %d■module♦wifi■file♦../path/to/file.cc
70*61c4878aSAndroid Build Coastguard Worker  //
71*61c4878aSAndroid Build Coastguard Worker  // See http://pigweed.dev/pw_log_tokenized for full details. When
72*61c4878aSAndroid Build Coastguard Worker  // pw_log_tokenized is used, this metadata is automatically included as
73*61c4878aSAndroid Build Coastguard Worker  // described.
74*61c4878aSAndroid Build Coastguard Worker  //
75*61c4878aSAndroid Build Coastguard Worker  // The level and flags are not included since they may be runtime values and
76*61c4878aSAndroid Build Coastguard Worker  // thus cannot always be tokenized. The line number is not included because
77*61c4878aSAndroid Build Coastguard Worker  // line numbers change frequently and a new token is created for each line.
78*61c4878aSAndroid Build Coastguard Worker  //
79*61c4878aSAndroid Build Coastguard Worker  // Size analysis when tokenized:
80*61c4878aSAndroid Build Coastguard Worker  //
81*61c4878aSAndroid Build Coastguard Worker  //   tag+wire = 1 byte
82*61c4878aSAndroid Build Coastguard Worker  //   size     = 1 byte; payload will almost always be < 127 bytes
83*61c4878aSAndroid Build Coastguard Worker  //   payload  = N bytes; typically 4-10 in practice
84*61c4878aSAndroid Build Coastguard Worker  //
85*61c4878aSAndroid Build Coastguard Worker  // Total: 2 + N ~= 6-12 bytes
86*61c4878aSAndroid Build Coastguard Worker  optional bytes message = 1 [(tokenizer.format) = TOKENIZATION_OPTIONAL];
87*61c4878aSAndroid Build Coastguard Worker
88*61c4878aSAndroid Build Coastguard Worker  // Packed log level and line number. Structure:
89*61c4878aSAndroid Build Coastguard Worker  //
90*61c4878aSAndroid Build Coastguard Worker  //   Level: Bottom 3 bits; level = line_level & 0x7
91*61c4878aSAndroid Build Coastguard Worker  //   Line: Remaining bits; line = (line_level >> 3)
92*61c4878aSAndroid Build Coastguard Worker  //
93*61c4878aSAndroid Build Coastguard Worker  // Note: This packing saves two bytes per log message in most cases compared
94*61c4878aSAndroid Build Coastguard Worker  // to having line and level separately; and is zero-cost if the log backend
95*61c4878aSAndroid Build Coastguard Worker  // omits the line number.
96*61c4878aSAndroid Build Coastguard Worker  uint32 line_level = 2;
97*61c4878aSAndroid Build Coastguard Worker
98*61c4878aSAndroid Build Coastguard Worker  // Some log messages have flags to indicate attributes such as whether they
99*61c4878aSAndroid Build Coastguard Worker  // are from an assert or if they contain PII. The particular flags are
100*61c4878aSAndroid Build Coastguard Worker  // product- and implementation-dependent.
101*61c4878aSAndroid Build Coastguard Worker  uint32 flags = 3;
102*61c4878aSAndroid Build Coastguard Worker
103*61c4878aSAndroid Build Coastguard Worker  // Timestamps are either specified with an absolute timestamp or relative to
104*61c4878aSAndroid Build Coastguard Worker  // the previous log entry.
105*61c4878aSAndroid Build Coastguard Worker  oneof time {
106*61c4878aSAndroid Build Coastguard Worker    // The absolute timestamp in implementation-defined ticks. Applications
107*61c4878aSAndroid Build Coastguard Worker    // determine how to interpret this on the receiving end. In the simplest
108*61c4878aSAndroid Build Coastguard Worker    // case, these ticks might be milliseconds or microseconds since boot.
109*61c4878aSAndroid Build Coastguard Worker    // Applications could also access clock information out-of-band with a
110*61c4878aSAndroid Build Coastguard Worker    // ClockParameters protobuf.
111*61c4878aSAndroid Build Coastguard Worker    int64 timestamp = 4;
112*61c4878aSAndroid Build Coastguard Worker
113*61c4878aSAndroid Build Coastguard Worker    // Time since the last entry in implementation-defined ticks, as for the
114*61c4878aSAndroid Build Coastguard Worker    // timestamp field. This enables delta encoding when batching entries
115*61c4878aSAndroid Build Coastguard Worker    // together.
116*61c4878aSAndroid Build Coastguard Worker    //
117*61c4878aSAndroid Build Coastguard Worker    // Size analysis for this field including tag and varint, assuming 1 kHz
118*61c4878aSAndroid Build Coastguard Worker    // ticks:
119*61c4878aSAndroid Build Coastguard Worker    //
120*61c4878aSAndroid Build Coastguard Worker    //           < 127 ms gap == 127 ms      ==  7 bits == 2 bytes
121*61c4878aSAndroid Build Coastguard Worker    //        < 16,000 ms gap ==  16 seconds == 14 bits == 3 bytes
122*61c4878aSAndroid Build Coastguard Worker    //     < 2,000,000 ms gap ==  35 minutes == 21 bits == 4 bytes
123*61c4878aSAndroid Build Coastguard Worker    //   < 300,000,000 ms gap ==  74 hours   == 28 bits == 5 bytes
124*61c4878aSAndroid Build Coastguard Worker    //
125*61c4878aSAndroid Build Coastguard Worker    // Log bursts will thus consume just 2 bytes (tag + up to 127ms delta) for
126*61c4878aSAndroid Build Coastguard Worker    // the timestamp, which is a good improvement over an absolute timestamp.
127*61c4878aSAndroid Build Coastguard Worker    int64 time_since_last_entry = 5;
128*61c4878aSAndroid Build Coastguard Worker  }
129*61c4878aSAndroid Build Coastguard Worker
130*61c4878aSAndroid Build Coastguard Worker  // When the log buffers are full but more logs come in, the logs are counted
131*61c4878aSAndroid Build Coastguard Worker  // and a special log message is omitted with only counts for the number of
132*61c4878aSAndroid Build Coastguard Worker  // messages dropped.
133*61c4878aSAndroid Build Coastguard Worker  uint32 dropped = 6;
134*61c4878aSAndroid Build Coastguard Worker
135*61c4878aSAndroid Build Coastguard Worker  // The PW_LOG_MODULE_NAME for this log message.
136*61c4878aSAndroid Build Coastguard Worker  bytes module = 7 [(tokenizer.format) = TOKENIZATION_OPTIONAL];
137*61c4878aSAndroid Build Coastguard Worker
138*61c4878aSAndroid Build Coastguard Worker  // The file path where this log was created, if not encoded in the message.
139*61c4878aSAndroid Build Coastguard Worker  bytes file = 8 [(tokenizer.format) = TOKENIZATION_OPTIONAL];
140*61c4878aSAndroid Build Coastguard Worker
141*61c4878aSAndroid Build Coastguard Worker  // The task or thread name that created the log message. If the log was not
142*61c4878aSAndroid Build Coastguard Worker  // created on a thread, it should use a name appropriate to that context.
143*61c4878aSAndroid Build Coastguard Worker  bytes thread = 9 [(tokenizer.format) = TOKENIZATION_OPTIONAL];
144*61c4878aSAndroid Build Coastguard Worker
145*61c4878aSAndroid Build Coastguard Worker  // The following fields are planned but will not be added until they are
146*61c4878aSAndroid Build Coastguard Worker  // needed. Protobuf field numbers over 15 use an extra byte, so these fields
147*61c4878aSAndroid Build Coastguard Worker  // are left out for now to avoid reserving field numbers unnecessarily.
148*61c4878aSAndroid Build Coastguard Worker
149*61c4878aSAndroid Build Coastguard Worker  // Represents the device from which the log originated. The meaning of this
150*61c4878aSAndroid Build Coastguard Worker  // field is implementation defined
151*61c4878aSAndroid Build Coastguard Worker  // uint32 source_id = ?;
152*61c4878aSAndroid Build Coastguard Worker
153*61c4878aSAndroid Build Coastguard Worker  // Some messages are associated with trace events, which may carry additional
154*61c4878aSAndroid Build Coastguard Worker  // contextual data. This is a tuple of a data format string which could be
155*61c4878aSAndroid Build Coastguard Worker  // used by the decoder to identify the data (e.g. printf-style tokens) and the
156*61c4878aSAndroid Build Coastguard Worker  // data itself in bytes.
157*61c4878aSAndroid Build Coastguard Worker  // bytes data_format = ?
158*61c4878aSAndroid Build Coastguard Worker  //     [(tokenizer.format) = TOKENIZATION_OPTIONAL];
159*61c4878aSAndroid Build Coastguard Worker  // bytes data = ?;
160*61c4878aSAndroid Build Coastguard Worker}
161*61c4878aSAndroid Build Coastguard Worker
162*61c4878aSAndroid Build Coastguard Workermessage LogRequest {}
163*61c4878aSAndroid Build Coastguard Worker
164*61c4878aSAndroid Build Coastguard Workermessage LogEntries {
165*61c4878aSAndroid Build Coastguard Worker  repeated LogEntry entries = 1;
166*61c4878aSAndroid Build Coastguard Worker  uint32 first_entry_sequence_id = 2;
167*61c4878aSAndroid Build Coastguard Worker}
168*61c4878aSAndroid Build Coastguard Worker
169*61c4878aSAndroid Build Coastguard Worker// RPC service for accessing logs.
170*61c4878aSAndroid Build Coastguard Workerservice Logs {
171*61c4878aSAndroid Build Coastguard Worker  rpc Listen(LogRequest) returns (stream LogEntries);
172*61c4878aSAndroid Build Coastguard Worker}
173*61c4878aSAndroid Build Coastguard Worker
174*61c4878aSAndroid Build Coastguard Workermessage FilterRule {
175*61c4878aSAndroid Build Coastguard Worker  // Log level values match pw_log/levels.h. Enum names avoid collissions with
176*61c4878aSAndroid Build Coastguard Worker  // possible macros.
177*61c4878aSAndroid Build Coastguard Worker  enum Level {
178*61c4878aSAndroid Build Coastguard Worker    ANY_LEVEL = 0;
179*61c4878aSAndroid Build Coastguard Worker    DEBUG_LEVEL = 1;
180*61c4878aSAndroid Build Coastguard Worker    INFO_LEVEL = 2;
181*61c4878aSAndroid Build Coastguard Worker    WARN_LEVEL = 3;
182*61c4878aSAndroid Build Coastguard Worker    ERROR_LEVEL = 4;
183*61c4878aSAndroid Build Coastguard Worker    CRITICAL_LEVEL = 5;
184*61c4878aSAndroid Build Coastguard Worker    FATAL_LEVEL = 7;
185*61c4878aSAndroid Build Coastguard Worker  };
186*61c4878aSAndroid Build Coastguard Worker  // Condition 1: log.level >= level_greater_than_or_equal.
187*61c4878aSAndroid Build Coastguard Worker  Level level_greater_than_or_equal = 1;
188*61c4878aSAndroid Build Coastguard Worker
189*61c4878aSAndroid Build Coastguard Worker  // Condition 2: (module_equals.size() == 0) || (log.module == module_equals);
190*61c4878aSAndroid Build Coastguard Worker  bytes module_equals = 2 [(tokenizer.format) = TOKENIZATION_OPTIONAL];
191*61c4878aSAndroid Build Coastguard Worker
192*61c4878aSAndroid Build Coastguard Worker  // Condition 3: (any_flags_set == 0) || (log.flags & any_flags_set) != 0))
193*61c4878aSAndroid Build Coastguard Worker  uint32 any_flags_set = 3;
194*61c4878aSAndroid Build Coastguard Worker
195*61c4878aSAndroid Build Coastguard Worker  // Action to take if all conditions are met and rule is not inactive.
196*61c4878aSAndroid Build Coastguard Worker  enum Action {
197*61c4878aSAndroid Build Coastguard Worker    INACTIVE = 0;  // Ignore the rule entirely.
198*61c4878aSAndroid Build Coastguard Worker    KEEP = 1;      // Keep the log entry if all conditions are met.
199*61c4878aSAndroid Build Coastguard Worker    DROP = 2;      // Drop the log entry if all conditions are met
200*61c4878aSAndroid Build Coastguard Worker  };
201*61c4878aSAndroid Build Coastguard Worker  Action action = 4;
202*61c4878aSAndroid Build Coastguard Worker
203*61c4878aSAndroid Build Coastguard Worker  // Condition 4: (thread_equals.size() == 0 || log.thread == thread_equals).
204*61c4878aSAndroid Build Coastguard Worker  bytes thread_equals = 5 [(tokenizer.format) = TOKENIZATION_OPTIONAL];
205*61c4878aSAndroid Build Coastguard Worker}
206*61c4878aSAndroid Build Coastguard Worker
207*61c4878aSAndroid Build Coastguard Worker// A filter is a series of rules. First matching rule wins.
208*61c4878aSAndroid Build Coastguard Workermessage Filter {
209*61c4878aSAndroid Build Coastguard Worker  repeated FilterRule rule = 1;
210*61c4878aSAndroid Build Coastguard Worker}
211*61c4878aSAndroid Build Coastguard Worker
212*61c4878aSAndroid Build Coastguard Workermessage SetFilterRequest {
213*61c4878aSAndroid Build Coastguard Worker  // A filter can be identified by a human readable string, token, or number.
214*61c4878aSAndroid Build Coastguard Worker  bytes filter_id = 1 [(tokenizer.format) = TOKENIZATION_OPTIONAL];
215*61c4878aSAndroid Build Coastguard Worker
216*61c4878aSAndroid Build Coastguard Worker  Filter filter = 2;
217*61c4878aSAndroid Build Coastguard Worker}
218*61c4878aSAndroid Build Coastguard Worker
219*61c4878aSAndroid Build Coastguard Workermessage GetFilterRequest {
220*61c4878aSAndroid Build Coastguard Worker  bytes filter_id = 1 [(tokenizer.format) = TOKENIZATION_OPTIONAL];
221*61c4878aSAndroid Build Coastguard Worker}
222*61c4878aSAndroid Build Coastguard Worker
223*61c4878aSAndroid Build Coastguard Workermessage FilterIdListRequest {}
224*61c4878aSAndroid Build Coastguard Worker
225*61c4878aSAndroid Build Coastguard Workermessage FilterIdListResponse {
226*61c4878aSAndroid Build Coastguard Worker  repeated bytes filter_id = 1 [(tokenizer.format) = TOKENIZATION_OPTIONAL];
227*61c4878aSAndroid Build Coastguard Worker}
228*61c4878aSAndroid Build Coastguard Worker
229*61c4878aSAndroid Build Coastguard Worker// RPC service for retrieving and modifying log filters.
230*61c4878aSAndroid Build Coastguard Workerservice Filters {
231*61c4878aSAndroid Build Coastguard Worker  rpc SetFilter(SetFilterRequest) returns (pw.protobuf.Empty);
232*61c4878aSAndroid Build Coastguard Worker  rpc GetFilter(GetFilterRequest) returns (Filter);
233*61c4878aSAndroid Build Coastguard Worker  rpc ListFilterIds(FilterIdListRequest) returns (FilterIdListResponse);
234*61c4878aSAndroid Build Coastguard Worker}
235