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