Linux应用框架cpp-tbox之日志系统设计

cpp-tbox项目链接 https://gitee.com/cpp-master/cpp-tbox

更多精彩内容欢迎关注微信公众号:码农练功房
往期精彩内容:
Linux应用框架cpp-tbox之弱定义

简介

cpp-tbox的日志系统有如下特点:

1) 有三种日志输出渠道:stdout + filelog + syslog

  • stdout,将日志通过 std::cout 输出到终端;
  • syslog,将日志通过 syslog() 输出到系统日志;
  • filelog,将日志写入到指定目录下,以格式:前缀.年月日_时分秒.进程号.log 的文件中。文件大小超过1M则另创建新的日志文件。由于写文件效率低,该输出渠道采用前后端模式。

三种渠道可以在启动参数中选定一个或同时多种,也可在运行时通过终端更改。

2) 根据日志等级渲染不同颜色,一目了然,内容详尽
日志内容包含了:等级、时间(精确到微秒)、线程号、模块名、函数名、正文、文件名、行号。方便快速定位问题。
请添加图片描述

3) 灵活的日志输出过滤器,且能运行时修改

可在程序运行时针对不同的模块单独设置日志等级,如下:
请添加图片描述

整体结构图

下图是cpp-tbox中日志系统的代码模型,这里只标识出了主干接口,同时为了排版方便,去除了有些接口的参数,但是不影响我们理解整个结构。
请添加图片描述

输出通道

cpp-tbox支持三种日志输出渠道,可以在启动参数中选定一个或同时多种输出渠道,也可在运行时通过终端更改。这个是怎么实现的呢?

cpp-tbox\modules\base\log_imp.cpp中你可以找到答案:

// cpp-tbox\modules\base\log_imp.cpp
struct OutputChannel {
   
   
    uint32_t id;
    LogPrintfFuncType func;
    void *ptr;
};
std::vector<OutputChannel> _output_channels;

这里在源文件的匿名空间中定义了OutputChannel这个数据结构,其中ptr为指向各个具体Sink类的this指针,func为函数指针,指向具体Sink类的日志处理接口。

需要使能某种输出方式时,把对应类添加到这个输出通道。要关闭某种输出方式时,把对应类从通道中删除即可。

通道删除、添加由以下接口实现,其中id主要在关闭输出方式时使用:

// cpp-tbox\modules\base\log_imp.cpp
uint32_t LogAddPrintfFunc(LogPrintfFuncType func, void *ptr)
bool LogRemovePrintfFunc(uint32_t id)

通道添加、删除接口被Sink::enable和Sink::disable接口所调用。

日志数据包

在日志前端每条日志都会被打包成如下数据结构,送给输出通道。

//  cpp-tbox\modules\base\log_imp.cpp
struct LogContent {
   
   
    long thread_id;         //!< 线程ID
    struct {
   
   
        uint32_t sec;       //!< 秒
        uint32_t usec;      //!< 微秒
    } timestamp;            //!< 时间戳

    const char *module_id;  //!< 模块名
    const char *func_name;  //!< 函数名
    const char *file_name;  //!< 文件名
    int         line;       //!< 行号
    int         level;      //!< 日志等级
    uint32_t    text_len;   //!< 内容大小
    const char *text_ptr;   //!< 内容地址
};

在输出通道中,最终会调用Sink::onLogFrontEnd这个日志前端接口(纯虚接口),而这个接口由各个派生类实现,这里用到了模板方法(Template Method)。

// cpp-tbox\modules\log\sink.cpp
// Sink::HandleLog被注册到OutputChannel.func
void Sink::HandleLog(const LogContent *content, void *ptr)
{
   
   
    Sink *pthis = static_cast<Sink*>(ptr);
    pthis->handleLog
在使用cpp-tbox框架编写高并发TCP服务器时,首先需要了解cpp-tbox的基本结构和网络通信模块。cpp-tbox是一个轻量级、高性能的C++库,主要用于网络编程和系统工具开发。以下是一个简单的示例,展示如何利用cpp-tbox创建一个基础的TCP服务器: ```cpp #include "tbox/tbox.hpp" #include "tbox/net/tcp_server.hpp" class MyHandler : public tbox::net::TcpServer::SessionHandler { public: void on_connection(const tbox::net::Address &address) override { std::cout << "New connection from " << address.to_string() << std::endl; // 创建一个新的线程处理客户端请求 std::thread([this] { while (true) { char buffer[1024]; if (recv(buffer, sizeof(buffer)) > 0) { send(buffer, strlen(buffer)); } else { break; // 断开连接时退出循环 } } close(); // 关闭连接 }).detach(); // 线程异步执行并脱离主线程 } void on_error(int error_code) override { std::cerr << "Error code: " << error_code << std::endl; } }; int main() { try { tbox::net::TcpServer server(8080); // 设置监听端口 server.set_handler<MyHandler>(); // 设置处理器 server.start(); // 启动服务 std::cout << "Server started." << std::endl; // 保持主进程运行,直到用户停止程序 while (true) { std::this_thread::sleep_for(std::chrono::seconds(1)); } } catch (const std::exception &e) { std::cerr << "Error: " << e.what() << std::endl; } return 0; } ``` 在这个例子中,我们创建了一个`MyHandler`类,继承自`TcpServer::SessionHandler`,它实现了接收到新连接和错误处理的行为。服务器启动后,每个新连接会被放入一个新的线程中处理,这样可以充分利用多核CPU提高并发性能。 然而,实际生产环境中,可能还需要考虑线程池、负载均衡、错误恢复等因素。对于更复杂的场景,你可能需要查阅cpp-tbox的具体文档,或者参考其官方示例代码来优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值