日志系統——日志格式化模塊設計

一,模塊主要成員

該模塊的主要作用是對日志消息進行格式化,將日志消息組織成制定格式的字符串

該模塊主要成員有兩個:1.格式化字符串。 2.格式化子項數組

1.1 格式化字符串

格式化字符串的主要功能是保存日志輸出的格式字符串。其格式化字符主要有下面幾種

格式化字符串定義了日志的輸出格式,而格式化字符更有助于用戶自由的控制日志的輸出格式 。這里要注意的是由于我們信息中的日期為時間戳,因此在設置其格式化字符時還應設置對應的子格式化字符如[%d{%H:%M:%S}]指的是按照年月日輸出時間

?1.2 格式化子項數組

格式化子項數組:用于按順序保存格式化字符串對應的子格式化對象(FormatItem類)

那么什么是子格式化類(FormatItem類)?子格式化類主要負責日志消息子項的獲取以及格式化,其下包含諸多子類,通過繼承關系實現多態,即使是不同的子類也能依靠多態由相同的父類指針指向,從而保存到同一個vector中,Formatltem主要有以下子類:

?格式化字符,以及格式化子項的關系如下,這里我們以日期為例子

?

?

1.3 舉例說明

例子:"[%d{%H:%M:%S}] %m%n"

pattern = "[%d{%H:%M:%S}] %m%n"
items = {{OtherFormatItem(), "["},{TimeFormatItem(), "%H:%M:%S"},{OtherFormatItem(), "]"},{MsgFormatItem (), ""},{NLineFormatItem (), ""}
}
message msg = {size_t _line = 22;size_t _ctime = 12345678;std::thread::id _tid = 0x12345678;std::string _logger = "logger";std::string _file = "main.cpp";std::string _payload = "創建套接字失敗";LogLevel::level _level = ERROR;
};

格式化的過程其實就是按次序從Msg中取出需要的數據進?字符串的連接的過程。

最終組織出來的格式化消息: "[22:32:54] 創建套接字失敗\n"

?二,代碼實現

2.1 代碼

核心代碼bool AnalyPattern()的分析如下

?

?

#ifndef _M_FORMAT_H_
#define _M_FORMAT_H_#include "level.hpp"
#include "message.hpp"
#include "util.hpp"
#include <vector>
#include <memory>
#include <sstream>namespace mjwlog
{// 格式化子項基類class Formatlem{public:using ptr=std::shared_ptr<Formatlem>;virtual void format(std::ostream &os, const message& msg) = 0;};// 格式化子項子類// 日期類子類class TimeFormatlem : public Formatlem{public:TimeFormatlem(std::string format="%H:%M:%S"):_fromat(format){}void format(std::ostream &os, const message& msg) override{struct tm time;localtime_r((time_t*)&msg._time,&time);char str[32];strftime(str,sizeof(str)-1,_fromat.c_str(),&time);os<<str;}private:std::string _fromat;//用來控制輸出格式};//縮進子類class TabFormatlem : public Formatlem{public:void format(std::ostream &os, const message& msg) override{os<<"\t";}};//線程id子類class ThreadFormatlem : public Formatlem{public:void format(std::ostream &os, const message& msg) override{os<<msg._id;}};//日志級別子類class LevelFormatlem : public Formatlem{public:void format(std::ostream &os, const message& msg) override{os<<LogLevel::LeveltoString(msg._level);}};//日志器名稱子類class NameFormatlem : public Formatlem{public:void format(std::ostream &os, const message& msg) override{os<<msg._logger;}};//文件名子類class CFileFormatlem : public Formatlem{public:void format(std::ostream &os, const message& msg) override{os<<msg._filename;}};//行號子類class CLineFormatlem : public Formatlem{public:void format(std::ostream &os, const message& msg) override{os<<msg._line;}};//日志消息主體子類class MsgFormatlem : public Formatlem{public:void format(std::ostream &os, const message& msg) override{os<<msg._msg;}};//換行子類class NLineFormatlem : public Formatlem{public:void format(std::ostream &os, const message& msg) override{os<<"\n";}};//其他字符子類,直接原路返回class OtherFormatlem : public Formatlem{public:OtherFormatlem(std::string str):_str(str){}void format(std::ostream &os, const message& msg) override{os<<_str;}private:std::string _str;};//格式化類class Formatter{/*%d 日期%T 縮進%t 線程id%p 日志級別%c 日志器名稱%f 文件名%l 行號%m 日志消息%n 換行*/public://默認格式:時間{年-月-日 時:分:秒}縮進 線程ID 縮進 [日志級別] 縮進 [日志器名稱] 縮進 文件名:行號 縮進 消息換行Formatter(std::string pattern="[%d{%H:%M:%S}]%T[%t]%T[%p]%T[%c]%T[%f:%l]%T%n"):_pattern(pattern){}//對msg進行格式化nvoid format(std::ostream& os,const message& msg)//將格式化后的內容寫入os執行流{if(AnalyPattern()){for(auto& it:_items){it->format(os,msg);}}}std::string format(const message& msg)//將格式化后的內容以string方式返回{std::stringstream str;if(AnalyPattern()){for(auto& it:_items){it->format(str,msg);}}return str.str();}//對格式化字符串進行分析bool AnalyPattern(){//遍歷_parttern進行逐一分析int cur=0;std::string key="",val="";//"abc[%%d{%H:%M:%S}]"while(cur<_pattern.size()){//先排查非格式化字符,如abcif(_pattern[cur]!='%'){val+=_pattern[cur++];//特殊情況:"aaaa[%%d{%H:%M:%S}]"if(cur==_pattern.size()){_items.push_back(createItem(key,val));}continue;}//到這一步,說明碰到%,這是需要排除"%[" "%%"等情況//"%["//if(_pattern[cur]=='%'&&_pattern[cur+1]=='%')if(_pattern[cur]=='%'&&(!isalpha(_pattern[cur+1]))){val+=_pattern[cur++];//特殊情況:"aaaa[%%d{%H:%M:%S}%"/* if(cur==_pattern.size()){_items.push_back(createItem(key,val));} */continue;}//此時,key為空,val中全是非格式化字符字符//不過也有可能val中沒有任何字符if(!val.empty()) _items.push_back(createItem(key,val));key.clear();val.clear();//cur+1==_pattern.size()if(cur+1==_pattern.size()){std::cout<<"格式化字符關鍵字%后數據錯誤"<<std::endl;return false;}//到這一步,說明目前cur指向%,且cur+1指向的為一個字母字符cur=cur+1;key+=_pattern[cur++];//"abc[%%d{%H:%M:%S}]",此時cur指向d后面的{//因此,這時候我們需要判斷后面是否是子格式化字符if(cur<_pattern.size()&&_pattern[cur]=='{'){cur++;while(cur<_pattern.size()&&_pattern[cur]!='}'){val+=_pattern[cur++];}//出while循環有下面兩種可能//1.cur==_pattern.size(),說明沒有找到'}',說明這是非法子格式化字符if(cur==_pattern.size()){std::cout<<"非法子格式化字符...."<<std::endl;abort();}//2._pattern[cur]=='}'_items.push_back(createItem(key,val));key.clear();val.clear();//此時cur指向},因此進入下一個循環前cur應該++cur++;}else{_items.push_back(createItem(key,val));key.clear();val.clear();}}return true;}private://根據不同的格式創建不同的格式化子類對象//key用來存儲格式化字符,val用來存儲格式化字符子字符如[%d{%H:%M:%S}]std::shared_ptr<Formatlem> createItem(const std::string& key,const std::string& val){if(key=="d") return Formatlem::ptr(new TimeFormatlem(val));if(key=="T") return Formatlem::ptr(new TabFormatlem());if(key=="p") return Formatlem::ptr(new LevelFormatlem());if(key=="t") return Formatlem::ptr(new ThreadFormatlem());if(key=="c") return Formatlem::ptr(new NameFormatlem());if(key=="f") return Formatlem::ptr(new CFileFormatlem());if(key=="l") return Formatlem::ptr(new CLineFormatlem());if(key=="n") return Formatlem::ptr(new NLineFormatlem());//當key為空時,則說明val里存儲的是非格式化化字符,如abcdif(key.empty()) return Formatlem::ptr(new OtherFormatlem(val));//還有一種情況,就是key中存儲的不是設定的格式字符,如%gstd::cout<<"沒有該格式化字符:%"<<key<<std::endl;abort();return nullptr;}private:std::string _pattern;std::vector<Formatlem::ptr> _items;};
}#endif

3.1 測試

?

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/41834.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/41834.shtml
英文地址,請注明出處:http://en.pswp.cn/news/41834.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

WPF 界面結構化處理

文章目錄 概要一、xaml界面結構化處理二、邏輯樹與視覺樹 概要 WPF 框架是開源的&#xff0c;但是不能跨平臺&#xff0c;可以使用MAUI&#xff0c;這個框架可以跨平臺&#xff0c;WPF源碼可以在github上下載&#xff0c;下載地址&#xff1a;https://gitbub.com/dotnet/wpf。…

【C++ 記憶站】命名空間

文章目錄 命名空間概念命名空間的定義1、正常的命名空間定義2、命名空間可以嵌套3、同一個工程中允許存在多個相同名稱的命名空間,編譯器最后會合成同一個命名空間中 命名空間的使用1、加命名空間名稱及作用域限定符2、使用using將命名空間中某個成員引入3、使用using namespac…

初試時間官宣!研招網發布下半年重要時間節點!今日速報來了

距24考研初試還有127天&#xff0c;今天給大家帶來初試和報名時間官宣消息、考研報名注意事項、研招網發布的2024考研“保姆級”下半年重要時間節點。有用記得收藏 24考研報名和初試時間官宣 已有學校在招生簡章中明確24考研初試時間 初試時間預計為&#xff1a;2023年12月23…

初試rabbitmq

rabbitmq的七種模式 Hello word 客戶端引入依賴 <!--rabbitmq 依賴客戶端--><dependency><groupId>com.rabbitmq</groupId><artifactId>amqp-client</artifactId><version>5.8.0</version></dependency> 生產者 imp…

邀請函|澎峰科技邀您參加CCF HPC China2023

一年一度的全球超算盛會&#xff01; 以“算力互聯智領未來”為主題的第十九屆全國高性能計算學術年會&#xff08;CCF HPC China 2023&#xff09;將于8月24-26日&#xff08;展覽23-25日&#xff09;在青島紅島國際會議展覽中心舉辦。 九大院士領銜 打造頂級超算盛會 力邀…

《離散數學及其應用(原書第8版)》ISBN978-7-111-63687-8 第11章 11.1.3 樹的性質 節 第664頁的例9說明

《離散數學及其應用&#xff08;原書第8版&#xff09;》ISBN978-7-111-63687-8 第11章 11.1.3 樹的性質 節 第664頁的定理3的引申 定理3 帶有i個內點的m叉樹含有nmi1個頂點 見本人博文 內點定義不同的討論 如果對于一個m叉正則樹&#xff0c;即任意分支節點的兒子恰好有m個&am…

談談IP地址和子網掩碼的概念及應用

個人主頁&#xff1a;insist--個人主頁?????? 本文專欄&#xff1a;網絡基礎——帶你走進網絡世界 本專欄會持續更新網絡基礎知識&#xff0c;希望大家多多支持&#xff0c;讓我們一起探索這個神奇而廣闊的網絡世界。 目錄 一、IP地址的概念 二、IP地址的分類 1、A類 …

長勝證券:散戶可以隨大流嗎?怎么做才好?

在我國的股市里邊&#xff0c;最不缺的或許便是散戶了&#xff0c;一方面&#xff0c;散戶促進了股市的活潑&#xff0c;可一方面又特容易望風而動&#xff0c;追漲殺跌。因此&#xff0c;散戶能夠隨大流嗎&#xff1f;該怎么做才好&#xff1f;對于這些&#xff0c;長勝證券為…

IntelliJ IDEA熱部署:JRebel插件的安裝與使用

熱部署 概述JRebel 概述 熱部署&#xff0c;指修改代碼后&#xff0c;無需停止應用程序&#xff0c;即可使修改后的代碼生效&#xff0c;其有利于提高開發效率。 熱部署方式&#xff1a; 手動熱部署&#xff1a;修改代碼后&#xff0c;重新編譯項目&#xff0c;然后啟動應用程…

Springboot項目啟動后按順序加載自定義類 (demo)

1. 實現ApplicationRunner接口, 重寫run方法 import lombok.extern.slf4j.Slf4j; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.core.annotation.Order; import org.springframewor…

IDEA啟動報錯java.nio.charset.MalformedInputException: Input length=2

IDEA啟動報錯java.nio.charset.MalformedInputException: Input length2 問題解決后記 問題 原本系統運行好好得&#xff0c;一段時間沒打開&#xff0c;再次打開重啟 IDEA啟動報錯java.nio.charset.MalformedInputException: Input length2。 解決 百度了 https://blog.csd…

使用 Qt 生成 Word 和 PDF 文檔的詳細教程

系列文章目錄 文章目錄 系列文章目錄前言一、安裝 Qt二、生成 Word 文檔三、生成 PDF 文檔四、運行代碼并查看結果五、自定義文檔內容總結前言 Qt 是一個跨平臺的應用程序開發框架,除了用于創建圖形界面應用程序外,還可以用來生成 Word 和 PDF 文檔。本文將介紹如何使用 Qt …

【C語言】const修飾普通變量和指針

大家好&#xff0c;我是蘇貝&#xff0c;本篇博客帶大家了解const修飾普通變量和指針&#xff0c;如果你覺得我寫的還不錯的話&#xff0c;可以給我一個贊&#x1f44d;嗎&#xff0c;感謝?? 文章目錄 一.const修飾普通變量二.const修飾指針1.const 放在 * 左邊2.const 放在…

git commit用法

git commit 是 Git 版本控制系統中的一個命令&#xff0c;用于將更改提交到本地存儲庫。以下是 git commit 的一些常見用法和選項&#xff1a; 基本用法: git commit -m "提交信息"使用 -m 選項可以直接在命令行中添加提交信息。 提交所有更改: git commit -a -m &q…

設計模式-簡單工廠模式

簡單工廠模式又稱為靜態工廠模式&#xff0c;其實就是根據傳入參數創建對應具體類的實例并返回實例對象&#xff0c;這些類通常繼承至同一個父類&#xff0c;該模式專門定義了一個類來負責創建其他類的實例。 using System.Collections; using System.Collections.Generic; us…

Nacos - 安裝指南(Windows系統)

一、下載安裝包 Nacos現在雖然已經出到二點幾的版本&#xff0c;但二點幾版本還處在測試階段&#xff0c;我們選擇下載成熟的 1.4.6 版本 下載地址&#xff1a;Nacos 1.4.6 GitHub的Release下載頁 拉到頁面最底部&#xff0c;可以看到下載按鈕&#xff0c;windows版本使用naco…

htmlCSS-----彈性布局

目錄 前言 什么是彈性布局 樣式 學習概要 容器和項目 彈性布局的排列方式 1.橫向排列&#xff08;默認樣式&#xff09; 2.父元素容器的屬性&#xff08;*5&#xff09; &#xff08;1&#xff09;主軸 代碼示例&#xff1a; &#xff08;2&#xff09;交叉軸 3.子元素…

正則表達式試煉

序 我希望在這里列出我很多想寫的正則表達式&#xff0c;很多我想寫&#xff0c;但是不知道怎么寫的。分享點滴案例。未來這個文章會越來越長 前言 互聯網時代&#xff0c;除了文本還有更好的學習方式&#xff0c;下面是幾個不錯的練習網站&#xff0c;如果你想系統地學習&a…

[Flutter]有的時候調用setState(() {})報錯?

先看FlutterSDK的原生類State中有一個變量mounted。 abstract class State<T extends StatefulWidget> with Diagnosticable {/// mounted的作用是&#xff0c;此State對象當前是否在樹中。/// 在創建State對象之后&#xff0c;在調用initState之前&#xff0c;框架通過…

【Linux】【驅動】應用層和驅動層傳輸數據

【Linux】【驅動】應用層和驅動層傳輸數據 緒論1.如果我在應用層使用系統0 對設備節點進行打開&#xff0c;關閉&#xff0c;讀寫等操作會發生什么呢? 2 我們的應用層和內核層是不能直接進行數據傳輸的3 驅動部分的代碼4 應用代碼5 編譯以及運行代碼 緒論 Linux一切皆文件! 文…