大量項目在使用logback記日誌,有部分項目使用日誌混亂,格式不統一,多數人搞不懂配置文件,致使配置錯誤,如今須要開發一套統一的、少配置的日誌組件,使用方便。java
儘可能採用0配置,無logback.xmlredis
日誌格式統一,方便後續日誌分析系統spring
只有兩個日誌級別,一個是正常日誌,一個是異常日誌json
提供log4j、jcl、logback、commons-log等橋接方案及版本兼容方案api
提子線程、json格式化輸出、map格式化、數組格式化、請求響應參數(供耗時)等便捷日誌輸出方法數組
支持redis、db、http自動開關配置**app
api採用流式結構,相似StringBuffermaven
調研代碼ui
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配置。
約定固定將日誌輸出到,相對路徑log/xxx.yyyy-MM-dd-HH.log,其中xxx爲logger的name
格式固定:
MMddHHmmss.SSS||id||【交易名★子步驟】||context ||level
例:
150000.311||N-XrUTQzIc1531897200311||【CiTeeFilter★ci攔截器】||ci攔截器 請求的完整參數爲:{"merchantId":["0012444"],"userId":["13112341232"]} ||INFO
固定格式的核心代碼,攔截到日誌請求,按照格式拼裝,主要方法爲繼承ThrowableProxyConverter和MessageConverter來實現對日誌的攔截,並修改成想要的格式,其中使用的例如id等放到本地變量內,核心是對MDC的使用
全部日誌都默認輸出到這裏 logger name:service 系統初始化時,定義這個Logger和appender,即這個Logger爲root log
提供addLogger方法,參數 packageName 包名,例如:com.test 必輸參數 若是name未設置時,name默認爲包名最後一個.後面的字符 name 名字,決定日誌文件的名字 非必輸 path 日誌路徑 非必輸 additivity 是否輸出到root log內
特殊的log
提供特殊組件的log配置,例如: redis 默認ERROR http 默認ERROR db鏈接池 默認ERROR kafka 默認ERROR schedul 默認ERROR spring 默認ERROR
提供exception異常棧格式打印 提供帶換行的格式化打印 代碼思路:繼承ThrowableProxyConverter,獲取異常棧,在每行的前面插入固定格式文本
方法 | 方法描述 |
---|---|
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級別日誌,不建議使用 |
平時記日誌時,若是某個類沒有時間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格式化日誌 |
方法 | 方法描述 |
---|---|
getLogger() | 獲取logger,用於記日誌 |
getLogger(name) | 經過name獲取logger |
addLogger() | 參考自定義Logger,若是logger已經建立,則再也不建立,通常不使用,除非想自定義日誌名等 |
consoleOpen() | 打開控制檯日誌,系統啓動時默認配置控制檯日誌 |
commonOpen(name, level) | 默認的組件都是error級別,這個方法能夠變動日誌級別,例如redis http等 |
map:即轉化爲json,而後再格式化
collection:同上
array:也同上
object:同上
一、密碼脫敏、加解密有必要單獨提取方法嗎
二、提供父線程打印開關
<dependency> <groupId>com.cdc.ecliptic</groupId> <artifactId>virgo</artifactId> <version>1.5_1.6-SNAPSHOT</version> </dependency>
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<String, String> 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); // } }