平常的使用过程中我们经常需要使用日志打印,有些信息比如线程信息、时间戳、日志级别等都可以用一些默认规则很容易的使用。但是如果是一些自定义的信息可能就需要拓展一下了。
Logback 简单使用
1 2 3 4 5 6 7 8 9 10 11 12 13 package chapters.introduction;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class HelloWorld1 { public static void main (String[] args) { Logger logger = LoggerFactory.getLogger("chapters.introduction.HelloWorld1" ); logger.debug("Hello world." ); } }
20:49:07.962 [main] DEBUG chapters.introduction.HelloWorld1 - Hello world.
配置
1 2 3 4 5 6 7 8 9 10 11 12 <configuration > <appender name ="STDOUT" class ="ch.qos.logback.core.ConsoleAppender" > <encoder > <pattern > %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern > </encoder > </appender > <root level ="debug" > <appender-ref ref ="STDOUT" /> </root > </configuration >
1 2 3 4 5 6 7 8 9 10 11 12 package chapters.configuration; import org.slf4j.Logger;import org.slf4j.LoggerFactory; public class Foo { static final Logger logger = LoggerFactory.getLogger(Foo.class); public void doIt () { logger.debug("Did it again!" ); } }
16:06:09.031 [main] INFO chapters.configuration.MyApp1 - Entering application. 16:06:09.046 [main] DEBUG chapters.configuration.Foo - Did it again! 16:06:09.046 [main] INFO chapters.configuration.MyApp1 - Exiting application.
通过配置规则*%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n*来输出响应信息
logback主要由三块组成: Logger
, Appender
and Layout
Appender
负责把日志事件的任务写入
1 2 3 4 5 public interface Appender <E > extends LifeCycle , ContextAware , FilterAttachable { public String getName () ; public void setName (String name) ; void doAppend (E event) ; }
encoder
将事件转换为一个字节数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package ch.qos.logback.core.encoder;public interface Encoder <E > extends ContextAware , LifeCycle { void init (OutputStream os) throws IOException ; void doEncode (E event) throws IOException ; void close () throws IOException ; }
Layout
负责将传入的事件转换为一个字符串
1 2 3 4 5 6 7 8 9 public interface Layout <E > extends ContextAware , LifeCycle { String doLayout (E event) ; String getFileHeader () ; String getPresentationHeader () ; String getFileFooter () ; String getPresentationFooter () ; String getContentType () ; }
完全自定义layout LayoutBase 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <configuration > <appender name ="STDOUT" class ="ch.qos.logback.core.ConsoleAppender" > <encoder class ="ch.qos.logback.core.encoder.LayoutWrappingEncoder" > <layout class ="chapters.layouts.MySampleLayout2" > <prefix > MyPrefix</prefix > <printThreadName > false</printThreadName > </layout > </encoder > </appender > <root level ="DEBUG" > <appender-ref ref ="STDOUT" /> </root > </configuration >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 package chapters.layouts;import ch.qos.logback.classic.spi.ILoggingEvent;import ch.qos.logback.core.LayoutBase;public class MySampleLayout2 extends LayoutBase <ILoggingEvent > { String prefix = null ; boolean printThreadName = true ; public void setPrefix (String prefix) { this .prefix = prefix; } public void setPrintThreadName (boolean printThreadName) { this .printThreadName = printThreadName; } public String doLayout (ILoggingEvent event) { StringBuffer sbuf = new StringBuffer(128 ); if (prefix != null ) { sbuf.append(prefix + ": " ); } sbuf.append(event.getTimeStamp() - event.getLoggerContextVO().getBirthTime()); sbuf.append(" " ); sbuf.append(event.getLevel()); if (printThreadName) { sbuf.append(" [" ); sbuf.append(event.getThreadName()); sbuf.append("] " ); } else { sbuf.append(" " ); } sbuf.append(event.getLoggerName()); sbuf.append(" - " ); sbuf.append(event.getFormattedMessage()); sbuf.append(LINE_SEP); return sbuf.toString(); } }
PatternLayout Logback classic附带一个叫做PatternLayout灵活的布局。所有Layout,PatternLayout负责日志事件并返回一个字符串。这个字符串可以通过调整PatternLayout定制的转换模式。
你可以在转换模式里面插入任意文字,格式都是以百分号开头,括号括起来的。比如[%thread]
创建一个自定义转换说明符
继承ClassicConverter
1 2 3 4 5 6 7 8 9 10 public class MySampleConverter extends ClassicConverter { long start = System.nanoTime(); @Override public String convert (ILoggingEvent event) { long nowInNanos = System.nanoTime(); return Long.toString(nowInNanos-start); } }
声明转换文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <configuration> <conversionRule conversionWord="nanos" converterClass="chapters.layouts.MySampleConverter" /> <appender name="STDOUT" class ="ch.qos.logback.core.ConsoleAppender" > <encoder> <pattern>%-6nanos [%thread] - %msg%n</pattern> </encoder> </appender> <root level="DEBUG" > <appender-ref ref="STDOUT" /> </root> </configuration>
4868695 [main] DEBUG - Everything’s going well 5758748 [main] ERROR - maybe not quite…
另外一种方式
继承PatternLayout,默认转换说明符号多设置一条
1 2 3 4 5 public class TraceIdPatternLogbackLayout extends PatternLayout { static { defaultConverterMap.put("traceId" , LogbackPatternConverter.class.getName()); } }
继承ClassicConverter
1 2 3 4 5 6 public class LogbackPatternConverter extends ClassicConverter { @Override public String convert (ILoggingEvent iLoggingEvent) { return Strings.isNullOrEmpty(TraceUtil.getTraceId()) ? "N/A" : TraceUtil.getTraceId(); } }
配置自定义layout配置文件
1 2 3 4 5 6 7 <appender name ="STDOUT" class ="ch.qos.logback.core.ConsoleAppender" > <encoder class ="ch.qos.logback.core.encoder.LayoutWrappingEncoder" > <layout class ="com.absurd.logback.TraceIdPatternLogbackLayout" > <pattern > [%d{MM-dd HH:mm:ss.SSS}] [%traceId] [%thread] %-5level %logger[%M] - %msg%n</pattern > </layout > </encoder > </appender >
Log4j 简单使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import com.foo.Bar; import org.apache.log4j.Logger; import org.apache.log4j.BasicConfigurator; public class MyApp { static Logger logger = Logger.getLogger(MyApp.class); public static void main (String[] args) { BasicConfigurator.configure(); logger.info("Entering application." ); Bar bar = new Bar(); bar.doIt(); logger.info("Exiting application." ); } }
0 [main] INFO MyApp - Entering application. 36 [main] DEBUG com.foo.Bar - Did it again! 51 [main] INFO MyApp - Exiting application.
手动设置配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import com.foo.Bar;import org.apache.log4j.Logger;import org.apache.log4j.PropertyConfigurator;public class MyApp { static Logger logger = Logger.getLogger(MyApp.class.getName()); public static void main (String[] args) { PropertyConfigurator.configure(args[0 ]); logger.info("Entering application." ); Bar bar = new Bar(); bar.doIt(); logger.info("Exiting application." ); } }
屏蔽日志
1 2 3 4 5 6 7 8 9 log4j.rootLogger =DEBUG, A1 log4j.appender.A1 =org.apache.log4j.ConsoleAppender log4j.appender.A1.layout =org.apache.log4j.PatternLayout log4j.appender.A1.layout.ConversionPattern =%d [%t] %-5p %c - %m%n log4j.logger.com.foo =WARN
2000-09-07 14:07:41,508 [main] INFO MyApp - Entering application. 2000-09-07 14:07:41,529 [main] INFO MyApp - Exiting application.
多个appender
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 log4j.rootLogger =debug, stdout, R log4j.appender.stdout =org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout =org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern =%5p [%t] (%F:%L) - %m%n log4j.appender.R =org.apache.log4j.RollingFileAppender log4j.appender.R.File =example.log log4j.appender.R.MaxFileSize =100KB log4j.appender.R.MaxBackupIndex =1 log4j.appender.R.layout =org.apache.log4j.PatternLayout log4j.appender.R.layout.ConversionPattern =%p %t %c - %m%n
INFO [main] (MyApp2.java:12) - Entering application. DEBUG [main] (Bar.java:8) - Doing it again! INFO [main] (MyApp2.java:15) - Exiting application.
自定义
log4j-1.x
1 2 3 4 5 6 public class TraceIdPatternConverter extends PatternConverter { @Override protected String convert (LoggingEvent loggingEvent) { return Strings.isNullOrEmpty(TraceUtil.getTraceId()) ? "N/A" : TraceUtil.getTraceId(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class TraceIdPatternParser extends PatternParser { public TraceIdPatternParser (String pattern) { super (pattern); } @Override protected void finalizeConverter (char c) { if ('T' == c) { addConverter(new TraceIdPatternConverter()); } else { super .finalizeConverter(c); } } }
1 2 3 4 5 6 public class TraceIdPatternLayout extends PatternLayout { @Override protected PatternParser createPatternParser (String pattern) { return new TraceIdPatternParser(pattern); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 log4j.rootLogger=debug, stdout, R log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=com.absurd.log4j.TraceIdPatternLayout # Pattern to output the caller's file name and line number. log4j.appender.stdout.layout.ConversionPattern=%5p [%T] [%t] (%F:%L) - %m%n log4j.appender.R=org.apache.log4j.RollingFileAppender log4j.appender.R.File=trace.log log4j.appender.R.MaxFileSize=100KB # Keep one backup file log4j.appender.R.MaxBackupIndex=1 log4j.appender.R.layout=com.absurd.log4j.TraceIdPatternLayout log4j.appender.R.layout.ConversionPattern=%p [%T] %t %c - %m%n
INFO [1524824013684_bOcv][main] (TraceTest.java:44) - Entering application. INFO [1524824013684_bOcv][main] (TraceTest.java:45) - Exiting application.
log4j-2.x
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Plugin(name = "TraceIdConverter", category = "Converter") @ConverterKeys({"traceId"}) public class TraceIdConverter extends LogEventPatternConverter { protected TraceIdConverter (String name, String style) { super (name, style); } public static TraceIdConverter newInstance (String[] options) { return new TraceIdConverter("traceId" , "traceId" ); } @Override public void format (LogEvent event, StringBuilder toAppendTo) { Log4j2OutputAppender.append(toAppendTo); } }
1 2 3 4 5 6 public class Log4j2OutputAppender { public static void append (StringBuilder toAppendTo) { toAppendTo.append(Strings.isNullOrEmpty(TraceUtil.getTraceId()) ? "N/A" : TraceUtil.getTraceId()); } }
1 2 3 4 5 <Appenders > <Console name ="Console" target ="SYSTEM_OUT" > <PatternLayout pattern ="%d [%traceId] %-5p %c{1}:%L - %m%n" /> </Console > </Appenders >