13#ifndef LIBE3_LOGGER_HPP
14#define LIBE3_LOGGER_HPP
50using LogCallback = std::function<void(
LogLevel level,
const std::string& component,
const std::string& message)>;
69 level_.store(
level, std::memory_order_relaxed);
76 level_.store(
static_cast<LogLevel>(
level), std::memory_order_relaxed);
83 return level_.load(std::memory_order_relaxed);
93 std::lock_guard<std::mutex> lock(mutex_);
94 callback_ = std::move(callback);
101 std::lock_guard<std::mutex> lock(mutex_);
112 std::lock_guard<std::mutex> lock(mutex_);
119 file_ = std::fopen(path.c_str(),
"a");
121 std::setvbuf(file_,
nullptr, _IOLBF, 0);
123 std::fprintf(stderr,
"[Logger] Failed to open log file %s: %s (errno %d)\n",
124 path.c_str(), std::strerror(errno), errno);
133 return static_cast<int>(
level) <=
static_cast<int>(level_.load(std::memory_order_relaxed));
144 std::lock_guard<std::mutex> lock(mutex_);
147 callback_(
level, component, message);
149 FILE* out = file_ ? file_ : stderr;
151 auto now = std::chrono::system_clock::now();
152 auto time_t = std::chrono::system_clock::to_time_t(now);
153 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
154 now.time_since_epoch()) % 1000;
157 std::strftime(time_buf,
sizeof(time_buf),
"%Y-%m-%d %H:%M:%S", std::localtime(&time_t));
159 std::fprintf(out,
"[%s.%03d] [%s] [%s] %s\n",
160 time_buf,
static_cast<int>(ms.count()),
161 level_to_string(
level), component.c_str(), message.c_str());
172 static const char* level_to_string(
LogLevel level)
noexcept {
179 default:
return "?????";
188 FILE* file_{
nullptr};
198 : level_(level), component_(std::move(component)) {}
201 if (!message_.str().empty()) {
214 std::string component_;
215 std::ostringstream message_;
221#define E3_LOG(level, component) \
222 if (::libe3::Logger::instance().should_log(level)) \
223 ::libe3::LogStream(level, component)
225#define E3_LOG_ERROR(component) E3_LOG(::libe3::LogLevel::ERROR, component)
226#define E3_LOG_WARN(component) E3_LOG(::libe3::LogLevel::WARN, component)
227#define E3_LOG_INFO(component) E3_LOG(::libe3::LogLevel::INFO, component)
228#define E3_LOG_DEBUG(component) E3_LOG(::libe3::LogLevel::DEBUG, component)
229#define E3_LOG_TRACE(component) E3_LOG(::libe3::LogLevel::TRACE, component)
LogStream & operator<<(const T &value)
LogStream(LogLevel level, std::string component)
void set_log_file(const std::string &path)
Set log file path (append mode).
bool should_log(LogLevel level) const noexcept
Check if a level should be logged.
void set_level(int level) noexcept
Set the log level from integer.
void clear_callback()
Clear external log callback.
static Logger & instance()
Get the singleton logger instance.
LogLevel level() const noexcept
Get current log level.
void log(LogLevel level, const std::string &component, const std::string &message)
Log a message.
void set_callback(LogCallback callback)
Set external log callback.
void set_level(LogLevel level) noexcept
Set the log level.
std::function< void(LogLevel level, const std::string &component, const std::string &message)> LogCallback
Log callback function type.