• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #pragma once
16 
17 #include "pw_bytes/span.h"
18 #include "pw_result/result.h"
19 #include "pw_ring_buffer/prefixed_entry_ring_buffer.h"
20 #include "pw_status/status.h"
21 #include "pw_status/status_with_size.h"
22 
23 // LogQueue is a ring-buffer queue of log messages. LogQueue is backed by
24 // a caller-provided byte array and stores its messages in the format
25 // dictated by the pw_log log.proto format.
26 //
27 // Logs can be returned as a repeated proto message and the output of this
28 // class can be directly fed into an RPC stream.
29 //
30 // Push logs:
31 // 0) Create LogQueue instance.
32 // 1) LogQueue::PushTokenizedMessage().
33 //
34 // Pop logs:
35 // 0) Use exsiting LogQueue instance.
36 // 1) For single entires, LogQueue::Pop().
37 // 2) For multiple entries, LogQueue::PopMultiple().
38 namespace pw::log_rpc {
39 namespace {
40 constexpr size_t kLogEntryMaxSize = 100;
41 }  // namespace
42 
43 using LogEntriesBuffer = ByteSpan;
44 
45 struct LogEntries {
46   // A buffer containing an encoded protobuf of type pw.log.LogEntries.
47   ConstByteSpan entries;
48   size_t entry_count;
49 };
50 
51 class LogQueue {
52  public:
53   // Constructs a LogQueue. Callers can optionally supply a maximum log entry
54   // size, which limits the size of messages that can be pushed into this log
55   // queue. When such an entry arrives, the queue increments its drop counter.
56   // Calls to Pop and PopMultiple should be provided a buffer of at least the
57   // configured max size.
58   LogQueue(ByteSpan log_buffer,
59            ByteSpan encode_buffer,
60            size_t max_log_entry_size = kLogEntryMaxSize)
pop_status_for_test_(OkStatus ())61       : pop_status_for_test_(OkStatus()),
62         max_log_entry_size_(max_log_entry_size),
63         encode_buffer_(encode_buffer),
64         ring_buffer_(true) {
65     ring_buffer_.SetBuffer(log_buffer);
66   }
67 
68   LogQueue(const LogQueue&) = delete;
69   LogQueue& operator=(const LogQueue&) = delete;
70   LogQueue(LogQueue&&) = delete;
71   LogQueue& operator=(LogQueue&&) = delete;
72 
73   // Construct a LogEntry proto message and push it into the ring buffer.
74   // Returns:
75   //
76   //  OK - success.
77   //  FAILED_PRECONDITION - Failed when encoding the proto message.
78   //  RESOURCE_EXHAUSTED - Not enough space in the buffer to write the entry.
79   Status PushTokenizedMessage(ConstByteSpan message,
80                               uint32_t flags,
81                               uint32_t level,
82                               uint32_t line,
83                               uint32_t thread,
84                               int64_t timestamp);
85 
86   // Pop the oldest LogEntry from the queue into the provided buffer.
87   // On success, the size is the length of the entry, on failure, the size is 0.
88   // Returns:
89   //
90   // For now, don't support batching. This will always use a single absolute
91   // timestamp, and not use delta encoding.
92   //
93   //  OK - success.
94   //  OUT_OF_RANGE - No entries in queue to read.
95   //  RESOURCE_EXHAUSTED - Destination data std::span was smaller number of
96   //  bytes than the data size of the data chunk being read.  Available
97   //  destination bytes were filled, remaining bytes of the data chunk were
98   //  ignored.
99   Result<LogEntries> Pop(LogEntriesBuffer entry_buffer);
100 
101   // Pop entries from the queue into the provided buffer. The provided buffer is
102   // filled until there is insufficient space for the next log entry.
103   // Returns:
104   //
105   // LogEntries - contains an encoded protobuf byte span of pw.log.LogEntries.
106   LogEntries PopMultiple(LogEntriesBuffer entries_buffer);
107 
108  protected:
109   friend class LogQueueTester;
110   // For testing, status to return on calls to Pop.
111   Status pop_status_for_test_;
112 
113  private:
114   const size_t max_log_entry_size_;
115   size_t dropped_entries_;
116   int64_t latest_dropped_timestamp_;
117 
118   ByteSpan encode_buffer_;
119   pw::ring_buffer::PrefixedEntryRingBuffer ring_buffer_{true};
120 };
121 
122 // LogQueueWithEncodeBuffer is a LogQueue where the internal encode buffer is
123 // created and managed by this class.
124 template <size_t kEncodeBufferSize>
125 class LogQueueWithEncodeBuffer : public LogQueue {
126  public:
LogQueueWithEncodeBuffer(ByteSpan log_buffer)127   LogQueueWithEncodeBuffer(ByteSpan log_buffer)
128       : LogQueue(log_buffer, encode_buffer_) {}
129 
130  private:
131   std::byte encode_buffer_[kEncodeBufferSize];
132 };
133 
134 }  // namespace pw::log_rpc
135