demo演示如何寫一個無配置格式統一的日誌
一、背景
大量專案在使用logback記日誌,有部分專案使用日誌混亂,格式不統一,多數人搞不懂配置檔案,導致配置錯誤,現在需要開發一套統一的、少配置的日誌元件,方便使用。
二、設計思路
儘量採用0配置,無logback.xml
日誌格式統一,方便後續日誌分析系統
只有兩個日誌級別,一個是正常日誌,一個是異常日誌
提供log4j、jcl、logback、commons-log等橋接方案及版本相容方案
提子執行緒、json格式化輸出、map格式化、陣列格式化、請求響應引數(供耗時)等便捷日誌輸出方法
支援redis、db、http自動開關配置****
新增日誌型別(logger)
api採用流式結構,類似StringBuffer
三、概要設計
1、零配置
調研程式碼
java static LoggerContext lc; static { lc = (LoggerContext) LoggerFactory.getILoggerFactory(); // 對應配置中的appender ConsoleAppender ca = new ConsoleAppender(); ca.setContext(lc); ca.setName("console"); // 格式 PatternLayoutEncoder pl = new PatternLayoutEncoder(); pl.setContext(lc); pl.setPattern("%d{MMddHHmmss.SSS} [%thread] %-5level %logger{36} - %msg%n"); pl.start(); ca.setEncoder(pl); ca.start(); // 對應配置中的logger ch.qos.logback.classic.Logger rootLogger = lc.getLogger("com.test"); rootLogger.addAppender(ca);}
上面程式碼等價於下面的xml
%d{MMddHHmmss.SSS} [%thread] %-5level %logger{36} - %msg%n
由此可以隨意把配置檔案中的內容以程式碼形式編寫,理論已經可以實現0配置。
2、輸出路徑
約定固定將日誌輸出到,相對路徑log/xxx.yyyy-MM-dd-HH.log,其中xxx為logger的name
3、日誌格式
格式固定: MMddHHmmss.SSS||id||【交易名★子步驟】||context ||[level][執行緒號] 例: 150000.311||N-XrUTQzIc1531897200311||【CiTeeFilter★ci攔截器】||ci攔截器 請求的完整引數為:{"merchantId":["0012444"],"userId":["13112341232"]} ||[INFO][http-8091-7]
固定格式的核心程式碼,攔截到日誌請求,按照格式拼裝,主要方法為繼承ThrowableProxyConverter和MessageConverter來實現對日誌的攔截,並修改為想要的格式,其中使用的例如id等放到本地變數內,核心是對MDC的使用
4、基礎logger
所有日誌都預設輸出到這裡 logger name:service 系統初始化時,定義這個Logger和appender,即這個Logger為root log
5、自定義的logger
提供addLogger方法,引數 packageName 包名,例如:com.test 必輸引數 如果name未設定時,name預設為包名最後一個.後面的字元 name 名字,決定日誌檔案的名字 非必輸 path 日誌路徑 非必輸 additivity 是否輸出到root log內
6、特殊的log
提供特殊元件的log配置,例如:redis 預設ERROR http 預設ERROR db連線池 預設ERROR kafka 預設ERROR schedul 預設ERROR spring 預設ERROR
7、異常、換行日誌處理
提供exception異常棧格式列印 提供帶換行的格式化列印 程式碼思路:繼承ThrowableProxyConverter,獲取異常棧,在每行的前面插入固定格式文字
8、普通日誌api(VirgoLog)
方法 | 方法描述 |
---|---|
setUniqKey(id) | 設定當前執行緒id,執行緒開始時設定即可,後面無需設定 |
updateStep(trade, step) | 更新當前id的步驟資訊 |
log(msg, param) | 記錄普通日誌,msg替換規則,普通替換為{},如果想替換為業務日誌api中的格式,使用``替換 |
logErr(msg, e) | 記錄異常日誌 |
log( trade, step, msg, param) | 記錄普通日誌,此方法會自動更新id、trade、step,不建議使用 |
logErr(trade, step, msg, e) | 記錄異常日誌 |
log(cid, trade, step, msg, param) | 記錄普通日誌,此方法會自動更新id、trade、step,不建議使用 |
logErr(cid, trade, step, msg, e) | 記錄異常日誌 |
debug(msg, param) | 記錄debug級別日誌,不建議使用 |
業務日誌api(VirgoLog)
平時記日誌時,如果某個類沒有時間toString方法,會無法正確列印出資料,此時提供替換方法,直接將object替換為json列印,核心程式碼思路為
MessageFormatter是處理{}替換的類,重新寫個類,稍加改動即支援{}也支援`` ,並判斷替換為json還是toString
api如下
方法 | 方法描述 |
---|---|
begin(msg) | 記錄開始 |
end(msg) | 記錄完成,會列印本執行緒內上一個begin到現在的耗時 |
logJson(json, format) | 記錄json格式化日誌,format表示是否換行 |
logMap(map, format) | 記錄map格式化日誌 |
logCollection(list, format) | 記錄集合格式化日誌 |
logArray(array, format) | 記錄陣列格式化日誌 |
logObjct(obj, format) | 記錄Object格式化日誌 |
系統api(LoggerHelper)
方法 | 方法描述 |
---|---|
getLogger() | 獲取logger,用於記日誌 |
getLogger(name) | 透過name獲取logger |
addLogger() | 參考自定義Logger,如果logger已經建立,則不再建立,一般不使用,除非想自定義日誌名等 |
consoleOpen() | 開啟控制檯日誌,系統啟動時預設配置控制檯日誌 |
commonOpen(name, level) | 預設的元件都是error級別,這個方法可以變更日誌級別,例如redis http等 |
9、特殊的格式化
map:即轉化為json,然後再格式化
collection:同上
array:也同上
object:同上
10、問題
-
密碼脫敏、加解密有必要單獨提取方法嗎
-
提供父執行緒列印開關
11、maven依賴
com.cdc.ecliptic virgo 1.5_1.6-SNAPSHOT
12、demo
public static void main(String[] args) throws InterruptedException { // 啟動 VirgoLancher.start("hahaha", "com.cdc.virgo", "D:/test/hahah.log"); LoggerHelper.commonOpen("hahaha", LogLevel.DEBUG); Logger logger1 = LoggerFactory.getLogger("druid"); // VirgoLancher.commonStart("abc", "com.cdc.virgo"); // 開啟控制檯 LoggerHelper.consoleOpen(); // 設定cid VirgoLog.setUniqKey(null); // 設定步驟名和交易名 VirgoLog.updateStep("adfa", "saf"); // 獲取Logger VirgoLog logger = VirgoLog.getLogger(); // 開啟debug級別(只有在開發階段可以開啟) // logger.changeLevel(LogLevel.DEBUG); // 記錄換行 logger.log("a"); logger1.info("dddddddddd"); logger1.error("dddddddddd"); // logger1.info("sfdasfaf" + // "\nafafdasfd" + // "\nasfdasf"); logger.log("sfdasfaf" + "\nafafdasfd" + "\nasfdasf"); // logger1.info("b"); // 正常日誌 // logger.log("我只有一行"); Map map = new HashMap(); map.put("asdf", "1"); map.put("asdf2", "2"); map.put("asdf3", "13"); map.put("asdf4", "14"); map.put("asdf5", "15"); map.put("asdf6", "16"); // // 異常日誌也支援格式化 // logger.logErr("我錯了:{},你沒錯:~~", new Exception("asdfsaflk"), "啊", map); // logger.log("----------------------------------------------"); // // {}替換普通物件,呼叫toString() ~~把物件轉換為json並且格式化輸出 ``把物件轉換為json不格式化輸出 logger.log("你好{},你是誰~~``,sd~xx {}", map, map, map, "tttt"); VirgoLog.updateStep("saf2"); // // 把物件轉換為json輸出 // logger.logJson(map, false); // // 更新步驟名和交易名 // VirgoLog.updateStep("bbbbb", "ccccc"); // // 耗時日誌列印 logger.begin("處理內容"); logger.begin("處理第二個"); logger.begin("處理第三個"); Thread.sleep(3000L); logger.end(); Thread.sleep(1000L); logger.end(); VirgoLog.updateStep("saf3"); logger.end(); // // 記錄debug日誌,一般除錯用 // logger.logDebug("jajajajaja"); // List l = new ArrayList(); // B b = new B(); // try { // b.b(); // } catch (Exception e) { // logger.logErr("woqu", e); // } }
作者:劉鵬飛
來源:宜信技術學院
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69918724/viewspace-2657884/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Logstash收集json格式日誌檔案如何寫配置檔案JSON
- 一個 JSer 的 Dart 學習日誌(六):寫一個向量JSDart
- 一種分散式預寫日誌系統分散式
- 從0寫一個Golang日誌處理包Golang
- Logstash 配置Java日誌格式的方法Java
- 寫一個簡單的demo理解vuexVue
- 如何實現一個高效的本地日誌收集程式
- 統一日誌管理
- 一個完整的go 日誌元件Go元件
- 上一個日誌的錯誤
- 【Java進階】利用APT優雅的實現統一日誌格式JavaAPT
- 參考 logviewer 重寫了一個日誌讀寫包View
- Laravel artisan 寫入日誌的使用者和 fpm 不一致,導致無法寫入日誌問題Laravel
- Kafka與ELK實現一個日誌系統Kafka
- flight-tracker-demo:一個Quarkus + Kafka演示原始碼專案Kafka原始碼
- 分享一個收集 Nginx 日誌的 ExporterNginxExport
- Linux日誌系統(一)Linux
- 【Mysql】一天一個慢日誌MySql
- 如何寫一個拖拽日曆元件(附原始碼)元件原始碼
- 一個不需要Log4Net的寫日誌的簡單方法
- 基於ThinkPHP5.0+GatewayWorker寫的一個聊天DEMOPHPGateway
- binlog日誌的格式
- 一個 JSer 的 Dart 學習日誌(一):函式JSDart函式
- 三個例項演示 Java Thread Dump 日誌分析Javathread
- log4js快速寫一個Node服務訪問日誌JS
- oracle日誌分析從列表中移去一個日誌檔案Oracle
- 自己寫了一個簡單的後置中介軟體統一格式
- C++的一個記日誌的程式碼C++
- 一個clean框架的demo框架
- PHPstrom 配置 Laravel Log 格式日誌高亮顯示PHPLaravel
- 配置Tomcat的訪問日誌格式化輸出Tomcat
- 【Nginx】如何配置Nginx日誌?這是最全面的一篇了!!Nginx
- 如何在多個應用程式中共享日誌配置
- 我的管理日誌【一】
- [awstats]一個基於perl的日誌分析工具
- 檢視pod下面某一個容器的日誌
- LogFX:JavaFX編寫一個漂亮、輕量級的日誌檢視器
- log4net寫入日誌檔案示例時一個奇怪的錯誤