高级用法¶
本文档介绍 CFLogger 的高级功能,包括自定义 Sink、Formatter 以及运行时配置。
为什么使用高级 API?¶
简单 API (cflog.h) 适合快速上手,但高级 API (cflog.hpp) 提供更多控制:
| 功能 | 简单 API | 高级 API |
|---|---|---|
| 基本日志记录 | ✅ | ✅ |
| 自定义 Sink | ❌ | ✅ |
| 自定义 Formatter | ❌ | ✅ |
| 同步刷新 | ❌ | ✅ |
| 运行时配置 | ⚠️ 有限 | ✅ 完全控制 |
高级 API 基础¶
引入头文件¶
#include "cflog/cflog.hpp"
#include "cflog/cflog_format_factory.h"
#include "cflog/formatter/console_formatter.h"
#include "cflog/sinks/console_sink.h"
获取 Logger 实例¶
基本用法¶
// 记录日志
logger.log(level::INFO, "消息内容", "标签", std::source_location::current());
// 设置最低级别
logger.setMininumLevel(level::INFO);
// 刷新
logger.flush(); // 异步
logger.flush_sync(); // 同步
自定义 Sink¶
Sink 决定日志的输出目标。CFLogger 提供 ConsoleSink 和 FileSink,你也可以创建自定义 Sink。
创建自定义 Sink¶
#include "cflog/cflog_sink.h"
#include "cflog/cflog_record.h"
#include <iostream>
class MyCustomSink : public ISink {
public:
MyCustomSink(const std::string& prefix = "[MY LOG] ")
: prefix_(prefix) {}
bool write(const LogRecord& record) override {
// 如果有格式化器,使用格式化器
if (formatable() && formatter_) {
auto formatted = formatter_->format_me(record);
output_stream_ << prefix_ << formatted << std::endl;
} else {
// 没有格式化器,简单输出
output_stream_ << prefix_ << record.msg << std::endl;
}
return true;
}
bool flush() override {
output_stream_ << std::flush;
return true;
}
private:
std::string prefix_;
std::ostream& output_stream_ = std::cout;
};
使用自定义 Sink¶
// 创建自定义 Sink
auto my_sink = std::make_shared<MyCustomSink>("[CUSTOM] ");
// 设置格式化器
my_sink->setFormat(std::make_shared<AsciiColorFormatter>());
// 添加到 Logger
Logger::instance().add_sink(my_sink);
网络 Sink 示例¶
#include <asio.hpp>
class NetworkSink : public ISink {
public:
NetworkSink(const std::string& host, int port)
: endpoint_(asio::ip::make_address(host), port),
socket_(io_context_) {}
bool write(const LogRecord& record) override {
if (formatable() && formatter_) {
messages_.push_back(formatter_->format_me(record));
}
return true;
}
bool flush() override {
try {
asio::ip::tcp::socket socket(io_context_);
socket.connect(endpoint_);
for (const auto& msg : messages_) {
asio::write(socket, asio::buffer(msg + "\n"));
}
messages_.clear();
return true;
} catch (...) {
return false;
}
}
private:
asio::io_context io_context_;
asio::ip::tcp::endpoint endpoint_;
asio::ip::tcp::socket socket_;
std::vector<std::string> messages_;
};
自定义 Formatter¶
Formatter 决定日志的输出格式。
创建自定义 Formatter¶
#include "cflog/cflog_format.h"
#include "cflog/cflog_record.h"
#include <sstream>
#include <iomanip>
class JsonFormatter : public IFormatter {
public:
std::string format_me(const LogRecord& r) override {
std::ostringstream oss;
oss << "{";
oss << "\"level\":\"" << to_string(r.lvl) << "\",";
oss << "\"tag\":\"" << r.tag << "\",";
oss << "\"message\":\"" << r.msg << "\",";
oss << "\"thread\":\"" << r.tid << "\"";
oss << "}";
return oss.str();
}
bool configurable() const override { return false; }
};
可配置的 Formatter¶
class ConfigurableFormatter : public IFormatter {
public:
ConfigurableFormatter() {
config_ = std::make_shared<FormatterConfig>(
FormatterFlag::DEFAULT
);
}
std::string format_me(const LogRecord& r) override {
std::string result;
auto flags = config_->get_flags();
if ((flags & FormatterFlag::TIMESTAMP)) {
result += format_timestamp(r);
}
if ((flags & FormatterFlag::LEVEL)) {
result += "[" + std::string(to_string(r.lvl)) + "] ";
}
if ((flags & FormatterFlag::MESSAGE)) {
result += r.msg;
}
return result;
}
bool configurable() const override { return true; }
bool set_config(std::shared_ptr<FormatterConfig> config) override {
if (config) {
config_ = config;
return true;
}
return false;
}
std::shared_ptr<FormatterConfig> get_config() const override {
return config_;
}
private:
std::shared_ptr<FormatterConfig> config_;
};
FormatterFactory 使用¶
FormatterFactory 管理和创建 Formatter 实例。
基本用法¶
FormatterFactory factory;
// 注册格式化器(函数形式)
factory.register_formatter("console", []() {
return std::make_shared<AsciiColorFormatter>();
});
// 注册格式化器(单例形式)
auto json_formatter = std::make_shared<JsonFormatter>();
factory.register_formatter("json", json_formatter);
// 创建新实例
auto formatter = factory.create("console");
// 获取或创建(带缓存)
auto cached = factory.get_or_create("console");
// 清除缓存
factory.clear_cache();
运行时切换格式¶
FormatterFactory factory;
factory.register_formatter("simple", []() {
return std::make_shared<AsciiColorFormatter>(FormatterFlag::MINIMAL);
});
factory.register_formatter("verbose", []() {
return std::make_shared<AsciiColorFormatter>(FormatterFlag::VERBOSE);
});
auto sink = std::make_shared<ConsoleSink>();
// 使用简单格式
sink->setFormat(factory.create("simple"));
// 运行时切换到详细格式
sink->setFormat(factory.create("verbose"));
动态 Sink 管理¶
运行时添加 Sink¶
void enable_file_logging(const std::string& path) {
auto file_sink = std::make_shared<FileSink>(path);
file_sink->setFormat(std::make_shared<FileFormatter>());
Logger::instance().add_sink(file_sink);
}
运行时移除 Sink¶
清除所有 Sink¶
运行时配置修改¶
动态修改日志级别¶
// 白天使用 INFO 级别
Logger::instance().setMininumLevel(level::INFO);
// 晚上调试时使用 DEBUG 级别
Logger::instance().setMininumLevel(level::DEBUG);
动态修改 Formatter 配置¶
auto formatter = std::make_shared<AsciiColorFormatter>();
auto config = std::make_shared<FormatterConfig>();
// 禁用颜色输出
config->disable(FormatterFlag::COLOR);
// 设置时间格式
config->set_timestamp_format("%Y-%m-%d %H:%M:%S");
formatter->set_config(config);
多环境配置¶
开发环境配置¶
void setup_dev_logging() {
using namespace cf::log;
FormatterFactory factory;
factory.register_formatter("dev", []() {
// 开发环境:详细输出 + 颜色
return std::make_shared<AsciiColorFormatter>(
FormatterFlag::VERBOSE | FormatterFlag::COLOR
);
});
auto console = std::make_shared<ConsoleSink>();
console->setFormat(factory.create("dev"));
Logger::instance().clear_sinks();
Logger::instance().add_sink(console);
Logger::instance().setMininumLevel(level::TRACE);
}
生产环境配置¶
void setup_prod_logging() {
using namespace cf::log;
FormatterFactory factory;
factory.register_formatter("prod", []() {
// 生产环境:简洁输出,无颜色
return std::make_shared<FileFormatter>(
FormatterFlag::DEFAULT
);
});
// 文件输出
auto file = std::make_shared<FileSink>(
"/var/log/myapp/app.log",
OpenMode::Append
);
file->setFormat(factory.create("prod"));
// 错误单独输出
auto error_file = std::make_shared<FileSink>(
"/var/log/myapp/error.log",
OpenMode::Append
);
error_file->setFormat(factory.create("prod"));
Logger::instance().clear_sinks();
Logger::instance().add_sink(file);
Logger::instance().add_sink(error_file);
Logger::instance().setMininumLevel(level::INFO);
}
完整示例¶
#include "cflog/cflog.hpp"
#include "cflog/cflog_format_factory.h"
#include "cflog/formatter/console_formatter.h"
#include "cflog/sinks/console_sink.h"
#include "cflog/sinks/file_sink.h"
#include <memory>
class AdvancedLoggerConfig {
public:
static void initialize(bool is_production = false) {
using namespace cf::log;
FormatterFactory factory;
// 注册格式化器
factory.register_formatter("console", []() {
return std::make_shared<AsciiColorFormatter>(
FormatterFlag::DEFAULT | FormatterFlag::COLOR
);
});
factory.register_formatter("file", []() {
return std::make_shared<FileFormatter>(
FormatterFlag::DEFAULT
);
});
// 清除现有 sink
Logger::instance().clear_sinks();
// 添加控制台输出
auto console_sink = std::make_shared<ConsoleSink>();
console_sink->setFormat(factory.create("console"));
Logger::instance().add_sink(console_sink);
// 生产环境添加文件输出
if (is_production) {
auto file_sink = std::make_shared<FileSink>(
"app.log",
OpenMode::Append
);
file_sink->setFormat(factory.create("file"));
Logger::instance().add_sink(file_sink);
}
// 设置日志级别
Logger::instance().setMininumLevel(
is_production ? level::INFO : level::DEBUG
);
}
};
int main(int argc, char** argv) {
// 根据命令行参数配置
bool is_prod = (argc > 1 && std::string(argv[1]) == "--prod");
AdvancedLoggerConfig::initialize(is_prod);
using namespace cf::log;
info("应用程序启动");
// 你的应用逻辑...
Logger::instance().flush_sync();
return 0;
}