| // Copyright 2020 The Pigweed Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| // use this file except in compliance with the License. You may obtain a copy of |
| // the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| // License for the specific language governing permissions and limitations under |
| // the License. |
| |
| #pragma once |
| |
| #include "pw_bytes/span.h" |
| #include "pw_result/result.h" |
| #include "pw_ring_buffer/prefixed_entry_ring_buffer.h" |
| #include "pw_status/status.h" |
| #include "pw_status/status_with_size.h" |
| |
| // LogQueue is a ring-buffer queue of log messages. LogQueue is backed by |
| // a caller-provided byte array and stores its messages in the format |
| // dictated by the pw_log log.proto format. |
| // |
| // Logs can be returned as a repeated proto message and the output of this |
| // class can be directly fed into an RPC stream. |
| // |
| // Push logs: |
| // 0) Create LogQueue instance. |
| // 1) LogQueue::PushTokenizedMessage(). |
| // |
| // Pop logs: |
| // 0) Use exsiting LogQueue instance. |
| // 1) For single entires, LogQueue::Pop(). |
| // 2) For multiple entries, LogQueue::PopMultiple(). |
| namespace pw::log_rpc { |
| namespace { |
| constexpr size_t kLogEntryMaxSize = 100; |
| } // namespace |
| |
| using LogEntriesBuffer = ByteSpan; |
| |
| struct LogEntries { |
| // A buffer containing an encoded protobuf of type pw.log.LogEntries. |
| ConstByteSpan entries; |
| size_t entry_count; |
| }; |
| |
| class LogQueue { |
| public: |
| // Constructs a LogQueue. Callers can optionally supply a maximum log entry |
| // size, which limits the size of messages that can be pushed into this log |
| // queue. When such an entry arrives, the queue increments its drop counter. |
| // Calls to Pop and PopMultiple should be provided a buffer of at least the |
| // configured max size. |
| LogQueue(ByteSpan log_buffer, |
| ByteSpan encode_buffer, |
| size_t max_log_entry_size = kLogEntryMaxSize) |
| : pop_status_for_test_(OkStatus()), |
| max_log_entry_size_(max_log_entry_size), |
| encode_buffer_(encode_buffer), |
| ring_buffer_(true) { |
| ring_buffer_.SetBuffer(log_buffer); |
| } |
| |
| LogQueue(const LogQueue&) = delete; |
| LogQueue& operator=(const LogQueue&) = delete; |
| LogQueue(LogQueue&&) = delete; |
| LogQueue& operator=(LogQueue&&) = delete; |
| |
| // Construct a LogEntry proto message and push it into the ring buffer. |
| // Returns: |
| // |
| // OK - success. |
| // FAILED_PRECONDITION - Failed when encoding the proto message. |
| // RESOURCE_EXHAUSTED - Not enough space in the buffer to write the entry. |
| Status PushTokenizedMessage(ConstByteSpan message, |
| uint32_t flags, |
| uint32_t level, |
| uint32_t line, |
| uint32_t thread, |
| int64_t timestamp); |
| |
| // Pop the oldest LogEntry from the queue into the provided buffer. |
| // On success, the size is the length of the entry, on failure, the size is 0. |
| // Returns: |
| // |
| // For now, don't support batching. This will always use a single absolute |
| // timestamp, and not use delta encoding. |
| // |
| // OK - success. |
| // OUT_OF_RANGE - No entries in queue to read. |
| // RESOURCE_EXHAUSTED - Destination data std::span was smaller number of |
| // bytes than the data size of the data chunk being read. Available |
| // destination bytes were filled, remaining bytes of the data chunk were |
| // ignored. |
| Result<LogEntries> Pop(LogEntriesBuffer entry_buffer); |
| |
| // Pop entries from the queue into the provided buffer. The provided buffer is |
| // filled until there is insufficient space for the next log entry. |
| // Returns: |
| // |
| // LogEntries - contains an encoded protobuf byte span of pw.log.LogEntries. |
| LogEntries PopMultiple(LogEntriesBuffer entries_buffer); |
| |
| protected: |
| friend class LogQueueTester; |
| // For testing, status to return on calls to Pop. |
| Status pop_status_for_test_; |
| |
| private: |
| const size_t max_log_entry_size_; |
| size_t dropped_entries_; |
| int64_t latest_dropped_timestamp_; |
| |
| ByteSpan encode_buffer_; |
| pw::ring_buffer::PrefixedEntryRingBuffer ring_buffer_{true}; |
| }; |
| |
| // LogQueueWithEncodeBuffer is a LogQueue where the internal encode buffer is |
| // created and managed by this class. |
| template <size_t kEncodeBufferSize> |
| class LogQueueWithEncodeBuffer : public LogQueue { |
| public: |
| LogQueueWithEncodeBuffer(ByteSpan log_buffer) |
| : LogQueue(log_buffer, encode_buffer_) {} |
| |
| private: |
| std::byte encode_buffer_[kEncodeBufferSize]; |
| }; |
| |
| } // namespace pw::log_rpc |