2#ifndef LOGIT_CPP_HEADER_LOGIT_CPP_LOGIT_LOGGER_HPP_INCLUDED
3#define LOGIT_CPP_HEADER_LOGIT_CPP_LOGIT_LOGGER_HPP_INCLUDED
19#if __cplusplus >= 201703L
20#include <shared_mutex>
21#define LOGIT_HAS_SHARED_MUTEX 1
23#define LOGIT_HAS_SHARED_MUTEX 0
28#if LOGIT_HAS_SHARED_MUTEX
65 std::unique_ptr<ILogger> logger,
66 std::unique_ptr<ILogFormatter> formatter,
67 bool single_mode =
false) {
68 if (
m_shutdown.load(std::memory_order_acquire))
return;
69 auto strategy = std::make_shared<LoggerStrategy>();
70 strategy->logger = std::move(logger);
71 strategy->formatter = std::move(formatter);
72 strategy->single_mode = single_mode;
73 strategy->enabled =
true;
76 if (
m_shutdown.load(std::memory_order_acquire))
return;
87 if (logger_index >= 0 && logger_index <
static_cast<int>(
m_loggers.size()) &&
m_loggers[logger_index]) {
88 m_loggers[logger_index]->enabled.store(enabled, std::memory_order_relaxed);
97 if (logger_index >= 0 && logger_index <
static_cast<int>(
m_loggers.size()) &&
m_loggers[logger_index]) {
98 return m_loggers[logger_index]->enabled.load(std::memory_order_relaxed);
109 if (logger_index >= 0 && logger_index <
static_cast<int>(
m_loggers.size()) &&
m_loggers[logger_index]) {
110 m_loggers[logger_index]->single_mode.store(single_mode, std::memory_order_relaxed);
120 if (logger_index >= 0 && logger_index <
static_cast<int>(
m_loggers.size()) &&
m_loggers[logger_index]) {
121 std::lock_guard<std::mutex> exec_lock(
m_loggers[logger_index]->exec_mx);
122 m_loggers[logger_index]->formatter->set_timestamp_offset(offset_ms);
132 if (!strategy)
continue;
133 std::lock_guard<std::mutex> exec_lock(strategy->exec_mx);
134 strategy->logger->set_log_level(level);
144 if (logger_index >= 0 && logger_index <
static_cast<int>(
m_loggers.size()) &&
m_loggers[logger_index]) {
145 std::lock_guard<std::mutex> exec_lock(
m_loggers[logger_index]->exec_mx);
146 m_loggers[logger_index]->logger->set_log_level(level);
156 if (logger_index >= 0 && logger_index <
static_cast<int>(
m_loggers.size()) &&
m_loggers[logger_index]) {
157 return m_loggers[logger_index]->single_mode.load(std::memory_order_relaxed);
168 if (
m_shutdown.load(std::memory_order_acquire))
return;
171#ifdef LOGIT_BENCH_LEGACY_REGISTRY
188 const int strategy_index = targeted ? 0 : record.
logger_index;
190 const auto snapshot = std::atomic_load_explicit(
192 const StrategyList* strategies = snapshot ? snapshot.get() :
nullptr;
195 if (!strategies)
return;
198 if (strategy_index < 0 ||
199 strategy_index >=
static_cast<int>(strategies->size()))
return;
200 const auto& strategy = (*strategies)[strategy_index];
201 if (!strategy)
return;
203 std::lock_guard<std::mutex> exec_lock(strategy->exec_mx);
204 if (
m_shutdown.load(std::memory_order_acquire))
return;
205 if (!strategy->enabled.load(std::memory_order_relaxed))
return;
207 static_cast<int>(record.
log_level) <
static_cast<int>(strategy->logger->get_log_level()))
return;
212 for (
const auto& strategy : *strategies) {
213 if (!strategy)
continue;
215 std::lock_guard<std::mutex> exec_lock(strategy->exec_mx);
216 if (
m_shutdown.load(std::memory_order_acquire))
return;
217 if (strategy->single_mode.load(std::memory_order_relaxed))
continue;
218 if (!strategy->enabled.load(std::memory_order_relaxed))
continue;
220 static_cast<int>(record.
log_level) <
static_cast<int>(strategy->logger->get_log_level()))
continue;
233 if (logger_index >= 0 && logger_index <
static_cast<int>(
m_loggers.size()) &&
m_loggers[logger_index]) {
234 const auto& strategy =
m_loggers[logger_index];
235 return strategy->logger->get_string_param(param);
237 return std::string();
247 if (logger_index >= 0 && logger_index <
static_cast<int>(
m_loggers.size()) &&
m_loggers[logger_index]) {
248 const auto& strategy =
m_loggers[logger_index];
249 return strategy->logger->get_int_param(param);
261 if (logger_index >= 0 && logger_index <
static_cast<int>(
m_loggers.size()) &&
m_loggers[logger_index]) {
262 const auto& strategy =
m_loggers[logger_index];
263 return strategy->logger->get_float_param(param);
272 if (
m_shutdown)
return std::vector<std::string>();
276 return std::vector<std::string>();
279 return strategy->logger->get_buffered_strings();
286 if (
m_shutdown)
return std::vector<BufferedLogEntry>();
290 return std::vector<BufferedLogEntry>();
293 return strategy->logger->get_buffered_entries();
300 if (
m_shutdown)
return std::vector<LogFileInfo>();
304 return std::vector<LogFileInfo>();
307 return strategy->logger->list_log_files();
330 return strategy->logger->read_log_file(path);
337 std::vector<LogFileReadResult>
read_log_files(
int logger_index,
const std::vector<std::string>& paths)
const {
339 std::vector<LogFileReadResult> results;
340 results.reserve(paths.size());
341 for (
size_t i = 0; i < paths.size(); ++i) {
345 results.push_back(result);
352 std::vector<LogFileReadResult> results;
353 results.reserve(paths.size());
354 for (
size_t i = 0; i < paths.size(); ++i) {
358 results.push_back(result);
363 return strategy->logger->read_log_files(paths);
377 return strategy->logger->get_log_level();
385 template <
typename... Ts>
387 this->
print(record, args...);
388 return std::forward_as_tuple(std::forward<Ts>(args)...);
398 template <
typename T>
400 this->
print(record, args);
401 return std::forward<decltype(args)>(args);
417 for (
const auto& strategy : snapshot) {
418 if (!strategy)
continue;
419 strategy->logger->wait();
429 if (
m_shutdown.load(std::memory_order_acquire)) {
432 result.
message =
"logger system is shut down";
440 result.
message =
"logger index not found";
444 std::lock_guard<std::mutex> exec_lock(strategy->exec_mx);
445 if (
m_shutdown.load(std::memory_order_acquire)) {
448 result.
message =
"logger system is shut down";
451 return strategy->logger->clear_logs(options);
459 if (
m_shutdown.load(std::memory_order_acquire)) {
462 result.
message =
"logger system is shut down";
467 std::size_t supported = 0;
468 std::size_t failed = 0;
469 std::size_t unsupported = 0;
470 for (
const auto& strategy : snapshot) {
471 if (!strategy)
continue;
472 std::lock_guard<std::mutex> exec_lock(strategy->exec_mx);
473 if (
m_shutdown.load(std::memory_order_acquire)) {
476 result.
message =
"logger system is shut down";
493 result.
ok = supported > 0 && failed == 0;
496 result.
message = unsupported > 0 ?
"cleared supported loggers; skipped unsupported loggers" :
"cleared";
500 result.
message = unsupported > 0 ?
"no logger supports clearing" :
"no loggers to clear";
513 template <
typename LoggerT>
516 return (strategy && strategy->logger)
517 ?
dynamic_cast<LoggerT*
>(strategy->logger.get())
522 template <
typename LoggerT>
525 return (strategy && strategy->logger)
526 ?
dynamic_cast<const LoggerT*
>(strategy->logger.get())
535 if (
m_shutdown.exchange(
true, std::memory_order_acq_rel))
return;
538 for (
const auto& strategy : snapshot) {
539 if (!strategy)
continue;
540 std::lock_guard<std::mutex> exec_lock(strategy->exec_mx);
541 strategy->logger->shutdown();
567 const std::string msg = strategy.
formatter ? strategy.
formatter->format(record) : std::string();
568 strategy.
logger->log(record, msg);
572 const auto snapshot = std::atomic_load_explicit(
574 if (logger_index >= 0 &&
575 snapshot && logger_index <
static_cast<int>(snapshot->size()) &&
576 (*snapshot)[logger_index]) {
577 return (*snapshot)[logger_index];
579 return std::shared_ptr<LoggerStrategy>();
583 const std::shared_ptr<const StrategyList> snapshot(
585 std::atomic_store_explicit(
604# pragma warning(push)
605# pragma warning(disable: 4127)
612 template <
typename... Ts>
614 if (
sizeof...(Ts) == 0) {
629 std::atomic_store_explicit(
631 std::shared_ptr<const StrategyList>(
new StrategyList()),
632 std::memory_order_release);
Defines the interface for loggers used in the logging system.
Task executor used by asynchronous loggers.
Singleton class managing multiple loggers and formatters.
LoggerT * get_logger_as(int logger_index)
Retrieves a typed backend pointer from a logger by index.
auto log_and_return(const LogRecord &record) -> std::tuple<>
Logs message without arguments and returns empty tuple.
auto log_and_return(const LogRecord &record, T &&args) -> decltype(args)
Logs message and returns argument.
LogClearResult clear_logger(int logger_index, const LogClearOptions &options=LogClearOptions())
Clears logger-owned records for a specific logger.
void set_logger_enabled(int logger_index, bool enabled)
Enables or disables a logger by index.
std::vector< std::shared_ptr< LoggerStrategy > > get_all_strategy_snapshots() const
void publish_strategy_snapshot_locked()
void wait()
Waits for all asynchronous loggers to finish processing.
void log(const LogRecord &record)
Logs a LogRecord using added loggers and formatters.
void set_logger_single_mode(int logger_index, bool single_mode)
Sets single-mode flag for a logger.
void set_timestamp_offset(int logger_index, int64_t offset_ms)
Sets timestamp offset for a specific logger.
LoggerMutex m_loggers_mx
Protects access to logger strategies.
std::vector< std::shared_ptr< LoggerStrategy > > m_loggers
Container for logger-formatter pairs.
void add_logger(std::unique_ptr< ILogger > logger, std::unique_ptr< ILogFormatter > formatter, bool single_mode=false)
Adds a logger and its corresponding formatter.
std::vector< LogFileReadResult > read_log_files(int logger_index, const std::vector< std::string > &paths) const
Reads several persisted log files exposed by a logger backend.
Logger & operator=(const Logger &)=delete
Logger(const Logger &)=delete
std::vector< LogFileInfo > list_log_files(int logger_index) const
Lists persisted log files exposed by a logger backend.
void shutdown()
Shuts down logger system.
void set_log_level(int logger_index, LogLevel level)
Sets minimal log level for a specific logger.
LogClearResult clear_all_loggers(const LogClearOptions &options=LogClearOptions())
Clears logger-owned records for all registered loggers.
void set_log_level(LogLevel level)
Sets minimal log level for all loggers.
void print(const LogRecord &record)
bool is_logger_single_mode(int logger_index) const
Checks whether a logger is in single mode.
LogFileReadResult read_log_file(int logger_index, const std::string &path) const
Reads one persisted log file exposed by a logger backend.
std::atomic< bool > m_shutdown
Flag indicating if shutdown was requested.
double get_float_param(int logger_index, const LoggerParam ¶m) const
Retrieves a floating-point parameter from a logger.
std::string get_string_param(int logger_index, const LoggerParam ¶m) const
Retrieves a string parameter from a logger.
auto log_and_return(const LogRecord &record, Ts &&... args) -> decltype(std::forward_as_tuple(std::forward< Ts >(args)...))
Logs message and returns tuple of arguments.
void dispatch_to_strategy(LoggerStrategy &strategy, const LogRecord &record)
int64_t get_int_param(int logger_index, const LoggerParam ¶m) const
Retrieves an integer parameter from a logger.
static void on_exit_handler()
Atexit shutdown handler for Logger and TaskExecutor.
std::shared_ptr< const StrategyList > m_loggers_snapshot
Immutable read-mostly strategy list.
bool is_logger_enabled(int logger_index) const
Checks if a logger is enabled.
LogLevel get_log_level(int logger_index) const
Retrieves the current minimal log level for a logger.
static Logger & get_instance()
Retrieves singleton instance of Logger.
Logger & operator=(Logger &&)=delete
std::size_t logger_count() const
Returns the number of registered logger strategies.
std::vector< BufferedLogEntry > get_buffered_entries(int logger_index) const
Retrieves buffered structured entries from a logger.
std::vector< std::shared_ptr< LoggerStrategy > > StrategyList
std::vector< std::string > get_buffered_strings(int logger_index) const
Retrieves buffered formatted messages from a logger.
const LoggerT * get_logger_as(int logger_index) const
Retrieves a typed backend pointer from a logger by index.
std::shared_ptr< LoggerStrategy > get_strategy_snapshot(int logger_index) const
void print(const LogRecord &record, Ts const &... args)
Logs a record with given arguments.
void shutdown()
Stop the worker thread and drain outstanding tasks.
static TaskExecutor & get_instance()
Returns the global executor instance.
Configuration macros for the LogIt logging system.
The primary namespace for the LogIt++ library.
std::unique_lock< LoggerMutex > LoggerReadLock
std::vector< VariableValue > args_to_array(std::vector< std::string >::const_iterator)
Base case of recursion for argument conversion — when there are no more arguments.
std::vector< std::string > split_arguments(const std::string &all_names)
Splits a string of argument names into individual names, ignoring nested templates,...
@ LOG_LVL_TRACE
Trace level logging.
LoggerParam
Enumeration for different logger parameters that can be retrieved.
std::unique_lock< LoggerMutex > LoggerWriteLock
Selects which data categories a logger cleanup should remove.
Result returned by logger cleanup operations.
std::string message
Optional diagnostic or unsupported reason.
std::size_t cleared_records
Number of primary records/files cleared when available.
LogClearStatus status
Detailed cleanup status.
bool ok
True when the backend completed cleanup.
std::string path
Full path to the file.
Result of reading a persisted log file from a file-based backend.
LogFileInfo file
Metadata for the requested file.
bool ok
Whether the read succeeded.
Stores log metadata and content.
const int logger_index
Logger index (-1 to log to all).
const LogLevel log_level
Log level (severity).
const bool raw_mode
Flag indicating if formatter and level filters should be bypassed.
const std::string format
Format string for the message.
std::vector< VariableValue > args_array
Argument values for the log.
const std::string arg_names
Argument names for the log.
Structure to hold a logger-formatter pair.
std::mutex exec_mx
Protects formatter+logger invocation.
std::atomic< bool > single_mode
Flag indicating if the logger is in single mode.
std::atomic< bool > enabled
Flag indicating if the logger is enabled.
std::unique_ptr< ILogger > logger
The logger instance.
std::unique_ptr< ILogFormatter > formatter
The formatter instance.