1 // Copyright 2020 The Pigweed Authors
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
7 // https://www.apache.org/licenses/LICENSE-2.0
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
15 #include "pw_log_multisink/log_queue.h"
17 #include "pw_log/levels.h"
18 #include "pw_log_proto/log.pwpb.h"
19 #include "pw_protobuf/wire_format.h"
20 #include "pw_status/try.h"
22 namespace pw::log_rpc {
25 using pw::protobuf::WireType;
26 constexpr std::byte kLogKey = static_cast<std::byte>(pw::protobuf::MakeKey(
27 static_cast<uint32_t>(pw::log::LogEntries::Fields::ENTRIES),
28 WireType::kDelimited));
32 Status LogQueue::PushTokenizedMessage(ConstByteSpan message,
38 pw::protobuf::NestedEncoder nested_encoder(encode_buffer_);
39 pw::log::LogEntry::Encoder encoder(&nested_encoder);
42 encoder.WriteMessageTokenized(message);
43 encoder.WriteLineLevel(
44 (level & PW_LOG_LEVEL_BITMASK) |
45 ((line << PW_LOG_LEVEL_BITWIDTH) & ~PW_LOG_LEVEL_BITMASK));
46 encoder.WriteFlags(flags);
47 encoder.WriteThreadTokenized(thread);
49 // TODO(prashanthsw): Add support for delta encoding of the timestamp.
50 encoder.WriteTimestamp(timestamp);
52 if (dropped_entries_ > 0) {
53 encoder.WriteDropped(dropped_entries_);
56 ConstByteSpan log_entry;
57 status = nested_encoder.Encode(&log_entry);
58 if (!status.ok() || log_entry.size_bytes() > max_log_entry_size_) {
59 // If an encoding failure occurs or the constructed log entry is larger
60 // than the configured max size, map the error to INTERNAL. If the
61 // underlying allocation of this encode buffer or the nested encoding
62 // sequencing are at fault, they are not the caller's responsibility. If
63 // the log entry is larger than the max allowed size, the log is dropped
64 // intentionally, and it is expected that the caller accepts this
66 status = PW_STATUS_INTERNAL;
68 // Try to push back the encoded log entry.
69 status = ring_buffer_.TryPushBack(log_entry, std::byte(kLogKey));
73 // The ring buffer may hit the RESOURCE_EXHAUSTED state, causing us
74 // to drop packets. However, this check captures all failures from
75 // Encode and TryPushBack, as any failure here causes packet drop.
77 latest_dropped_timestamp_ = timestamp;
85 Result<LogEntries> LogQueue::Pop(LogEntriesBuffer entry_buffer) {
86 size_t ring_buffer_entry_size = 0;
87 PW_TRY(pop_status_for_test_);
88 // The caller must provide a buffer that is at minimum max_log_entry_size, to
89 // ensure that the front entry of the ring buffer can be popped.
90 PW_DCHECK_UINT_GE(entry_buffer.size_bytes(), max_log_entry_size_);
91 PW_TRY(ring_buffer_.PeekFrontWithPreamble(entry_buffer,
92 &ring_buffer_entry_size));
93 PW_DCHECK_OK(ring_buffer_.PopFront());
96 .entries = ConstByteSpan(entry_buffer.first(ring_buffer_entry_size)),
100 LogEntries LogQueue::PopMultiple(LogEntriesBuffer entries_buffer) {
102 size_t entry_count = 0;
104 // The caller must provide a buffer that is at minimum max_log_entry_size, to
105 // ensure that the front entry of the ring buffer can be popped.
106 PW_DCHECK_UINT_GE(entries_buffer.size_bytes(), max_log_entry_size_);
108 while (ring_buffer_.EntryCount() > 0 &&
109 (entries_buffer.size_bytes() - offset) > max_log_entry_size_) {
110 const Result<LogEntries> result = Pop(entries_buffer.subspan(offset));
114 offset += result.value().entries.size_bytes();
115 entry_count += result.value().entry_count;
118 return LogEntries{.entries = ConstByteSpan(entries_buffer.first(offset)),
119 .entry_count = entry_count};
122 } // namespace pw::log_rpc