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