2024-12-02 15:16:25 +00:00
|
|
|
#ifndef _INCLUDE_LOGGER_
|
|
|
|
#define _INCLUDE_LOGGER_
|
|
|
|
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <vector>
|
|
|
|
#include <memory>
|
|
|
|
#include <iostream>
|
|
|
|
#include <chrono>
|
|
|
|
#include <unordered_map>
|
|
|
|
#include "level.h"
|
|
|
|
|
|
|
|
namespace logging {
|
|
|
|
|
|
|
|
struct Record;
|
|
|
|
class LoggerOStream;
|
|
|
|
class LoggerStreamBuf;
|
|
|
|
|
|
|
|
class Logger
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
enum class Level: uint8_t
|
|
|
|
{
|
|
|
|
UNKNOWN = 0,
|
|
|
|
DEBUG = LOG_LEVEL_DEBUG,
|
|
|
|
INFO = LOG_LEVEL_INFO,
|
|
|
|
WARN = LOG_LEVEL_WARN,
|
|
|
|
ERROR = LOG_LEVEL_ERROR,
|
|
|
|
FATAL = LOG_LEVEL_FATAL
|
|
|
|
};
|
|
|
|
|
|
|
|
constexpr static const char* namesep = "::";
|
|
|
|
|
2024-12-18 15:08:16 +00:00
|
|
|
explicit Logger(Level level = Level::INFO) : _parent(nullptr), _level(level) {}
|
2024-12-02 15:16:25 +00:00
|
|
|
Logger(const Logger&) = delete;
|
|
|
|
virtual ~Logger() = default;
|
|
|
|
|
2024-12-18 15:08:16 +00:00
|
|
|
inline Level level() const
|
|
|
|
{
|
|
|
|
if (_level == Logger::Level::UNKNOWN) {
|
|
|
|
if (_parent) {
|
|
|
|
return _parent->level();
|
|
|
|
}
|
|
|
|
return Logger::Level::INFO;
|
|
|
|
}
|
|
|
|
return _level;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline const std::string& name() const
|
|
|
|
{
|
|
|
|
return _name;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline Logger* parent() const
|
|
|
|
{
|
|
|
|
return _parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline size_t children_count() const
|
|
|
|
{
|
|
|
|
return logger_cache.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void set_level(Level level)
|
|
|
|
{
|
|
|
|
_level = level;
|
|
|
|
}
|
2024-12-02 15:16:25 +00:00
|
|
|
|
|
|
|
template<Level level>
|
2024-12-18 15:08:16 +00:00
|
|
|
inline void log(const char* fmt, ...) {
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
|
|
vlog(level, fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
inline void log(Level level, const char* fmt, ...)
|
|
|
|
{
|
2024-12-02 15:16:25 +00:00
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
|
|
vlog(level, fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
}
|
2024-12-18 15:08:16 +00:00
|
|
|
inline void debug(const char* fmt, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
|
|
vlog(Logger::Level::DEBUG, fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
void info(const char* fmt, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
|
|
vlog(Logger::Level::INFO, fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
void warn(const char* fmt, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
|
|
vlog(Logger::Level::WARN, fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
void error(const char* fmt, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
|
|
vlog(Logger::Level::ERROR, fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
void fatal(const char* fmt, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
|
|
vlog(Logger::Level::FATAL, fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
}
|
2024-12-02 15:16:25 +00:00
|
|
|
template<Level level>
|
2024-12-18 15:08:16 +00:00
|
|
|
inline void vlog(const char* fmt, va_list args) {
|
2024-12-02 15:16:25 +00:00
|
|
|
vlog(level, fmt, args);
|
|
|
|
}
|
|
|
|
template<typename E = std::runtime_error>
|
2024-12-18 15:08:16 +00:00
|
|
|
inline void raise_from_errno(const char* msg) {
|
2024-12-02 15:16:25 +00:00
|
|
|
error("%s: %s", msg, strerror(errno));
|
|
|
|
throw E(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
void vlog(Level level, const char* fmt, va_list args);
|
|
|
|
virtual void log_message(Level level, const std::string& msg);
|
|
|
|
|
|
|
|
LoggerOStream operator[](Level level);
|
|
|
|
LoggerOStream operator[](int level);
|
|
|
|
|
2024-12-10 07:53:48 +00:00
|
|
|
void move_children_to(Logger& other);
|
|
|
|
|
|
|
|
template<class T_Logger = Logger>
|
|
|
|
Logger* get_child(const std::string& name, Level level)
|
|
|
|
{
|
|
|
|
Logger* logger;
|
|
|
|
auto sep_pos = name.find(namesep);
|
|
|
|
do {
|
|
|
|
if (name.empty() || sep_pos == 0) {
|
|
|
|
logger = this;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
std::string base_name;
|
|
|
|
if (sep_pos == std::string::npos) {
|
|
|
|
base_name = name;
|
|
|
|
} else {
|
|
|
|
base_name = name.substr(0, sep_pos);
|
|
|
|
}
|
|
|
|
auto iter = logger_cache.find(base_name);
|
|
|
|
|
|
|
|
if (iter != logger_cache.end()) {
|
|
|
|
logger = iter->second.get();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
logger = new T_Logger(base_name, level, this);
|
|
|
|
logger_cache[base_name] = std::unique_ptr<Logger>(logger);
|
|
|
|
} while (0);
|
|
|
|
auto seqlen = strlen(namesep);
|
|
|
|
if (sep_pos == std::string::npos || sep_pos + seqlen >= name.size())
|
|
|
|
return logger;
|
|
|
|
return logger->get_child(name.substr(sep_pos + seqlen), level);
|
|
|
|
}
|
2024-12-02 15:16:25 +00:00
|
|
|
|
2024-12-19 10:00:09 +00:00
|
|
|
inline void add_stream(std::ostream& stream)
|
|
|
|
{
|
|
|
|
_streams.push_back(std::unique_ptr<std::ostream>(new std::ostream(stream.rdbuf())));
|
|
|
|
}
|
|
|
|
|
2024-12-18 15:08:16 +00:00
|
|
|
template <typename T>
|
|
|
|
inline void add_stream(T&& stream)
|
|
|
|
{
|
|
|
|
_streams.push_back(std::unique_ptr<std::ostream>(new typename std::remove_reference<T>::type(std::move(stream))));
|
|
|
|
}
|
|
|
|
|
|
|
|
inline std::vector<std::ostream*> streams() const
|
|
|
|
{
|
|
|
|
std::vector<std::ostream*> streams;
|
|
|
|
for (auto& stream : _streams)
|
|
|
|
streams.push_back(stream.get());
|
|
|
|
return streams;
|
|
|
|
}
|
|
|
|
|
2024-12-02 15:16:25 +00:00
|
|
|
protected:
|
|
|
|
explicit Logger(const std::string& name, Level level = Level::INFO, Logger* parent = nullptr);
|
|
|
|
|
|
|
|
virtual void log_record(const Record& record);
|
|
|
|
virtual void write_record(std::ostream& os, const Record& record);
|
|
|
|
|
|
|
|
static constexpr std::ostream& default_stream = std::cerr;
|
|
|
|
|
|
|
|
std::vector<std::unique_ptr<std::ostream>> _streams;
|
|
|
|
Logger* _parent;
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::unordered_map<std::string, std::unique_ptr<Logger>> logger_cache;
|
|
|
|
std::string _name;
|
|
|
|
Level _level;
|
|
|
|
};
|
|
|
|
|
|
|
|
class LoggerStreamBuf : public std::streambuf {
|
|
|
|
public:
|
|
|
|
LoggerStreamBuf(Logger& logger, Logger::Level level);
|
2024-12-06 08:07:06 +00:00
|
|
|
LoggerStreamBuf(const LoggerStreamBuf&) = delete;
|
|
|
|
LoggerStreamBuf(LoggerStreamBuf&& loggerStream) = default;
|
2024-12-02 15:16:25 +00:00
|
|
|
|
|
|
|
protected:
|
|
|
|
int overflow(int c) override;
|
|
|
|
std::streamsize xsputn(const char* s, std::streamsize n) override;
|
|
|
|
int sync() override;
|
|
|
|
|
|
|
|
private:
|
|
|
|
void flush_line(); // 将当前行写入日志
|
|
|
|
|
|
|
|
Logger& _logger;
|
|
|
|
Logger::Level _level;
|
|
|
|
std::string _lineBuffer; // 行缓存
|
|
|
|
};
|
|
|
|
|
|
|
|
class LoggerOStream : public std::ostream {
|
|
|
|
public:
|
|
|
|
LoggerOStream(Logger& logger, Logger::Level level);
|
|
|
|
LoggerOStream(const LoggerOStream&) = delete;
|
|
|
|
LoggerOStream(LoggerOStream&& loggerStream);
|
|
|
|
|
|
|
|
private:
|
|
|
|
LoggerStreamBuf _streamBuf;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Record
|
|
|
|
{
|
|
|
|
std::string name;
|
|
|
|
std::chrono::system_clock::time_point time;
|
|
|
|
Logger::Level level;
|
|
|
|
std::string msg;
|
|
|
|
|
|
|
|
Record(const std::string& name, Logger::Level level, const std::string& msg);
|
|
|
|
};
|
|
|
|
|
2024-12-10 07:53:48 +00:00
|
|
|
using LogLevel = Logger::Level;
|
|
|
|
|
2024-12-02 15:16:25 +00:00
|
|
|
std::ostream& operator<<(std::ostream& os, const Logger::Level level);
|
|
|
|
Logger::Level str2level(const char* level);
|
2024-12-10 07:53:48 +00:00
|
|
|
std::unique_ptr<Logger>& _get_global_logger();
|
|
|
|
Logger& get_global_logger();
|
|
|
|
void set_global_logger(std::unique_ptr<Logger>&& logger);
|
2024-12-02 15:16:25 +00:00
|
|
|
|
2024-12-10 07:53:48 +00:00
|
|
|
template<class T_Logger = Logger>
|
2024-12-02 15:16:25 +00:00
|
|
|
static inline Logger* get_logger(const std::string& name, LogLevel level = LogLevel::UNKNOWN)
|
|
|
|
{
|
2024-12-10 07:53:48 +00:00
|
|
|
return _get_global_logger()->get_child<T_Logger>(name, level);
|
2024-12-02 15:16:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|