当前位置: 首页 > news >正文

娄底网站优化门头沟做网站公司

娄底网站优化,门头沟做网站公司,WordPress多站点绑定域名,网站建设合作合同模板下载文章目录 专栏导读日志格式化类成员介绍patternitems 格式化子项类的设计抽象格式化子项基类日志主体消息子项日志等级子项时间子项localtime_r介绍strftime介绍 源码文件名子项源码文件行号子项线程ID子项日志器名称子项制表符子项换行符子项原始字符串子项 日志格式化类的设计…

文章目录

  • 专栏导读
  • 日志格式化类成员介绍
    • pattern
    • items
  • 格式化子项类的设计
      • 抽象格式化子项基类
      • 日志主体消息子项
      • 日志等级子项
      • 时间子项
        • localtime_r介绍
        • strftime介绍
      • 源码文件名子项
      • 源码文件行号子项
      • 线程ID子项
      • 日志器名称子项
      • 制表符子项
      • 换行符子项
      • 原始字符串子项
  • 日志格式化类的设计
    • 设计思想
    • 接口实现
      • Formatter
      • format
      • parsePattern
      • createItem
  • 日志输出格式化类整理

专栏导读

🌸作者简介:花想云 ,在读本科生一枚,C/C++领域新星创作者,新星计划导师,阿里云专家博主,CSDN内容合伙人…致力于 C/C++、Linux 学习。

🌸专栏简介:本文收录于 C++项目——基于多设计模式下的同步与异步日志系统

🌸相关专栏推荐:C语言初阶系列C语言进阶系列C++系列数据结构与算法Linux

在这里插入图片描述

日志格式化类成员介绍

日志消息格式化类主要负责将日志消息进行格式化。类中包含以下成员:

pattern

  • pattern:保存格式化规则字符串
    • 默认日志输出格式[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n
    • %d 表示日期,包含子格式 {%H:%M:%S}
    • %T 表示缩进;
    • %t 表示线程ID;
    • %c 表示日志器名称;
    • %f 表示源码文件名;
    • %l 表示源码行号;
    • %p 表示日志级别;
    • %m 表示主体消息;
    • %n 表示换行;

格式化规则字符串控制了日志的输出格式。定义格式化字符,就是为了方便让用户自己决定以何种形式将日志消息进行输出。

例如,在默认输出格式下,输出的日志消息为:
在这里插入图片描述

items

  • std::vector< FormatItem::ptr > items:用于按序保存格式化字符串对应的格式化子项对象。
    • MsgFormatItem:表示要从LogMsg中取出有效载荷;
    • LevelFormatItem:表示要从LogMsg中取出日志等级;
    • LoggerFormatItem:表示要从LogMsg中取出日志器名称;
    • ThreadFormatItem:表示要从LogMsg中取出线程ID;
    • TimeFormatItem:表示要从LogMsg中取出时间戳并按照指定格式进行格式化;
    • FileFormatItem:表示要从LogMsg中取出源码所在文件名;
    • LineFormatItem:表示要从LogMsg中取出源码所在行号;
    • TabFormatItem:表示一个制表符缩进;
    • NLineFormatItem:表示一个换行;
    • OtherFormatItem:表示非格式化的原始字符串;

一个日志消息对象包含许多元素,如时间、线程ID、文件名等等,我们针对不同的元素设计不同的格式化子项。

换句话说,不同的格式化子项从日志消息对象中提取出指定元素,转换为规则字符串并按顺序保存在一块内存空间中。

/*%d 表示日期,包含子格式 {%H:%M:%S}%t 表示线程ID%c 表示日志器名称%f 表示源码文件名%l 表示源码行号%p 表示日志级别%m 表示主体消息%n 表示换行
*/
class Formatter
{
public:// ...
private:std::string _pattern; // 格式化规则字符串std::vector<FormatItem::ptr> _items;
};

格式化子项类的设计

刚才提到对于一条日志消息message,其中包含很多元素(时间、线程ID等)。我们通过设计不同的格式化子项来取出指定的元素,并将它们追加到一块内存空间中。

但是由于不同的格式化子项类对象类型也各不相同,我们就采用多态的思想,抽象出一个格式化子项基类,基于基类派生出不同的格式化子项类。这样就可以定义父类指针的数组,指向不同的格式化子项子类对象。

抽象格式化子项基类

class FormatItem
{
public:using ptr = std::shared_ptr<FormatItem>;virtual void format(std::ostream &out, const LogMsg &msg) = 0;
};
  • 在基类中定义一个智能指针对象,方便管理;
  • format的参数为一个IO流对象,一个LogMsg对象。作用为提取LogMsg对象中的指定元素追加到流对象中。

日志主体消息子项

class MsgFormatItem : public FormatItem
{
public:void format(std::ostream &out, const LogMsg &msg) override{out << msg._payload;}
};

日志等级子项

class MsgFormatItem : public FormatItem
{
public:void format(std::ostream &out, const LogMsg &msg) override{out << msg._payload;}
};

时间子项

class TimeFormatItem : public FormatItem
{
public:TimeFormatItem(const std::string &fmt = "%H:%M:%S") : _time_fmt(fmt) {}void format(std::ostream &out, const LogMsg &msg) override{struct tm t;localtime_r(&msg._ctime, &t);char tmp[32] = {0};strftime(tmp, 31, _time_fmt.c_str(), &t);out << tmp;}private:std::string _time_fmt; // %H:%M:%S
};
  • 时间子项可以设置子格式,在构造函数中需要传递一个子格式字符串来控制时间子格式;

localtime_r介绍

在LogMsg对象中,时间元素是一个时间戳数字,不方便观察时间信息。我们需要将该时间戳转化为易于观察的时分秒的格式。

localtime_r函数是C标准库中的一个函数,用于将时间戳(表示自1970年1月1日以来的秒数)转换为本地时间的表示。这个函数是线程安全的版本,它接受两个参数:一个指向时间戳的指针和一个指向struct tm类型的指针,它会将转换后的本地时间信息存储在struct tm结构中。

函数原型如下:

struct tm *localtime_r(const time_t *timep, struct tm *result);
  • timep参数是指向时间戳的指针;
  • result参数是指向struct tm类型的指针,用于存储转换后的本地时间信息;
  • localtime_r函数返回一个指向struct tm结构的指针,同时也将结果存储在result参数中;
  • struct tm结构包含了年、月、日、时、分、秒等时间信息的成员变量,可用于格式化和输出时间;

struct tm类型
struct tm是C语言中的一个结构体类型,用于表示日期和时间的各个组成部分。

struct tm结构包含以下成员变量:

struct tm
{int tm_sec; // 秒(0-59)int tm_min; // 分钟(0-59)int tm_hour; // 小时(0-23)int tm_mday; // 一个月中的日期(1-31)int tm_mon; // 月份(0-11,0代表1月)int tm_year; // 年份(从1900年起的年数,例如,121表示2021年)int tm_wday; // 一周中的星期几(0-6,0代表星期日)int tm_yday; // 一年中的第几天(0-365)int tm_isdst; // 是否为夏令时(正数表示是夏令时,0表示不是,负数表示夏令时信息不可用)
}

strftime介绍

strftime函数是C标准库中的一个函数,用于将日期和时间按照指定的格式进行格式化,并将结果存储到一个字符数组中。这个函数在C语言中非常常用,特别是在需要将日期和时间以不同的格式输出到屏幕、文件或其他输出设备时。

函数原型如下:

size_t strftime(char *s, size_t maxsize, const char *format, const struct tm *timeptr);
  • s:一个指向字符数组的指针,用于存储格式化后的日期和时间字符串;
  • maxsize:指定了字符数组 s 的最大容量,以防止缓冲区溢出;
  • format:一个字符串,用于指定日期和时间的输出格式。该字符串可以包含- 各种格式化控制符,例如%Y表示年份,%m表示月份等等;
  • timeptr:一个指向struct tm 结构的指针,表示待格式化的日期和时间;

返回值:

  • strftime函数返回生成的字符数(不包括空终止符\0),如果生成的字符数大于 maxsize,则返回0,表示字符串无法完全存储在给定的缓冲区中。

源码文件名子项

class FileFormatItem : public FormatItem
{
public:void format(std::ostream &out, const LogMsg &msg) override{out << msg._file;}
};

源码文件行号子项

class LineFormatItem : public FormatItem
{
public:void format(std::ostream &out, const LogMsg &msg) override{out << msg._line;}
};

线程ID子项

class ThreadFormatItem : public FormatItem
{
public:void format(std::ostream &out, const LogMsg &msg) override{out << msg._tid;}
};

日志器名称子项

class LoggerFormatItem : public FormatItem
{
public:void format(std::ostream &out, const LogMsg &msg) override{out << msg._logger;}
};

制表符子项

class TabFormatItem : public FormatItem
{
public:void format(std::ostream &out, const LogMsg &msg) override{out << "\t";}
};

换行符子项

class NLineFormatItem : public FormatItem
{
public:void format(std::ostream &out, const LogMsg &msg) override{out << "\n";}
};

原始字符串子项

class OtherFormatItem : public FormatItem
{
public:OtherFormatItem(const std::string &str) : _str(str) {}void format(std::ostream &out, const LogMsg &msg) override{out << _str;}private:std::string _str;
};

解释一下原始字符串:

  • 例如一个格式化字符串为[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n,其中[]:等符号是不属于上述任何子项的,这些符号不需要被解析,它们会作为日志内容被直接输出。

日志格式化类的设计

设计思想

日志格式化Formatter类中提供四个接口:

class Formatter
{
public:using ptr = std::shared_ptr<Formatter>;Formatter(const std::string &pattern = "[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n");void format(std::ostream &out, const LogMsg &msg);std::string format(const LogMsg &msg);
private:bool parsePattern();// 根据不同的格式化字符创建不同得格式化子项对象FormatItem::ptr createItem(const std::string &key, const std::string &val);
private:std::string _pattern; // 格式化规则字符串std::vector<FormatItem::ptr> _items;
};
  • Formatter:构造函数,构造一个formatter对象。函数参数为一个格式化字符串用来初始化成员pattern
  • format:提供两个重载函数,函数作用为将LogMsg中元素提取出来交由对应的格式化子项处理;可以将LogMsg进行格式化,并追加到流对象当中,也可以直接返回格式化后的字符串;
  • parsePattern:用于解析规则字符串_pattern
  • createItem:用于根据不同的格式化字符串创建不同的格式化子项对象

接口实现

Formatter

// 时间{年-月-日 时:分:秒}缩进 线程ID 缩进 [日志级别] 缩进 [日志名称] 缩进 文件名:行号 缩进 消息换行
Formatter(const std::string &pattern = "[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n"): _pattern(pattern)
{assert(parsePattern()); // 确保格式化字符串有效
}

format

// 对msg进行格式化
void format(std::ostream &out, const LogMsg &msg)
{for (auto &item : _items){item->format(out, msg);}
}std::string format(const LogMsg &msg)
{std::stringstream ss;format(ss, msg);return ss.str();
}

parsePattern

函数设计思想

  • 函数的主要逻辑是从前往后的处理格式化字符串。以默认格式化字符串"[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n"为例:
    • 从前往后遍历,如果没有遇到%则说明之前的字符都是原始字符串;
    • 遇到%,则看紧随其后的是不是另一个%,如果是,则认为%就是原始字符串;
    • 如果%后面紧挨着的是格式化字符(c、f、l、S等),则进行处理;
    • 紧随格式化字符之后,如果有{,则认为在{之后、}之前都是子格式内容;

在处理过程中,我们需要将得到的结果保存下来,于是我们可以创建一个vector,类型为一个键值对(key,val)。如果是格式化字符,则key为该格式化字符valnull;若为原始字符串keynullval原始字符串内容

得到数组之后,根据数组内容,调用createItem函数创建对应的格式化子项对象,添加到items成员中。

bool parsePattern()
{std::vector<std::pair<std::string, std::string>> fmt_order;size_t pos = 0;std::string key, val;while (pos < _pattern.size()){if (_pattern[pos] != '%'){val.push_back(_pattern[pos++]);continue;}if (pos + 1 < _pattern.size() && _pattern[pos + 1] == '%'){val.push_back('%');pos += 2;continue;}if (val.empty() == false){fmt_order.push_back(std::make_pair("", val));val.clear();}pos += 1;if (pos == _pattern.size()){std::cout << "%之后没有格式化字符\n";return false;}key = _pattern[pos];pos += 1;if (pos < _pattern.size() && _pattern[pos] == '{'){pos += 1;while (pos < _pattern.size() && _pattern[pos] != '}'){val.push_back(_pattern[pos++]);}if (pos == _pattern.size()){std::cout << "子规则{}匹配出错\n";return false;}pos += 1;}fmt_order.push_back(std::make_pair(key, val));key.clear();val.clear();}for (auto &it : fmt_order){_items.push_back(createItem(it.first, it.second));}return true;
}

createItem

  • 根据不同的格式化字符创建不同得格式化子项对象;
// 根据不同的格式化字符创建不同得格式化子项对象
FormatItem::ptr createItem(const std::string &key, const std::string &val)
{if (key == "d")return std::make_shared<TimeFormatItem>(val);if (key == "t")return std::make_shared<ThreadFormatItem>();if (key == "c")return std::make_shared<LoggerFormatItem>();if (key == "f")return std::make_shared<FileFormatItem>();if (key == "l")return std::make_shared<LineFormatItem>();if (key == "p")return std::make_shared<LevelFormatItem>();if (key == "T")return std::make_shared<TabFormatItem>();if (key == "m")return std::make_shared<MsgFormatItem>();if (key == "n")return std::make_shared<NLineFormatItem>();if (key == "")return std::make_shared<OtherFormatItem>(val);std::cout << "没有对应的格式化字符串:%" << key << std::endl;abort();
}

至此,日志消息格式化类已经全部实现完毕。


日志输出格式化类整理

#ifndef __M_FMT_H__
#define __M_FMT_H__#include "level.hpp"
#include "message.hpp"
#include <vector>
#include <sstream>
#include <ctime>
#include <cassert>namespace LOG
{// 抽象格式化子项基类class FormatItem{public:using ptr = std::shared_ptr<FormatItem>;virtual void format(std::ostream &out, const LogMsg &msg) = 0;};class MsgFormatItem : public FormatItem{public:void format(std::ostream &out, const LogMsg &msg) override{out << msg._payload;}};class LevelFormatItem : public FormatItem{public:void format(std::ostream &out, const LogMsg &msg) override{out << LogLevel::tostring(msg._level);}};class TimeFormatItem : public FormatItem{public:TimeFormatItem(const std::string &fmt = "%H:%M:%S") : _time_fmt(fmt) {}void format(std::ostream &out, const LogMsg &msg) override{struct tm t;localtime_r(&msg._ctime, &t);char tmp[32] = {0};strftime(tmp, 31, _time_fmt.c_str(), &t);out << tmp;}private:std::string _time_fmt; // %H:%M:%S};class FileFormatItem : public FormatItem{public:void format(std::ostream &out, const LogMsg &msg) override{out << msg._file;}};class LineFormatItem : public FormatItem{public:void format(std::ostream &out, const LogMsg &msg) override{out << msg._line;}};class ThreadFormatItem : public FormatItem{public:void format(std::ostream &out, const LogMsg &msg) override{out << msg._tid;}};class LoggerFormatItem : public FormatItem{public:void format(std::ostream &out, const LogMsg &msg) override{out << msg._logger;}};class TabFormatItem : public FormatItem{public:void format(std::ostream &out, const LogMsg &msg) override{out << "\t";}};class NLineFormatItem : public FormatItem{public:void format(std::ostream &out, const LogMsg &msg) override{out << "\n";}};class OtherFormatItem : public FormatItem{public:OtherFormatItem(const std::string &str) : _str(str) {}void format(std::ostream &out, const LogMsg &msg) override{out << _str;}private:std::string _str;};/*%d 表示日期,包含子格式 {%H:%M:%S}%t 表示线程ID%c 表示日志器名称%f 表示源码文件名%l 表示源码行号%p 表示日志级别%m 表示主体消息%n 表示换行*/class Formatter{public:using ptr = std::shared_ptr<Formatter>;// 时间{年-月-日 时:分:秒}缩进 线程ID 缩进 [日志级别] 缩进 [日志名称] 缩进 文件名:行号 缩进 消息换行Formatter(const std::string &pattern = "[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n"): _pattern(pattern){assert(parsePattern());}// 对msg进行格式化void format(std::ostream &out, const LogMsg &msg){for (auto &item : _items){item->format(out, msg);}}std::string format(const LogMsg &msg){std::stringstream ss;format(ss, msg);return ss.str();}private:// 解析格式化字符串bool parsePattern(){std::vector<std::pair<std::string, std::string>> fmt_order;size_t pos = 0;std::string key, val;while (pos < _pattern.size()){if (_pattern[pos] != '%'){val.push_back(_pattern[pos++]);continue;}if (pos + 1 < _pattern.size() && _pattern[pos + 1] == '%'){val.push_back('%');pos += 2;continue;}if (val.empty() == false){fmt_order.push_back(std::make_pair("", val));val.clear();}pos += 1;if (pos == _pattern.size()){std::cout << "%之后没有格式化字符\n";return false;}key = _pattern[pos];pos += 1;if (pos < _pattern.size() && _pattern[pos] == '{'){pos += 1;while (pos < _pattern.size() && _pattern[pos] != '}'){val.push_back(_pattern[pos++]);}if (pos == _pattern.size()){std::cout << "子规则{}匹配出错\n";return false;}pos += 1;}fmt_order.push_back(std::make_pair(key, val));key.clear();val.clear();}for (auto &it : fmt_order){_items.push_back(createItem(it.first, it.second));}return true;}// 根据不同的格式化字符创建不同得格式化子项对象FormatItem::ptr createItem(const std::string &key, const std::string &val){if (key == "d")return std::make_shared<TimeFormatItem>(val);if (key == "t")return std::make_shared<ThreadFormatItem>();if (key == "c")return std::make_shared<LoggerFormatItem>();if (key == "f")return std::make_shared<FileFormatItem>();if (key == "l")return std::make_shared<LineFormatItem>();if (key == "p")return std::make_shared<LevelFormatItem>();if (key == "T")return std::make_shared<TabFormatItem>();if (key == "m")return std::make_shared<MsgFormatItem>();if (key == "n")return std::make_shared<NLineFormatItem>();if (key == "")return std::make_shared<OtherFormatItem>(val);std::cout << "没有对应的格式化字符串:%" << key << std::endl;abort();}private:std::string _pattern; // 格式化规则字符串std::vector<FormatItem::ptr> _items;};
}#endif

在这里插入图片描述

http://www.yayakq.cn/news/411762/

相关文章:

  • wordpress网站流量统计插件黑龙江省建设工程交易中心网站
  • 网站太卡怎么优化做红木家具推广哪个网站比较好
  • 做电力的系统集成公司网站淘宝运营团队
  • 旅游网站建设平台分析湖南建设厅官网平台
  • 建设校园标准信息服务网站论文番禺网站开发服务
  • wordpress扁平化搜索引擎优化的核心本质
  • 最专业的网站设计公司有哪些有什么网站交互做的很好 知乎
  • 内网网站建设重庆市招投标网官网
  • 东莞模板建站软件网页升级访问中每天正常
  • 公司创建一个网站需要多少钱如何做网站拥有自己的地址
  • 播放量网站推广免费网络舆情监测预警系统
  • 网站建设小图标内蒙古自治区建设厅网站首页
  • 微信官网与手机网站区别网站建设推广加盟
  • wordpress制作小说网站模板下载添加网站绑定主机名
  • 如何看一个网站开发语言田阳县建设局网站
  • 芜湖营销型网站制作常州建设局下属网站
  • 网站内做关键词连接制作网站首页psd
  • 广州市平安建设 网站企业内部管理软件
  • 网站建设什么是开发实施实施建设网站企业排行
  • 网站网页设计怎么收费提交图片的网站要怎么做
  • 揭阳网站制作wordpress站长主题
  • 青岛知名网站建设多少钱平台网站可以做第三方检测报告
  • 网站备案多个域名备案单上填几个用模板网站做h5宣传页多少钱
  • 网站上职业学校排名 该怎么做商业计划书模板
  • 良精企业网站系统网站空间的权限
  • 三合一网站建设系统html5下载教程
  • 快手刷赞网站推广软件高水平的网站建设公司
  • 阿里巴巴做国际网站多少钱建站申请范文
  • 太仓广告设计公司网站广州品牌策划公司排行榜
  • 长沙专业建网站公司哪里卖网站域名