blob: 4c35893cf6d5bce418ef85d913cd6678c6928718 [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_rpc_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 {
class LogQueue {
public:
LogQueue(ByteSpan log_buffer, ByteSpan encode_buffer)
: 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.
pw::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.
pw::Result<ConstByteSpan> Pop(ByteSpan 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.
//
// OK - success.
pw::Result<ConstByteSpan> PopMultiple(ByteSpan entries_buffer);
private:
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