日志打印規(guī)范及技巧學(xué)習(xí)總結(jié)

一、日志打印級別

  • DEBUG(調(diào)試)
    開發(fā)調(diào)試日志。一般來說,在系統(tǒng)實際運行過程中,不會輸出該級別的日志。因此,開發(fā)人員可以打印任何自己覺得有利于了解系統(tǒng)運行狀態(tài)的東東。不過很多場景下,過多的DEBUG日志,并不是好事,建議是按照業(yè)務(wù)邏輯的走向打印。
  • INFO(通知)
    INFO日志級別主要用于記錄系統(tǒng)運行狀態(tài)等關(guān)聯(lián)信息。該日志級別,常用于反饋系統(tǒng)當前狀態(tài)給最終用戶。所以,在這里輸出的信息,應(yīng)該對最終用戶具有實際意義,也就是最終用戶要能夠看得明白是什么意思才行。
  • WARN(警告)
    WARN日志常用來表示系統(tǒng)模塊發(fā)生問題,但并不影響系統(tǒng)運行。 此時,進行一些修復(fù)性的工作,還能把系統(tǒng)恢復(fù)到正常的狀態(tài)。
  • ERROR(錯誤)
    此信息輸出后,主體系統(tǒng)核心模塊正常工作,需要修復(fù)才能正常工作。 就是說可以進行一些修復(fù)性的工作,但無法確定系統(tǒng)會正常的工作下去,系統(tǒng)在以后的某個階段,很可能會因為當前的這個問題,導(dǎo)致一個無法修復(fù)的錯誤(例如宕機),但也可能一直工作到停止也不出現(xiàn)嚴重問題。

二、日志打印規(guī)范

1. 【強制】應(yīng)用中不可直接使用日志系統(tǒng) (Log 4 j 、 Logback) 中的 API ,而應(yīng)依賴使用日志框架
SLF 4 J 中的 API ,使用門面模式的日志框架,有利于維護和各個類的日志處理方式統(tǒng)一。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger logger = LoggerFactory.getLogger(Abc.class);
  1. 【強制】日志文件推薦至少保存 15 天,因為有些異常具備以“周”為頻次發(fā)生的特點。

可以結(jié)合實際業(yè)務(wù)需求,基于按天,和按照容量配置appender。例如,按天保存接口對接基本關(guān)鍵數(shù)值記錄日志,按照容量保存接口對接詳細日志。

  1. 【強制】應(yīng)用中的擴展日志 ( 如打點、臨時監(jiān)控、訪問日志等 )
  • 命名方式:appName _ logType _ logName . log 。
  • 日志類型( logType),推薦分類有stats / desc / monitor / visit 等。
  • 日志描述(logName)。
    這種命名的好處:通過文件名就可知道日志文件屬于什么應(yīng)用,什么類型,什么目的,也有利于歸類查找。推薦對日志進行分類,如將錯誤日志和業(yè)務(wù)日志分開存放,便于開發(fā)人員查看,也便于通過日志對系統(tǒng)進行及時監(jiān)控。
    正例: mppserver 應(yīng)用中單獨監(jiān)控時區(qū)轉(zhuǎn)換異常,如:mppserver _ monitor _ timeZoneConvert . log
  1. 【強制】對 trace / debug / info 級別的日志輸出,必須使用條件輸出形式或者使用占位符的方式。
    說明: logger . debug( " Processing trade with id : " + id + " and symbol : " + symbol)。如果日志級別是 warn ,上述日志不會打印,但是會執(zhí)行字符串拼接操作,如果 symbol 是對象,會執(zhí)行 toString() 方法,浪費了系統(tǒng)資源,執(zhí)行了上述操作,最終日志卻沒有打印。
    正例: ( 占位符 )
    logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol);
  1. 【強制】避免重復(fù)打印日志,浪費磁盤空間,務(wù)必在 log 4 j . xml 中設(shè)置 additivity = false 。
    正例: <logger name="com.taobao.dubbo.config" additivity="false">
  1. 【強制】異常信息應(yīng)該包括兩類信息:案發(fā)現(xiàn)場信息和異常堆棧信息。如果不處理,那么通過關(guān)鍵字 throws 往上拋出。
    正例: logger.error(各類參數(shù)或者對象 toString + "_" + e.getMessage(), e);
  1. 【推薦】謹慎地記錄日志。生產(chǎn)環(huán)境禁止輸出 debug 日志 ; 有選擇地輸出 info 日志 ; 如果使用 warn 來記錄剛上線時的業(yè)務(wù)行為信息,一定要注意日志輸出量的問題,避免把服務(wù)器磁盤撐爆,并記得及時刪除這些觀察日志。
    說明:大量地輸出無效日志,不利于系統(tǒng)性能提升,也不利于快速定位錯誤點。記錄日志時請思考:這些日志真的有人看嗎?看到這條日志你能做什么?能不能給問題排查帶來好處?
  1. 【參考】可以使用 warn 日志級別來記錄用戶輸入?yún)?shù)錯誤的情況,避免用戶投訴時,無所適從。注意日志輸出的級別, error 級別只記錄系統(tǒng)邏輯出錯、異常等重要的錯誤信息。如非必要,請不要在此場景打出 error 級別。

三、日志打印技巧

問題排查的日志

  • 對接外部的調(diào)用封裝
    程序中對接外部系統(tǒng)與模塊的依賴調(diào)用前后都記下日志,方便接口調(diào)試。出問題時也可以很快理清是哪塊的問題
LOG.debug("Calling external system:" + parameters);  
Object result = null;  
try {  
    result = callRemoteSystem(params);  
    LOG.debug("Called successfully. result is " + result);  
} catch (Exception e) {  
    LOG.warn("Failed at calling xxx system . exception : " + e);  
}  
  • 狀態(tài)變化:
    程序中重要的狀態(tài)信息的變化應(yīng)該記錄下來,方便查問題時還原現(xiàn)場,推斷程序運行過程
boolean isRunning = true;  
LOG.info("System is running");  
//...  
isRunning = false;  
LOG.info("System was interrupted by " + Thread.currentThread().getName()); 
  • 系統(tǒng)入口與出口:
這個粒度可以是重要方法級或模塊級。記錄它的輸入與輸出,方便定位 
void execute(Object input) {  
    LOG.debug("Invoke parames : " + input);  
    Object result = null;  
      
    //business logical  
      
    LOG.debug("Method result : " + result);  
}  
  • 業(yè)務(wù)異常:
    任何業(yè)務(wù)異常都應(yīng)該記下來
try {  
    //business logical  
} catch (IOException e) {  
    LOG.warn("Description xxx" , e);  
} catch (BusinessException e) {  
    LOG.warn("Let me know anything",e);  
} catch (Exception e) {  
    LOG.error("Description xxx", e);  
}  
  
void invoke(Object primaryParam) {  
    if (primaryParam == null) {  
        LOG.warn(原因...);  
        return;  
    }  
} 
  • 非預(yù)期執(zhí)行:
    為程序在“有可能”執(zhí)行到的地方打印日志。如果我想刪除一個文件,結(jié)果返回成功。但事實上,那個文件在你想刪除之前就不存在了。最終結(jié)果是一致的,但程序得讓我們知道這種情況,要查清為什么文件在刪除之前就已經(jīng)不存在呢
int myValue = xxxx;  
int absResult = Math.abs(myValue);  
if (absResult < 0) {  
    LOG.info("Original int " + myValue + "has nagetive abs " + absResult);  
}  
  • 很少出現(xiàn)的else情況:
    else可能吞掉你的請求,或是賦予難以理解的最終結(jié)果
Object result = null;  
if (running) {  
   result = xxx;  
} else {  
   result = yyy;  
   LOG.debug("System does not running, we change the final result");  
}  

程序運行狀態(tài)的日志

程序在運行時就像一個機器人,我們可以從它的日志看出它正在做什么,是不是按預(yù)期的設(shè)計在做,所以這些正常的運行狀態(tài)是要有的。

  • 程序運行時間:
long startTime = System.currentTime();  
  
// business logical  
  
LOG.info("execution cost : " + (System.currentTime() - startTime) + "ms");  

大批量數(shù)據(jù)的執(zhí)行進度:

LOG.debug("current progress: " + (currentPos * 100 / totalAmount) + "%"); 

關(guān)鍵變量及正在做哪些重要的事情:
執(zhí)行關(guān)鍵的邏輯,做IO操作等等

String getJVMPid() {  
   String pid = "";  
   // Obtains JVM process ID  
   LOG.info("JVM pid is " + pid);  
   return pid;  
}  
  
void invokeRemoteMethod(Object params) {  
    LOG.info("Calling remote method : " + params);  
    //Calling remote server  
} 

四、需要規(guī)避的問題

  • 頻繁打印大數(shù)據(jù)量日志:
    當日志產(chǎn)生的速度大于日志文件寫磁盤的速度,會導(dǎo)致日志內(nèi)容積壓在內(nèi)存中,導(dǎo)致內(nèi)存泄漏。

  • 無意義的Log:
    日志不包含有意義的信息: 你肯定想知道的是哪個文件不存在吧

File file = new File("xxx");  
if (!file.isExist()) {  
    LOG.warn("File does not exist"); //Useless message  
} 
  • 混淆信息的Log:
    日志應(yīng)該是清晰準確的: 當看到日志的時候,你知道是因為連接池取不到連接導(dǎo)致的問題么?
Connection connection = ConnectionFactory.getConnection();  
if (connection == null) {  
    LOG.warn("System initialized unsuccessfully");  
}  

參考:
《阿里巴巴開發(fā)手冊》
Logger日志級別說明及設(shè)置方法、說明
閑談程序中如何打印log

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 在應(yīng)用程序中添加日志記錄總的來說基于三個目的:監(jiān)視代碼中變量的變化情況,周期性的記錄到文件中供其他應(yīng)用進行統(tǒng)計分析...
    時待吾閱讀 5,214評論 1 13
  • 在應(yīng)用程序中添加日志記錄總的來說基于三個目的:監(jiān)視代碼中變量的變化情況,周期性的記錄到文件中供其他應(yīng)用進行統(tǒng)計分析...
    時待吾閱讀 5,153評論 0 6
  • idea 添加注釋/** 然后回車 選中代碼塊 Ctrl+Shift+/ 重點推薦閱讀:https://www....
    Helen_Cat閱讀 20,460評論 0 37
  • From:Python之日志處理(logging模塊) - 云游道士 - 博客園 https://www.cnbl...
    vigny的先生閱讀 2,796評論 3 5
  • 程序員的日常離不開日志,日志就好比私人秘書,負責(zé)運行周期一切trace工作。優(yōu)秀的日志實踐能極大幫助地程序員快速定...
    Java架構(gòu)閱讀 938評論 0 3

友情鏈接更多精彩內(nèi)容