目录
日志器管理模块(单例)
设计思想
成员属性
提供的接口
代码实现:
全局的日志器建造者
代码实现
全局接口的设计
获取日志器的全局接口
使用宏函数代理日志器的输出接口
用户可能会创建多个日志器,然后从中选取一个输出日志,那我们就需要将这些日志器管理起来,因此我们需要设计一个日志器管理模块。
以日志器的名称作为唯一关键字将创建的日志器保存起来,允许用户通过日志器名称获取对应日志器,如果日志器不存在,返回一个默认的日志器。日志器管理者要求全局唯一。
void addLogger(Logger::ptr &logger):添加一个日志器。
bool hasLogger(const std::string &name):判断日志器是否存在。
Logger::ptr getLogger(const std::string &name):获取对应日志器。
Logger::ptr rootLogger():获取默认日志器。
class LoggerManager
{
public:
LoggerManager(const LoggerManager &) = delete;
LoggerManager &operator=(const LoggerManager &) = delete;
// 单例模式
static LoggerManager &getInstance()
{
static LoggerManager eton;
return eton;
}
// 添加一个日志器
void addLogger(Logger::ptr &logger)
{
if (hasLogger(logger->name()))
return;
std::unique_lock lock(_mutex);
_loggers.insert(std::make_pair(logger->name(), logger));
}
// 判断日志器是否存在
bool hasLogger(const std::string &name)
{
std::unique_lock lock(_mutex);
auto it = _loggers.find(name);
if (it == _loggers.end())
return false;
return true;
}
// 获取一个日志器
Logger::ptr getLogger(const std::string &name)
{
std::unique_lock lock(_mutex);
auto it = _loggers.find(name);
if (it == _loggers.end())
return _root_logger;
return it->second;
}
// 获取默认日志器
Logger::ptr rootLogger()
{
return _root_logger;
}
private:
std::unordered_map _loggers;
std::mutex _mutex;
Logger::ptr _root_logger; // 默认日志器
private:
LoggerManager()
{
std::unique_ptr builder = std::make_unique();
builder->buildLoggerName("root");
_root_logger = builder->build();
_loggers.insert(std::make_pair("root", _root_logger));
}
};
我们之前设计了一个local的日志器建造者,其中只是会返回对应的日志器,用户还需要自己将日志器添加到日志器管理者中,提高了操作的复杂度,所以我们设计一个全局的日志器建造者,自动将日志器添加到管理者中。
class GlobalLoggerBuilder : public LoggerBuilder
{
public:
Logger::ptr build() override
{
assert(!_logger_name.empty());
if (_formatter == nullptr)
{
_formatter = std::make_shared();
}
if (_sinks.empty())
{
_sinks.push_back(std::make_shared());
}
Logger::ptr logger;
if (_logger_type == LoggerType::LOGGER_ASYNC)
{
logger = std::make_shared(_logger_name, _limit_level, _formatter, _sinks, _async_type);
}
else
{
logger = std::make_shared(_logger_name, _limit_level, _formatter, _sinks);
}
LoggerManager::getInstance().addLogger(logger);
return logger;
}
};
所有的组件全部设计完毕,然后就是要降低一些使用的难度,因此我们设计一些全局的接口方便操作。
提供给用户根据日志器名称获取指定日志器和获取默认日志器的接口。
// 获取指定日志器的全局接口
Logger::ptr getLogger(const std::string &name)
{
return LoggerManager::getInstance().getLogger(name);
}
Logger::ptr rootLogger()
{
return LoggerManager::getInstance().rootLogger();
}
我们还需要设计一组宏函数来代理日志器对日志信息的落地,这里提供两组,一组是需要日志器指向的宏函数,一组是直接可以用默认日志器落地的宏函数。
// 使用宏函数对日志器接口进行代理
#define debug(fmt, ...) debug(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define info(fmt, ...) info(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define warn(fmt, ...) warn(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define error(fmt, ...) error(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define fatal(fmt, ...) fatal(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
// 提供宏函数,直接通过日志器进行打印
#define DEBUG(fmt, ...) jiuqilog::rootLogger()->debug(fmt, ##__VA_ARGS__)
#define INFO(fmt, ...) jiuqilog::rootLogger()->info(fmt, ##__VA_ARGS__)
#define WARN(fmt, ...) jiuqilog::rootLogger()->warn(fmt, ##__VA_ARGS__)
#define ERROR(fmt, ...) jiuqilog::rootLogger()->error(fmt, ##__VA_ARGS__)
#define FATAL(fmt, ...) jiuqilog::rootLogger()->fatal(fmt, ##__VA_ARGS__)