blob: f358abb0d0c28a2e243565ae96cd67fad664fc23 [file] [log] [blame]
// 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