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