e23ca1666cdf1f0b95c9280537826c723218316e
[platform/upstream/connectedhomeip.git] / third_party / pigweed / repo / pw_log_rpc / log_queue.cc
1 // Copyright 2020 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
15 #include "pw_log_rpc/log_queue.h"
16
17 #include "pw_log/levels.h"
18 #include "pw_log_rpc_proto/log.pwpb.h"
19 #include "pw_protobuf/wire_format.h"
20 #include "pw_status/try.h"
21
22 namespace pw::log_rpc {
23 namespace {
24
25 using pw::protobuf::WireType;
26 constexpr std::byte kLogKey = static_cast<std::byte>(pw::protobuf::MakeKey(
27     static_cast<uint32_t>(pw::log_rpc::Log::Fields::ENTRIES),
28     WireType::kDelimited));
29
30 }  // namespace
31
32 Status LogQueue::PushTokenizedMessage(ConstByteSpan message,
33                                       uint32_t flags,
34                                       uint32_t level,
35                                       uint32_t line,
36                                       uint32_t thread,
37                                       int64_t timestamp) {
38   pw::protobuf::NestedEncoder nested_encoder(encode_buffer_);
39   LogEntry::Encoder encoder(&nested_encoder);
40   Status status;
41
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);
48
49   // TODO(prashanthsw): Add support for delta encoding of the timestamp.
50   encoder.WriteTimestamp(timestamp);
51
52   if (dropped_entries_ > 0) {
53     encoder.WriteDropped(dropped_entries_);
54   }
55
56   ConstByteSpan log_entry;
57   status = nested_encoder.Encode(&log_entry);
58   if (!status.ok()) {
59     // When encoding failures occur, map the error to INTERNAL, as the
60     // underlying allocation of this encode buffer and the nested encoding
61     // sequencing are not the caller's responsibility.
62     status = PW_STATUS_INTERNAL;
63   } else {
64     // Try to push back the encoded log entry.
65     status = ring_buffer_.TryPushBack(log_entry, std::byte(kLogKey));
66   }
67
68   if (!status.ok()) {
69     // The ring buffer may hit the RESOURCE_EXHAUSTED state, causing us
70     // to drop packets. However, this check captures all failures from
71     // Encode and TryPushBack, as any failure here causes packet drop.
72     dropped_entries_++;
73     latest_dropped_timestamp_ = timestamp;
74     return status;
75   }
76
77   dropped_entries_ = 0;
78   return Status::Ok();
79 }
80
81 Result<ConstByteSpan> LogQueue::Pop(ByteSpan entry_buffer) {
82   size_t ring_buffer_entry_size = 0;
83   PW_TRY(ring_buffer_.PeekFrontWithPreamble(entry_buffer,
84                                             &ring_buffer_entry_size));
85   PW_DCHECK_OK(ring_buffer_.PopFront());
86   return ConstByteSpan(entry_buffer.first(ring_buffer_entry_size));
87 }
88
89 Result<ConstByteSpan> LogQueue::PopMultiple(ByteSpan entries_buffer) {
90   size_t offset = 0;
91   while (ring_buffer_.EntryCount() > 0 &&
92          (entries_buffer.size_bytes() - offset) >
93              ring_buffer_.FrontEntryTotalSizeBytes()) {
94     const Result<ConstByteSpan> result = Pop(entries_buffer.subspan(offset));
95     if (!result.ok()) {
96       break;
97     }
98     offset += result.value().size_bytes();
99   }
100   return ConstByteSpan(entries_buffer.first(offset));
101 }
102
103 }  // namespace pw::log_rpc