重写Sylar基于协程的服务器(1、日志模块的架构)

重写Sylar基于协程的服务器(1、日志模块的架构)

重写Sylar基于协程的服务器系列:

重写Sylar基于协程的服务器(0、搭建开发环境以及项目框架 || 下载编译简化版Sylar)

重写Sylar基于协程的服务器(1、日志模块的架构)

前言

和Muduo的日志对比,Muduo的同步日志虽然格式固定,但简单高性能。而sylar的日志设计的显得过于冗余,虽然灵活性强、扩展性高,但是性能却不及Muduo。尽管陈硕大大也说过,简单才能保证高性能,日志就没必要设计的那么花里胡哨,但是sylar对日志的设计思想以及设计模式超级超级适合小白去学习。

日志格式

由于用户可能并不需要将日志上下文的每一项都进行输出,而是希望可以自由地选择要输出的日志项。并且,用户还可能需要在每条日志里增加一些指定的字符,比如在文件名和行号之间加上一个冒号的情况。为了实现这项功能,LogFormatter使用了一个模板字符串来指定格式化的方式。模板字符串由普通字符和占位字符构成。在构造LogFormatter对象时会指定一串模板字符,LogFormatter会首先解析该模板字符串,将其中的占位符和普通字符解析出来。在格式化日志上下文时,根据模板字符串,将其中的占位符替换成日志上下文的具体内容,普通字符保持不变。下表是支持的占位符的含义。

占位符含义
%s普通字符串(直接输出的字符串)
%d时间
%t线程真实id
%N线程名
%f协程id
%p日志级别
%c日志器名
%F文件路径
%l行号
%m日志消息
%TTab缩进
%n换行

%d{%Y-%m-%d %H:%M:%S}%T%t%T%N%T%f%T[%p]%T[%c]%T%F:%l%T%m%n格式串为例,输出效果如图下:

在这里插入图片描述

时间占位符%d需要带有格式化参数%Y-%m-%d %H:%M:%S,这使得日志格式器能对日志上下文收集到的时间戳进行格式化,而对于其他占位符,日志格式器只需要从日志上下文中取来做简单的处理再直接拼接即可。

日志模块架构设计

sylar实现的日志中,一条日志数据流向是:日志包装器->日志器->数个日志输出地,如图所示。

在这里插入图片描述

关于这几个类的设计如下:

  1. LogEvent: 日志上下文,用于记录日志现场,比如该日志的时间,文件路径/行号,日志级别,线程/协程号,日志消息等。

  2. LogEventWrap: 日志事件包装类,其实就是将日志事件和日志器一起包装到日志上下文中,因为一条日志只会在一个日志器上进行输出。将日志事件和日志器包装到一起后,方便通过宏定义来简化日志模块的使用(这点和Muduo很像)。另外,LogEventWrap还负责在构建时指定日志事件和日志器,在析构时调用日志器的log方法将日志事件进行输出。

  3. Logger: 日志器,负责进行日志输出。一个Logger包含多个LogAppender和一个日志级别,提供log方法,传入日志事件,如果日志事件的级别高于日志器本身的级别就调用每一个LogAppender的log方法将日志进行输出,否则该日志被抛弃。

    日志包装器以及日志器伪代码:

    在这里插入图片描述

  4. LogAppender: 日志输出器,用于将一个日志上下文输出到对应的输出地。该类内部包含一个LogFormatter成员和一个log方法,日志事件先经过LogFormatter格式化后再输出到对应的输出地。从这个类可以派生出不同的输出器类型,比如StdoutLogAppender和FileLogAppender,分别表示终端和文件的日志输出器。

    日志输出器伪代码:

    在这里插入图片描述

  5. LogFormatter: 日志格式器,用于格式化一个日志事件。该类构建时可以指定pattern并根据提供的pattern调用init()进行解析。提供format方法,用于将日志事件格式化成字符串。

    日志格式串的解析:

        void LogFormatter::init(){std::vector<std::tuple<std::string, std::string>> res;int len = m_pattern.length();//state -- 0 普通字符部分/日志修饰字符//state -- 1 格式化字符部分//state -- 2 格式化字符参数部分int pLt = 0, pRt = 0, state = 0 ;//'\0'看成万能字符while(pRt <= len){if(state == 0){//状态升级if(pRt == len || m_pattern[pRt] == '%'){if(pLt < pRt){res.push_back(std::make_tuple("s", m_pattern.substr(pLt, pRt - pLt)));}state = 1;  //升级pLt = pRt + 1;}}else if(state == 1){//状态还原 或 状态升级 //或 此时遇到非{,非%,非字母的字符,则隐式代表格式化字符部分结束if(pRt < len && m_pattern[pRt] == '{'){if(pLt < pRt){res.push_back(std::make_tuple(m_pattern.substr(pLt, pRt - pLt), ""));}else{//错误:没有模式字符只有选项参数res.push_back(std::make_tuple("s", "<parse error> empty format character : "));}state = 2;pLt = pRt + 1;}else if(pRt < len && m_pattern[pRt] == '%'){if(pLt < pRt){res.push_back(std::make_tuple(m_pattern.substr(pLt, pRt - pLt), ""));}state = 0;pLt = pRt;continue;}else if(pRt == len || !isalpha(m_pattern[pRt])){if(pLt < pRt){res.push_back(std::make_tuple(m_pattern.substr(pLt, pRt - pLt), ""));}state = 0;pLt = pRt;}}else{  //state == 2//状态还原//缺少},结尾("\0")默认为'}'if(pRt == len || m_pattern[pRt] == '}'){std::get<1>(res.back()) = std::get<1>(res.back()) + m_pattern.substr(pLt, pRt - pLt);state = 0;pLt = pRt + 1;}}pRt++;}// ... 省略不重要的部分}
    
  6. LogManager: 日志器管理类,单例模式,用于统一管理所有的日志器,提供日志器的创建与获取方法。LogManager自带一个root Logger,用于为日志模块提供一个初始可用的日志器。

简化日志使用的宏定义:

日志宏:

#define LUNAR_LOG_LEVEL(logger, level) \if((logger)->getLevel() <= level) \(lunar::LogEventWrap(lunar::LogEvent::ptr(new lunar::LogEvent(__FILE__, __LINE__,\lunar::GetElapse(), lunar::Thread::GetTid(),\lunar::GetFiberId(), ::time(nullptr),\lunar::Thread::GetName(), level, (logger))))).getMsg()#define LUNAR_LOG_DEBUG(logger) LUNAR_LOG_LEVEL(logger, lunar::LogLevel::Level::DEBUG)#define LUNAR_LOG_INFO(logger) LUNAR_LOG_LEVEL(logger, lunar::LogLevel::Level::INFO)#define LUNAR_LOG_WRONG(logger) LUNAR_LOG_LEVEL(logger, lunar::LogLevel::Level::WRONG)#define LUNAR_LOG_ERROR(logger) LUNAR_LOG_LEVEL(logger, lunar::LogLevel::Level::ERROR)#define LUNAR_LOG_FATAL(logger) LUNAR_LOG_LEVEL(logger, lunar::LogLevel::Level::FATAL)

其他

关于异步日志

本着基于协程淡化线程的思想,在sylar中,要实现异步日志的前提是,先要基于协程实现一个信号量,然后通过继承LogAppender参考Muduo设计一个异步日志,但是其后台是由一个协程进行落盘

异步日志的实现涉及到后面的fiber、hook等模块,本文简略带过。

异步日志和同步日志对比

优点缺点
异步日志执行效率更高,一般应用程序只用将日志输出到一块缓存中,由另起的线程将缓存中的日志输出到磁盘上,减少了系统的IO负担当系统崩溃时,容易丢失内存中来不及写入的日志。日志本身的代码实现、调试更复杂
同步日志事件发生就输出,系统崩溃不会出现丢日志的情况,日志输出顺序可控,代码实现简单效率更低,增加系统IO负担,输出日志时会阻塞工作线程

感兴趣的同学,可以阅读一下本文实现的源码:https://github.com/LunarStore/lunar


本章完结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/657215.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

15EG在PL端使用外部时钟驱动led灯

创建PL端的vivado工程在 pl_only_led中已经介绍过了&#xff0c;这里直接从创建好设计文件开始 打开设计文件修改里面代码&#xff0c;代码我也提供了&#xff0c;在工程文件夹下的file文件夹中 15eg这块板子有俩个外部晶振&#xff0c;分别时200M和74.25 M我们可以在原理图中找…

16- OpenCV:轮廓的发现和轮廓绘制、凸包

目录 一、轮廓发现 1、轮廓发现(find contour in your image) 的含义 2、相关的API 以及代码演示 二、凸包 1、凸包&#xff08;Convex Hull&#xff09;的含义 2、Graham扫描算法- 概念介绍 3、cv::convexHull 以及代码演示 三、轮廓周围绘制矩形和圆形框 一、轮廓发现…

【图文详解】阿里云服务器放行高防IP加入安全组

打开阿里云的云服务器配置面板&#xff0c;在要操作实例的操作列找到更多 > 网络和安全组 > 安全组配置。 对已有安全组配置规则&#xff0c;或者直接添加安全组规则。 根据需要放通高防IP在内的IP段相应协议类型的端口访问。

QEMU - e1000全虚拟化前端与TAP/TUN后端流程简析

目录 1. Host -> Guest 2.Guest ->Host 3. 如何修改以支持TUN设备的后端&#xff1f; 4. 相关 QEMU 源码 5. 实验 1. Host -> Guest 2.Guest ->Host 3. 如何修改以支持TUN设备的后端&#xff1f; 1. 简单通过后端网卡名字来判断是TUN还是TAP。 2. 需要前端全…

Adobe Camera Raw forMac/win:掌控原始之美的秘密武器

Adobe Camera Raw&#xff0c;这款由Adobe开发的插件&#xff0c;已经成为摄影师和设计师们的必备工具。对于那些追求完美、渴望探索更多创意可能性的专业人士来说&#xff0c;它不仅仅是一个插件&#xff0c;更是一个能够释放无尽创造力的平台。 在数字摄影时代&#xff0c;R…

使用Win32API实现贪吃蛇小游戏

目录 C语言贪吃蛇项目 基本功能 需要的基础内容 Win32API 介绍 控制台程序部分指令 设置控制台窗口的长宽 设置控制台的名字 控制台在屏幕上的坐标位置结构体COORD 检索指定标准设备的句柄&#xff08;标准输入、标准输出或标准错误&#xff09; 光标信息结构体类型CONSOLE_CUR…

洛谷P8599 [蓝桥杯 2013 省 B] 带分数

[蓝桥杯 2013 省 B] 带分数 题目描述 100 100 100 可以表示为带分数的形式&#xff1a; 100 3 69258 714 100 3 \frac{69258}{714} 100371469258​。 还可以表示为&#xff1a; 100 82 3546 197 100 82 \frac{3546}{197} 100821973546​。 注意特征&#xff1a;带分…

条款32:确定你的public继承塑模出 is-a 关系

如果你编写类D(“派生类”)public继承类B(“基类”)&#xff0c;就是在告诉C编译器(以及代码的读者)每个类型D的对象都是类型B的对象&#xff0c;但反之则不然。 class Person {...}; class Student: public Person {...}; void eat(const Person& p); // 素有的Person都…

云计算HCIE备考经验分享

大家好&#xff0c;我是来自深圳信息职业技术学院22级鲲鹏3-1班的刘同学&#xff0c;在2023年9月19日成功通过了华为云计算HCIE认证&#xff0c;并且取得了A的成绩。下面把我的考证经验分享给大家。 转专业进鲲鹏班考HCIE 大一上学期的时候&#xff0c;在上Linux课程的时候&…

ES Serverless让日志检索更加便捷

前言 在项目中,或者开发过程中,出现bug或者其他线上问题,开发人员可以通过查看日志记录来定位问题。通过日志定位 bug 是一种常见的软件开发和运维技巧,只有观察日志才能追踪到具体代码。在软件开发过程中,开发人员会在代码中添加日志记录,以记录程序的运行情况和异常信…

发现了一款宝藏学习项目,包含了Web全栈的知识体系,JS、Vue、React知识就靠它了!

前言 在当今互联网时代&#xff0c;一切以页面、UI为主要呈现方式&#xff0c;web全栈开发工程师的需求越来越大。 然而&#xff0c;市场上大多数工程师只会使用api而不了解其原理&#xff0c;这种情况使得他们变得可替代。 因此&#xff0c;成为一个高级开发工程师需要具备…

用React给XXL-JOB开发一个新皮肤(四):实现用户管理模块

目录 一. 简述二. 模块规划 2.1. 页面规划2.2. 模型实体定义 三. 模块实现 3.1. 用户分页搜索3.2. Modal 配置3.3. 创建用户表单3.4. 修改用户表单3.5. 删除 四. 结束语 一. 简述 上一篇文章我们实现登录页面和管理页面的 Layout 骨架&#xff0c;并对接登录和登出接口。这篇…

在centos 7 中 安装 配置 并 远程连接 MySQL5.7

目录 安装MySQL 1.卸载CentOS7系统自带的mariadb 2.安装依赖库 3.上传MySQL并解压 4.安装MySQL 配置MySQL 1.修改登录密码 2.修改字符集 3.配置远程连接 前言&#xff1a; 安装MySQL版本&#xff1a;mysql-5.7.30-1.el7.x86_64.rpm-bundle 文件需求后台私信 以下7条为…

STM32学习笔记(四) —— 位段别名区的使用

STM32F103RCT6有两个位段区 (SRAM 最低1M空间和片内外设存储区最低1M空间)&#xff0c; 这两个区域都有各自的别名区&#xff0c;在别名区中每个字会映射到位段区的一个位&#xff0c;所以在别名区修改一个字相当于修改位段区中对应的一个位 映射公式( 别名区中的字与位段区中的…

实现vue3响应式系统核心-watch

简介 今天我们来看看 watch 的实现。 watch本质就是观测一个响应式数据&#xff0c;当数据发生变化时通知并执行相应的回调函数。实际上&#xff0c;watch的实现本质上就是利用了 effect 以及 options.scheduler选项。 代码地址&#xff1a; https://github.com/SuYxh/share-…

flask基于python的个人理财备忘录记账提醒系统vue

在当今高度发达的信息中&#xff0c;信息管理改革已成为一种更加广泛和全面的趋势。 “备忘记账系统”是基于Mysql数据库&#xff0c;在python程序设计的基础上实现的。为确保中国经济的持续发展&#xff0c;信息时代日益更新&#xff0c;蓬勃发展。同时&#xff0c;随着信息社…

【智能家居入门2】(MQTT协议、微信小程序、STM32、ONENET云平台)

此篇智能家居入门与前两篇类似&#xff0c;但是是使用MQTT协议接入ONENET云平台&#xff0c;实现微信小程序与下位机的通信&#xff0c;这里相较于使用http协议的那两篇博客&#xff0c;在主程序中添加了独立看门狗防止程序卡死和服务器掉线问题。后续还有使用MQTT协议连接MQTT…

输入和输出

按字符输入输出 按字符输出putchar&#xff08;&#xff09; 格式 #include <stdio.h> int putchar(int c); 功能&#xff1a;向终端输出一个字符 参数&#xff1a;要输出的字符的ASCII码值 返回值&#xff1a; 成功&#xff0c;返回输出字符的ASCII码值 失败&#xff…

基于springboot汽车租赁系统源码和论文

首先,论文一开始便是清楚的论述了系统的研究内容。其次,剖析系统需求分析,弄明白“做什么”,分析包括业务分析和业务流程的分析以及用例分析,更进一步明确系统的需求。然后在明白了系统的需求基础上需要进一步地设计系统,主要包括软件架构模式、整体功能模块、数据库设计。本项…

Missing or invalid credentials.(Git push报错解决方案)

前言 本文主要讲解git push后报错Missing or invalid credentials的解决方案。这里针对的是windows的。 编程环境&#xff1a;VsCode 问题原因 问题翻译起来就是 凭据缺失或无效。这里我们解决方案是取消vscode里面默认的控制终端git凭据来解决,具体方案如下. 解决方案 1…