9#include <reloco/ring_buffer.hpp>
23class ring_buffer_log_sink;
30 static void log(value_ref<context_type> ctx,
const log_msg &msg)
noexcept;
40 reloco::detail::unowned_ring_base<char> &ring RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS) noexcept
46 RELOCO_BEGIN_UNSAFE_CODE
49 const std::size_t name_len = std::min<std::size_t>(msg.logger_name.size(), 64);
50 const std::size_t payload_len =
51 std::min<std::size_t>(msg.payload.size(),
static_cast<size_t>(std::numeric_limits<uint16_t>::max()));
55 static_cast<uint8_t
>(msg.lvl)};
62 const auto spans = array{reloco::span<const char>(msg.logger_name.data(), name_len),
63 reloco::span<const char>(msg.payload.data(), payload_len)};
66 std::ignore = ring_->try_write_frame_evicting(hdr, spans, validator);
71 reloco::detail::unowned_ring_base<char> *ring_{};
86 [[nodiscard]]
constexpr std::size_t
size() const noexcept {
return first.size() + second.size(); }
93 reloco::detail::unowned_ring_base<char> *ring_{
nullptr};
94 level lvl_{level::trace};
97 std::size_t total_bytes_{0};
101 log_record_tx(reloco::detail::unowned_ring_base<char> *ring RELOCO_LIFETIMEBOUND,
level lvl,
split_string_view name,
102 split_string_view payload, std::size_t total_bytes)
noexcept RELOCO_RETURN_TYPESTATE(unconsumed)
103 : ring_(ring), lvl_(lvl), logger_name_(name), payload_(payload), total_bytes_(total_bytes) {}
107 constexpr log_record_tx()
noexcept RELOCO_RETURN_TYPESTATE(consumed) =
default;
109 log_record_tx(
const log_record_tx &) =
delete;
110 log_record_tx &operator=(
const log_record_tx &) =
delete;
112 log_record_tx(log_record_tx &&other)
noexcept RELOCO_RETURN_TYPESTATE(unconsumed)
113 : ring_(other.ring_), lvl_(other.lvl_), logger_name_(other.logger_name_), payload_(other.payload_),
114 total_bytes_(other.total_bytes_) {
115 other.ring_ =
nullptr;
118 ~log_record_tx() =
default;
120 [[nodiscard]]
constexpr explicit operator bool()
const noexcept RELOCO_TEST_TYPESTATE(unconsumed) {
121 return ring_ !=
nullptr;
124 [[nodiscard]]
constexpr bool is_known()
const noexcept RELOCO_TEST_TYPESTATE(unconsumed) {
return ring_ !=
nullptr; }
126 [[nodiscard]]
level get_level()
const noexcept RELOCO_CALLABLE_WHEN(unconsumed) {
return lvl_; }
127 [[nodiscard]]
split_string_view logger_name()
const noexcept RELOCO_CALLABLE_WHEN(unconsumed) {
return logger_name_; }
128 [[nodiscard]]
split_string_view payload()
const noexcept RELOCO_CALLABLE_WHEN(unconsumed) {
return payload_; }
133 void commit()
noexcept RELOCO_SET_TYPESTATE(consumed) {
134 if (ring_ !=
nullptr) {
135 ring_->consume(total_bytes_);
143 void rollback()
noexcept RELOCO_SET_TYPESTATE(consumed) { ring_ =
nullptr; }
145 [[nodiscard]] log_record_tx &as_known() &
noexcept RELOCO_SET_TYPESTATE(unconsumed) {
146 RELOCO_ASSERT(ring_,
"Record consumed");
150 [[nodiscard]]
const log_record_tx &as_known()
const &
noexcept RELOCO_SET_TYPESTATE(unconsumed) {
151 RELOCO_ASSERT(ring_,
"Record consumed");
155 [[nodiscard]] log_record_tx &&as_known() &&
noexcept RELOCO_SET_TYPESTATE(unconsumed) {
156 RELOCO_ASSERT(ring_,
"Record consumed");
157 return std::move(*
this);
170 reloco::detail::unowned_ring_base<char> &ring RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS) noexcept
177 [[nodiscard]] reloco::optional<log_record_tx>
try_read() &
noexcept {
180 if (ring_->size() < header_elems) {
189 const std::size_t total_bytes = header_elems + hdr_opt->
logger_name_len + hdr_opt->payload_len;
192 if (total_bytes > ring_->capacity() || hdr_opt->logger_name_len > 64) {
198 if (ring_->size() < total_bytes) {
203 auto [p1, p2] = ring_->read_slices(total_bytes);
205 RELOCO_BEGIN_UNSAFE_BUFFER_USAGE;
208 const auto slice_spans = [p1, p2](std::size_t offset, std::size_t len) {
209 const std::size_t p1_avail = (offset < p1.size()) ? p1.size() - offset : 0;
210 const std::size_t out1_len = std::min(len, p1_avail);
212 const std::size_t out2_len = len - out1_len;
213 const std::size_t s2_offset = (offset > p1.size()) ? offset - p1.size() : 0;
216 reloco::span<const char>(p2.data() + s2_offset, out2_len)};
219 RELOCO_END_UNSAFE_BUFFER_USAGE;
221 return log_record_tx(ring_,
static_cast<level>(hdr_opt->lvl), slice_spans(header_elems, hdr_opt->logger_name_len),
222 slice_spans(header_elems + hdr_opt->logger_name_len, hdr_opt->payload_len), total_bytes);
228 [[nodiscard]] reloco::optional<log_record_tx>
next_impl() noexcept {
return try_read(); }
231 reloco::detail::unowned_ring_base<char> *ring_{};
240 if (!val.first.empty()) {
241 out.write(microfmt::string_view(val.first.data(), val.first.size()));
243 if (!val.second.empty()) {
244 out.write(microfmt::string_view(val.second.data(), val.second.size()));
Definition microfmt.hpp:881
Type-erased, two-word handle to a log sink backend, plus the severity threshold below which records a...
Definition sink.hpp:73
Pull-based reader for extracting structured logs via RAII transactions. Natively supports the reloco/...
Definition ring_buffer_sink_protocol_sink.hpp:165
reloco::optional< log_record_tx > try_read() &noexcept
Attempts to extract the next log frame.
Definition ring_buffer_sink_protocol_sink.hpp:177
constexpr ring_buffer_log_reader(reloco::detail::unowned_ring_base< char > &ring RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS) noexcept
Definition ring_buffer_sink_protocol_sink.hpp:169
log_record_tx item_type
Definition ring_buffer_sink_protocol_sink.hpp:167
reloco::optional< log_record_tx > next_impl() noexcept
The magic hook that fuels the reloco::iterator_adaptor pipeline!
Definition ring_buffer_sink_protocol_sink.hpp:228
A log sink that serializes structured logs into a byte-oriented ring_buffer. Uses try_write_frame_evi...
Definition ring_buffer_sink_protocol_sink.hpp:37
constexpr ring_buffer_log_sink(reloco::detail::unowned_ring_base< char > &ring RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS) noexcept
Definition ring_buffer_sink_protocol_sink.hpp:39
log_sink as_sink() noexcept RELOCO_LIFETIMEBOUND
Definition ring_buffer_sink_protocol_sink.hpp:43
RELOCO_BEGIN_UNSAFE_CODE void log_impl(const log_msg &msg) const noexcept
Definition ring_buffer_sink_protocol_sink.hpp:47
Definition default_log_sink.template.hpp:51
class RELOCO_POINTER RELOCO_CONSUMABLE(unconsumed) log_record_tx
RAII Transaction holding an unconsumed log record.
Definition ring_buffer_sink_protocol_sink.hpp:92
level
Shared log severity levels in ascending order.
Definition log_msg.hpp:22
reloco::sink sink
Type-erased, zero-allocation output sink.
Definition microfmt.hpp:46
RELOCO_END_UNSAFE_CODE
Definition remote_object.hpp:132
Type-erased structured logging sinks and console output.
Structured log record forwarded by a logger to each sink.
Definition log_msg.hpp:69
Static customization point describing a log sink backend.
Definition sink.hpp:46
Definition ring_buffer_sink_protocol_sink.hpp:25
Represents string data that may cross the circular array boundary.
Definition ring_buffer_sink_protocol_sink.hpp:82
reloco::span< const char > second
Definition ring_buffer_sink_protocol_sink.hpp:84
constexpr std::size_t size() const noexcept
Definition ring_buffer_sink_protocol_sink.hpp:86
reloco::span< const char > first
Definition ring_buffer_sink_protocol_sink.hpp:83