xref: /aosp_15_r20/external/pigweed/pw_log/public/pw_log/proto_utils.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2021 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15 
16 #include <string_view>
17 
18 #include "pw_bytes/span.h"
19 #include "pw_log/levels.h"
20 #include "pw_log/proto/log.pwpb.h"
21 #include "pw_log_tokenized/metadata.h"
22 #include "pw_result/result.h"
23 #include "pw_status/try.h"
24 
25 namespace pw::log {
26 
27 // Packs line number and log level into a single uint32_t as dictated by the
28 // line_level field in the Log proto message.
29 //
30 // Note:
31 //   line_number is restricted to 29 bits. Values beyond 536870911 will be lost.
32 //   level is restricted to 3 bits. Values beyond 7 will be lost.
PackLineLevel(uint32_t line_number,uint8_t level)33 constexpr inline uint32_t PackLineLevel(uint32_t line_number, uint8_t level) {
34   return (level & PW_LOG_LEVEL_BITMASK) |
35          ((line_number << PW_LOG_LEVEL_BITS) & ~PW_LOG_LEVEL_BITMASK);
36 }
37 
38 // Unpacks the line_level field as dictated by the Log proto message into line
39 // number (uint32_t) and level (uint8_t).
UnpackLineLevel(uint32_t line_and_level)40 constexpr inline std::tuple<uint32_t, uint8_t> UnpackLineLevel(
41     uint32_t line_and_level) {
42   return std::make_tuple(
43       (line_and_level & ~PW_LOG_LEVEL_BITMASK) >> PW_LOG_LEVEL_BITS,
44       line_and_level & PW_LOG_LEVEL_BITMASK);
45 }
46 
47 // Convenience functions to encode multiple log attributes as a log proto
48 // message.
49 //
50 // Returns:
51 // OK - A byte span containing the encoded log proto.
52 // INVALID_ARGUMENT - `message` argument is zero-length.
53 // RESOURCE_EXHAUSTED - The provided buffer was not large enough to encode the
54 //   proto.
55 Result<ConstByteSpan> EncodeLog(int level,
56                                 unsigned int flags,
57                                 std::string_view module_name,
58                                 std::string_view thread_name,
59                                 std::string_view file_name,
60                                 int line_number,
61                                 int64_t ticks_since_epoch,
62                                 std::string_view message,
63                                 ByteSpan encode_buffer);
64 
65 // Encodes tokenized message and metadata, with a timestamp as a log proto.
66 // Extra fields can be encoded into the returned encoder. The caller must check
67 // the encoder status.
68 pwpb::LogEntry::MemoryEncoder CreateEncoderAndEncodeTokenizedLog(
69     log_tokenized::Metadata metadata,
70     ConstByteSpan tokenized_data,
71     int64_t ticks_since_epoch,
72     ByteSpan encode_buffer);
73 
74 // Convenience functions to convert from tokenized metadata to the log proto
75 // format.
76 //
77 // Returns:
78 // OK - A byte span containing the encoded log proto.
79 // RESOURCE_EXHAUSTED - The provided buffer was not large enough to store the
80 //   proto.
EncodeTokenizedLog(log_tokenized::Metadata metadata,ConstByteSpan tokenized_data,int64_t ticks_since_epoch,ByteSpan encode_buffer)81 inline Result<ConstByteSpan> EncodeTokenizedLog(
82     log_tokenized::Metadata metadata,
83     ConstByteSpan tokenized_data,
84     int64_t ticks_since_epoch,
85     ByteSpan encode_buffer) {
86   pwpb::LogEntry::MemoryEncoder encoder = CreateEncoderAndEncodeTokenizedLog(
87       metadata, tokenized_data, ticks_since_epoch, encode_buffer);
88   PW_TRY(encoder.status());
89   return ConstByteSpan(encoder);
90 }
91 
EncodeTokenizedLog(log_tokenized::Metadata metadata,const uint8_t * tokenized_data,size_t tokenized_data_size,int64_t ticks_since_epoch,ByteSpan encode_buffer)92 inline Result<ConstByteSpan> EncodeTokenizedLog(
93     log_tokenized::Metadata metadata,
94     const uint8_t* tokenized_data,
95     size_t tokenized_data_size,
96     int64_t ticks_since_epoch,
97     ByteSpan encode_buffer) {
98   return EncodeTokenizedLog(metadata,
99                             as_bytes(span(tokenized_data, tokenized_data_size)),
100                             ticks_since_epoch,
101                             encode_buffer);
102 }
103 
104 // Encodes tokenized message (passed as pointer and size), tokenized metadata,
105 // timestamp, and thread name as a log proto.
106 //
107 // Returns:
108 // OK - A byte span containing the encoded log proto.
109 // RESOURCE_EXHAUSTED - The provided buffer was not large enough to store the
110 //   proto.
EncodeTokenizedLog(log_tokenized::Metadata metadata,const uint8_t * tokenized_data,size_t tokenized_data_size,int64_t ticks_since_epoch,ConstByteSpan thread_name,ByteSpan encode_buffer)111 inline Result<ConstByteSpan> EncodeTokenizedLog(
112     log_tokenized::Metadata metadata,
113     const uint8_t* tokenized_data,
114     size_t tokenized_data_size,
115     int64_t ticks_since_epoch,
116     ConstByteSpan thread_name,
117     ByteSpan encode_buffer) {
118   pwpb::LogEntry::MemoryEncoder encoder = CreateEncoderAndEncodeTokenizedLog(
119       metadata,
120       as_bytes(span(tokenized_data, tokenized_data_size)),
121       ticks_since_epoch,
122       encode_buffer);
123   if (!thread_name.empty()) {
124     encoder.WriteThread(thread_name).IgnoreError();
125   }
126   PW_TRY(encoder.status());
127   return ConstByteSpan(encoder);
128 }
129 
130 // Encodes tokenized message (passed as a byte span), tokenized metadata,
131 // timestamp, and thread name as a log proto.
132 //
133 // Returns:
134 // OK - A byte span containing the encoded log proto.
135 // RESOURCE_EXHAUSTED - The provided buffer was not large enough to store the
136 //   proto.
EncodeTokenizedLog(log_tokenized::Metadata metadata,ConstByteSpan tokenized_data,int64_t ticks_since_epoch,ConstByteSpan thread_name,ByteSpan encode_buffer)137 inline Result<ConstByteSpan> EncodeTokenizedLog(
138     log_tokenized::Metadata metadata,
139     ConstByteSpan tokenized_data,
140     int64_t ticks_since_epoch,
141     ConstByteSpan thread_name,
142     ByteSpan encode_buffer) {
143   pwpb::LogEntry::MemoryEncoder encoder = CreateEncoderAndEncodeTokenizedLog(
144       metadata, tokenized_data, ticks_since_epoch, encode_buffer);
145   if (!thread_name.empty()) {
146     encoder.WriteThread(thread_name).IgnoreError();
147   }
148   PW_TRY(encoder.status());
149   return ConstByteSpan(encoder);
150 }
151 }  // namespace pw::log
152