@xtccc
2016-11-07T00:29:38.000000Z
字数 9074
阅读 4592
开发技巧
参考:
Log4j2是在Log4j的基础上演进而来的。
代码
package cn.gridx.log4j2.examplesimport org.apache.logging.log4j.LogManager;object FirstUsage {def main(args: Array[String]): Unit = {// 等价于 LogManager.getLogger(this.getClass)val logger = LogManager.getLogger()for (i <- 0 until 20) {logger.info("hello log4j2")logger.error("错误")logger.info("信息")logger.debug("好了")logger.trace("OK")}}}
依赖
dependencies {compile 'org.apache.logging.log4j:log4j-api:2.6.1','org.apache.logging.log4j:log4j-core:2.6.1'}
运行时也需要这两个依赖包
log4j2.prperties
status = inforootLogger.level = inforootLogger.appenderRef.console.ref = Console # 输出到控制台rootLogger.appenderRef.rolling.ref = RollingFile # 输出到rolling文件appender.console.type = Consoleappender.console.name = Consoleappender.console.layout.type = PatternLayoutappender.console.layout.pattern = %highlight{%-8p [%d{yyyy-MM-dd HH:mm:ss}] %C %t %L: %m%n} # highlight可以对日志分颜色高亮显示appender.rolling.type = RollingFileappender.rolling.name = RollingFileappender.rolling.fileName = mylogs/etl.logappender.rolling.filePattern = mylogs/etl-%d{yyyy-MM-dd}.log.%iappender.rolling.layout.type = PatternLayoutappender.rolling.layout.pattern = %-8p [%d{yyyy-MM-dd HH:mm:ss}] %C %t %L: %m%nappender.rolling.policies.type = SizeBasedTriggeringPolicyappender.rolling.policies.size=5MBappender.rolling.strategy.type = DefaultRolloverStrategyappender.rolling.strategy.max = 500
运行
java -cp \build/libs/log4j2-1.0-RELEASE.jar:./conf:jars/ \cn.gridx.log4j2.examples.FirstUsage
其中, 配置文件log4j2.prperties位于目录conf中,jars目录下则包含所需的依赖包。
配置文件的语法,与Log4J是不一样的,具体参考 Configuration with Properties
注意:配置文件log4j2.prperties必须位于classpath中,这里使用参数-cp指定的。不能直接写成配置文件的路径,而是要写成配置文件所在的目录,否则会报错 :
ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console
也可以不把配置文件放在classpath中,而是直接放在项目的resources目录下,让它存在于构件好的JAR包中。
SLF4J是一个facade,我们可以在代码中直接使用SLF4J的API,但是让实际的日志由Log4j2来处理。
使用方法很简单,在运行Java app时,将以下的几个包放入classpath中:
log4j-api-2.6.1.jar
log4j-core-2.6.1.jar
slf4j-api-1.7.21.jar
log4j-slf4j-impl-2.6.1.jar
可以参考 : Log4j 2 SLF4J Binding
这样,我们在需要输出日志时,只需要使用SLF4J的API即可:
val logger = LoggerFactory.getLogger(this.getClass)
使用additivity特性,我们可以把某个包下面的所有日志单独输出到一个指定的地方。
假设我们的需求是:
将属于
cn.gridx.log4j2.examples.additivity包的程序的日志输出到一个单独的目录mylogs/additivity,输出级别为WARN;其他程序产生的日志输出到另一个目录mylogs/system,同时输出到控制台上,输出级别为INFO。
那么,我们的配置文件可以写成:
<?xml version="1.0" encoding="UTF-8"?><Configuration status="WARN"><Appenders><Console name="Console" target="SYSTEM_OUT"><PatternLayout pattern="%highlight{%-8p [%d{yyyy-MM-dd HH:mm:ss}] %c %L: %m%n}"/></Console><RollingFile name="RollingFile_additivity"fileName="mylogs/additivity/log.out"filePattern="mylogs/additivity/log.out.%i"><PatternLayout><pattern>%-8p [%d{yyyy-MM-dd HH:mm:ss}] %c %L: %m%n</pattern></PatternLayout><SizeBasedTriggeringPolicy size="1KB" /><DefaultRolloverStrategy max="20"/></RollingFile><RollingFile name="RollingFile_system"fileName="mylogs/system/log.out"filePattern="mylogs/system/log.out.%i"><PatternLayout><pattern>%-8p [%d{yyyy-MM-dd HH:mm:ss}] %c %L: %m%n</pattern></PatternLayout><SizeBasedTriggeringPolicy size="1KB" /><DefaultRolloverStrategy max="20"/></RollingFile></Appenders><Loggers><!-- 将包"cn.gridx.log4j2.examples.additivity"下的程序产生的所有日志写入到RollingFile_additivity中 --><Logger name="cn.gridx.log4j2.examples.additivity" level="warn" additivity="false"><AppenderRef ref="RollingFile_additivity"/></Logger><!-- 将其他的程序都写入到Console和RollingFile_system --><Root level="info"><AppenderRef ref="Console"/><AppenderRef ref="RollingFile_system"/></Root></Loggers></Configuration>
在编译和构建时,我们并不需要用到SLF4J或者log4j2的依赖(除了在编译source code中的LoggerFactoryclass需要引入org.slf4j:slf4j-log4j12:1.7.21这个依赖),因此,我们在运行app时,往往通过java -cp来传入以下4个Jar包:
log4j-api-2.6.1.jar
log4j-core-2.6.1.jar
slf4j-api-1.7.21.jar
log4j-slf4j-impl-2.6.1.jar
但经常会遇到异常:
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/Users/SNAPSHOT-all.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/Users/lib/log4j-slf4j-impl-2.6.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]
这说明,在classpath中存在多个slf4j的实现,需要去掉不需要的。我们通过-cp传递过去的那4个Jar包肯定是正确的,说明我们自己生成的Jar包SNAPSHOT-all.jar中含有了slf4f的实现,也许是由其他依赖间接引入的。
我们在打包时,把org/slf4j这个package去掉即可。
shadowJar {exclude('org/slf4j/**')}或者jar {exclude('org/slf4j/**')}
Logback 是新一代的日志组件,在Akka系统中被推荐使用。
添加依赖
dependencies {compile 'org.slf4j:slf4j-api:1.7.10','ch.qos.logback:logback-classic:1.1.3','ch.qos.logback:logback-core:1.1.3'}
配置logback.xml
在resources目录下,或者是在classpath中,添加logback.xml文件:
<?xml version="1.0" encoding="UTF-8"?><configuration><appender name="FILE" class="ch.qos.logback.core.FileAppender"><file>log.out</file><append>true</append><encoder><pattern>%date{MM/dd HH:mm:ss} %-5level %logger{35} |- %msg%n</pattern></encoder></appender><appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><target>System.out</target><encoder><pattern>%date{MM/dd HH:mm:ss} %-5level %logger{35} |- %msg%n</pattern></encoder></appender><logger name="akka" level="INFO" /><root level="INFO"><appender-ref ref="FILE"/><appender-ref ref="CONSOLE"/></root></configuration>
调用logback
import org.slf4j.LoggerFactoryval log = LoggerFactory.getLogger(this.getClass)log.debug("DEBUG")log.info("Info")log.warn("WARN")log.error("Error")
使用highlight conversion word
可以通过highlight 这个 conversion word来让不同level的日志有不同的颜色,只需要在logback.xml里面配置即可。
<?xml version="1.0" encoding="UTF-8"?><configuration><appender name="Console" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%date{MM/dd HH:mm:ss} %highlight(%-5level) %logger{35} |- %highlight(%msg%n)</pattern></encoder></appender><logger name="akka" level="DEBUG" /><root level="DEBUG"><appender-ref ref="Console"/></root></configuration>
自定义高亮的颜色
可以通过自定义logback layout来实现自定义的颜色。
1. 创建一个Converter class
package logback.layouts.myhighlight;import ch.qos.logback.classic.Level;import ch.qos.logback.classic.spi.ILoggingEvent;import ch.qos.logback.core.pattern.color.ForegroundCompositeConverterBase;import static ch.qos.logback.core.pattern.color.ANSIConstants.*;/*** Created by tao on 10/9/16.*/public class MyHighLightConverter extends ForegroundCompositeConverterBase<ILoggingEvent> {@Overrideprotected String getForegroundColorCode(ILoggingEvent event) {Level level = event.getLevel();switch (level.toInt()) {case Level.ERROR_INT:return BOLD + RED_FG;case Level.WARN_INT:return RED_FG;case Level.INFO_INT:return YELLOW_FG;default:return DEFAULT_FG;}}}
然后在logback.xml中声明并使用它:
<?xml version="1.0" encoding="UTF-8"?><configuration><conversionRule conversionWord="myhighlight"converterClass="logback.layouts.myhighlight.MyHighLightConverter"/><appender name="Console" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%date{MM/dd HH:mm:ss} %myhighlight(%-5level) %logger{35} |- %myhighlight(%msg%n)</pattern></encoder></appender><logger name="akka" level="DEBUG" /><root level="DEBUG"><appender-ref ref="Console"/></root></configuration>
如果我们想把满足给定条件的日志去掉不显示,则可以使用过滤器。例如,我们想把满足下列三个条件的日志屏蔽掉:
akka.remote.ReliableDeliverySupervisor产生;则我们可以在logback.xml中添加一个filter:
<?xml version="1.0" encoding="UTF-8"?><configuration><conversionRule conversionWord="customhighlight"converterClass="com.gridx.pipeline.logback.layouts.CustomHighLightConverter"/><appender name="FILE" class="ch.qos.logback.core.FileAppender"><file>../logs/master.log</file><append>true</append><encoder><pattern>%date{MM/dd HH:mm:ss} %customhighlight(%-5level) %logger{35} |- %customhighlight(%msg%n)</pattern></encoder><filter class="ch.qos.logback.core.filter.EvaluatorFilter"><evaluator><expression>if(logger.equals("akka.remote.ReliableDeliverySupervisor") &&formattedMessage.startsWith("Association with") &&formattedMessage.contains("Caused by: [Connection refused"))return true;elsereturn false;</expression></evaluator><OnMatch>DENY</OnMatch><OnDismatch>NEUTRAL</OnDismatch></filter></appender><logger name="akka" level="INFO" /><root level="INFO"><appender-ref ref="FILE"/></root></configuration>
我们实际上是在XML中直接插入了Java代码,注意Java中的&在XML中需要用&来代替。
通过使用ch.qos.logback.core.rolling.RollingFileAppender,可以使得每个log文件的size不超过某个设置的值,如果log不断地产生,并且目前的log file size即将达到预设的大小时,新产生的日志会被写入到一个新生成的log file中。
<?xml version="1.0" encoding="UTF-8"?><configuration><appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>../logs/akka-master.log</file><rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"><fileNamePattern>../logs/akka-master.%i.log</fileNamePattern><minIndex>1</minIndex><maxIndex>10</maxIndex></rollingPolicy><triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"><maxFileSize>3MB</maxFileSize></triggeringPolicy><encoder><pattern>%date{MM/dd HH:mm:ss} %customhighlight(%-5level) %logger{35} |- %customhighlight(%msg%n)</pattern></encoder></appender><logger name="akka" level="INFO" /><root level="INFO"><appender-ref ref="FILE"/></root></configuration>