fwt_software/include/fgc/Logger.h

58 lines
2.0 KiB
C++

#pragma once
#include <ostream>
#include <sstream>
#include <string>
namespace fgc {
enum class LogLevel { Trace = 0, Debug, Info, Warn, Error, Off };
// Minimal leveled, thread-safe logger. Each log line is assembled in a
// per-statement buffer and written atomically under a shared mutex, so lines
// from different threads never interleave. Level filtering is global.
//
// Usage: LOG_INFO << "starting, rate=" << rate;
// Lines at Warn/Error go to stderr; everything else to stdout.
class Logger {
public:
static void setLevel(LogLevel level);
static LogLevel level();
static bool enabled(LogLevel level);
// Parse "trace"|"debug"|"info"|"warn"|"error"|"off" (case-insensitive).
// Returns false (and leaves the level unchanged) on an unknown string.
static bool setLevelFromString(const std::string& s);
};
// RAII helper that buffers one log line and flushes it on commit().
// Designed to be driven by the LOG_* macros' for-loop guard.
class LogStream {
public:
explicit LogStream(LogLevel level);
bool pending() const { return enabled_ && !done_; }
void commit();
std::ostream& stream() { return buffer_; }
private:
LogLevel level_;
bool enabled_;
bool done_ = false;
std::ostringstream buffer_;
};
} // namespace fgc
// Brace-safe: the whole macro is a single for-statement, so it composes
// correctly inside if/else without dangling-else hazards, and the message
// expression is never evaluated when the level is disabled.
#define FGC_LOG_AT(level) \
for (::fgc::LogStream _fgc_ls(level); _fgc_ls.pending(); _fgc_ls.commit()) \
_fgc_ls.stream()
#define LOG_TRACE FGC_LOG_AT(::fgc::LogLevel::Trace)
#define LOG_DEBUG FGC_LOG_AT(::fgc::LogLevel::Debug)
#define LOG_INFO FGC_LOG_AT(::fgc::LogLevel::Info)
#define LOG_WARN FGC_LOG_AT(::fgc::LogLevel::Warn)
#define LOG_ERROR FGC_LOG_AT(::fgc::LogLevel::Error)