上期咱們分享了Java中日誌的處理(上):Java中日誌的相關知識、Slf4j的原理及源碼分析java
本期咱們將分享Java中日誌的處理(下)git
分析:github
- 若是使用的是
Log4j
,且採用的RollingFileAppender
方式, 經過設置maxBackupIndex
屬性來指定要保留的日誌文件數的最大值能夠間接實現刪除N天前的日誌文件- 若是使用的是
Log4j
,且採用的DailyRollingFileAppender
方式,因爲該方式不支持maxBackupIndex
,須要從新實現DailyRollingFileAppender
,用以支持maxBackupIndex
的設置- 若是使用的是
Logback
,能夠經過設置maxHistory
實現刪除N天前的日誌
3.【強制】應用中的擴展日誌(如打點、臨時監控、訪問日誌等)命名方式: appName_logType_logName.log。logType:日誌類型,推薦分類有stats/desc/monitor/visit 等;logName:日誌 述。這種命名的好處:經過文件名就可知道日誌文件屬於什麼應用,什麼類型,什麼目的,也有利於歸類查找。 正例:mppserver應用中單獨監控時區轉換異常,如: mppserver_monitor_timeZoneConvert.log 說明:推薦對日誌進行分類,如將錯誤日誌和業務日誌分開存放,便於開發人員查看,也便於 經過日誌對系統進行及時監控。web
4.【強制】對trace/debug/info級別的日誌輸出,必須使用條件輸出形式或者使用佔位符的方 式。 說明:logger.debug("Processing trade with id: " + id + " and symbol: " + symbol); 若是日誌級別是warn,上述日誌不會打印,可是會執行字符串拼接操做,若是 symbol是對象, 會執行toString()方法,浪費了系統資源,執行了上述操做,最終日誌卻沒有打印。tomcat
正例:(條件)服務器
if (logger.isDebugEnabled()) {
logger.debug("Processing trade with id: " + id + " and symbol: " + symbol);
}
複製代碼
正例:(佔位符)微信
logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol);
複製代碼
分析:多線程
- 正如上篇分析的,推薦全部使用
Slf4j
,打印日誌統一使用佔位符
,且不需判讀isxxxEnabled()
<logger name="com.taobao.dubbo.config" additivity="false">
複製代碼
logger.error(各種參數或者對象 toString + "_" + e.getMessage(), e);
複製代碼
public final class LogIdThreadLocal {
private static ThreadLocal<String> logIdThreadLocal = new ThreadLocal<String>();
...
}
public class MyPatternLayout extends PatternLayout {
private static final String SPLIT_STRING = "|";
@Override
public String format(LoggingEvent event) {
String log = super.format(event);
String threadLocalId = LogIdThreadLocal.getLogId();
if (StringUtils.isEmpty(threadLocalId)) {
threadLocalId = LogIdThreadLocal.create();
}
return log + threadLocalId + SPLIT_STRING + event.getMessage() + Layout.LINE_SEP;
}
}
複製代碼
log4j.appender.output.layout=com.test.log.MyPatternLayout
log4j.appender.output.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss:SSS}|%t|%-5p|%C{1}.%M:%L|
複製代碼
對於生產環境,默認的日誌級別多是error/warning/info,對於debug的日誌就沒有打出來,若是要讓debug日誌能打印出來,那麼常見的方法就是修改log4j.xml或者log4j.properties文件,修改了以後須要重啓tomcat,咱們知道,生產環境是不可能隨隨便便重啓的,那麼有沒有其餘方法呢?答案是:有。 Log4j爲咱們提供了這樣的API,經過調用Log4j的API,提供rest接口,使得客戶端能夠動態修改某個日誌的級別:app
private String changeLoggerLevel(String loggerName, String level) {
Logger logger = LogManager.exists(loggerName);
String result = null;
if (logger != null) {
logger.setLevel(Level.toLevel(level));
result = logger.getName() + "|" + logger.getLevel();
} else {
result = "logger not exist.";
}
return result;
}
複製代碼
此外,推薦一個開源的第三方組件:Log4j Web Track(連接爲Github地址),以下圖:ide
相關配置:
<servlet>
<servlet-name>TrackerServlet</servlet-name>
<servlet-class>log4jwebtracker.servlet.TrackerServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>TrackerServlet</servlet-name>
<url-pattern>/tracker/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>Log4jInitServlet</servlet-name>
<servlet-class>log4jwebtracker.servlet.init.Log4jInitServlet</servlet-class>
<init-param>
<param-name>log4jConfigLocation</param-name>
<param-value>WEB-INF/classes/log4j.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
複製代碼
經過閱讀源碼,其也是調用了Log4j的API,進行了展現:
public abstract class LoggingUtils {
static synchronized public List getFileAppenders() {
List list = new ArrayList();
Enumeration e = LogManager.getRootLogger().getAllAppenders();
while(e.hasMoreElements()) {
Appender a = (Appender) e.nextElement();
if(a instanceof FileAppender) {
list.add(a);
}
}
return list;
}
static synchronized public FileAppender getFileAppender(String appenderName) {
Enumeration e = LogManager.getRootLogger().getAllAppenders();
while(e.hasMoreElements()) {
Appender a = (Appender) e.nextElement();
if(a instanceof FileAppender && a.getName().equals(appenderName)) {
return (FileAppender) a;
}
}
return null;
}
static public boolean contains(List loggers, String loggerName) {
int i=0;
while(i<loggers.size()) {
if(((Logger)loggers.get(i)).getName().equals(loggerName)) {
return true;
}
i++;
}
return false;
}
static public List getLoggers() {
Enumeration e = LogManager.getCurrentLoggers();
List loggersList = new LinkedList();
while(e.hasMoreElements()) {
loggersList.add(e.nextElement());
}
Collections.sort(loggersList, new Comparator() {
public int compare(Object arg0, Object arg1) {
Logger log0 = (Logger) arg0;
Logger log1 = (Logger) arg1;
return log0.getName().compareTo(log1.getName());
}
});
loggersList.add(0, LogManager.getRootLogger());
return loggersList;
}
}
複製代碼
若是有興趣的話,咱們能夠實現一個Web Tracker的門面,相似於Slf4j,那麼對於Log4j1/二、LogBack、Juc、Commons Logging的日誌都能實現可視化以及動態修改日誌級別的功能