Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion toolbox/sys/Log.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@ class Log {
, level_{level}
, os_{log_stream()}
{
os_.set_storage(os_.make_storage());
LogMsgPtr storage;
if (!log_buf_pool().pop(storage)) [[unlikely]] {
storage = LogStream::make_storage();
}
os_.set_storage(std::move(storage));
}
~Log()
{
Expand Down
3 changes: 3 additions & 0 deletions toolbox/sys/Log.ut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ struct TestLogger final : Logger {
void do_write_log(WallTime /*ts*/, LogLevel level, int /*tid*/, LogMsgPtr&& msg,
size_t size) noexcept override
{
const auto finally = make_finally([&]() noexcept {
log_buf_pool().bounded_push(std::move(msg));
});
last_level = level;
last_msg.assign(static_cast<const char*>(msg.get()), size);
}
Expand Down
32 changes: 30 additions & 2 deletions toolbox/sys/Logger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

#include "Logger.hpp"

#include <toolbox/util/Finally.hpp>

#include <atomic>
#include <mutex>

Expand Down Expand Up @@ -61,17 +63,34 @@ inline pid_t gettid()
}
#endif

struct LogBufPoolWrapper {
static constexpr std::size_t InitialPoolSize = 8;
LogBufPoolWrapper()
{
for ([[maybe_unused]] std::size_t i = 0; i < InitialPoolSize; i++) {
pool.bounded_push(util::make_storage<MaxLogLine>());
}
}
LogBufPool pool;
};
static LogBufPoolWrapper log_buf_pool_{};

class NullLogger final : public Logger {
void do_write_log(WallTime /*ts*/, LogLevel /*level*/, int /*tid*/, LogMsgPtr&& /*msg*/,
void do_write_log(WallTime /*ts*/, LogLevel /*level*/, int /*tid*/, LogMsgPtr&& msg,
size_t /*size*/) noexcept override
{
log_buf_pool().bounded_push(std::move(msg));
}
} null_logger_;

class StdLogger final : public Logger {
void do_write_log(WallTime ts, LogLevel level, int tid, LogMsgPtr&& msg,
size_t size) noexcept override
{
const auto finally = make_finally([&]() noexcept {
log_buf_pool().bounded_push(std::move(msg));
});

const auto t{WallClock::to_time_t(ts)};
tm tm;
localtime_r(&t, &tm);
Expand Down Expand Up @@ -107,6 +126,10 @@ class SysLogger final : public Logger {
void do_write_log(WallTime /*ts*/, LogLevel level, int /*tid*/, LogMsgPtr&& msg,
size_t size) noexcept override
{
const auto finally = make_finally([&]() noexcept {
log_buf_pool().bounded_push(std::move(msg));
});

int prio;
switch (level) {
case LogLevel::None:
Expand Down Expand Up @@ -152,6 +175,11 @@ inline Logger& acquire_logger() noexcept

} // namespace

LogBufPool& log_buf_pool() noexcept
{
return log_buf_pool_.pool;
}

Logger& null_logger() noexcept
{
return null_logger_;
Expand Down Expand Up @@ -244,7 +272,7 @@ void AsyncLogger::do_write_log(WallTime ts, LogLevel level, int tid, LogMsgPtr&&
// and prevents crashes caused by an out-of-memory situation during rare log-burst spikes.
}
// Failed to push the task, restore ownership of msg_ptr.
LogMsgPtr{msg_ptr};
log_buf_pool().bounded_push(LogMsgPtr{msg_ptr});
}

} // namespace sys
Expand Down
13 changes: 10 additions & 3 deletions toolbox/sys/Logger.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,16 @@
#ifndef TOOLBOX_SYS_LOGGER_HPP
#define TOOLBOX_SYS_LOGGER_HPP

#include <boost/lockfree/queue.hpp>
#include <thread>

#include <toolbox/sys/Limits.hpp>
#include <toolbox/sys/Time.hpp>
#include <toolbox/util/Storage.hpp>
#include <toolbox/util/Concepts.hpp>

#include <boost/lockfree/queue.hpp>
#include <boost/lockfree/stack.hpp>

#include <thread>

namespace toolbox {
inline namespace sys {

Expand All @@ -50,6 +52,11 @@ enum class LogLevel : int {
};

using LogMsgPtr = StoragePtr<MaxLogLine>;
inline constexpr std::size_t LogBufPoolCapacity = 64;
using LogBufPool = boost::lockfree::stack<LogMsgPtr, boost::lockfree::capacity<LogBufPoolCapacity>>;

/// A pool of log buffers, eliminating the need for dynamic memory allocations when logging
TOOLBOX_API LogBufPool& log_buf_pool() noexcept;

/// Null logger. This logger does nothing and is effectively /dev/null.
TOOLBOX_API Logger& null_logger() noexcept;
Expand Down