Log4j2 的配置、使用
最近公司让调研log4j2在Android中的使用,在网上查了很多资料,在这做个总结,一起学习,参考了许多文章,文末都有链接,感谢大佬们的文章
Log4j2 简介
log4j2是log4j 1.x 的升级版,2015年5月,Apache宣布log4j1.x 停止更新。最新版:官网下载
log4j2参考了logback的一些优秀的设计,并且修复了一些问题,因此带来了一些重大的提升,主要有:
-
异常处理:在logback中,Appender中的异常不会被应用感知到,但是在log4j2中,提供了一些异常处理机制。
-
性能提升:log4j2相较于log4j 1和logback都具有很明显的性能提升。
-
自动重载配置:参考了logback的设计,提供自动刷新参数配置,可以动态的修改日志的级别而不需要重启应用。
-
无垃圾机制,log4j2在大部分情况下,都可以使用其设计的一套无垃圾机制,避免频繁的日志收集导致的jvm gc。
Log4j2 配置
log4j2 既可以采用xml方式配置,也可采用代码的方式配置
在本文中是实现日志过滤,然后存入文件,按照一定大小分割文件。
-
添加依赖包
implementation 'org.apache.logging.log4j:log4j-api:2.14.0' implementation 'org.apache.logging.log4j:log4j-core:2.14.0'
直接这样添加会报错,网上给出的解决办法:
在app gradle中添加一下代码:
packagingOptions {
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/NOTICE'
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt'
}
不懂这是什么意思但是添加上就没问题了,知道的在下方评论一起学习吧。
-
xml方式配置:
先上代码,xml文件:
<?xml version="1.0" encoding="UTF-8"?> <configuration status="debug" > <appenders> <!--这个输出控制台的配置--> <console name="Stdout" target="SYSTEM_OUT"> <!--输出日志的格式--> <ThresholdFilter level="trace" onMatch="ACCEPT" onMismatch="NEUTRAL"/> <PatternLayout pattern="%d [%t] %-5level: %msg%n%throwable"/> </console> <RollingFile name="rolling" fileName="mnt/sdcard/rolling.log" filePattern="mnt/sdcard/rolling-%d{yyyy-MM-dd}-%i.txt" > <MarkerFilter marker="NAME" onMatch="ACCEPT" onMismatch="DENY"/> <PatternLayout pattern="[%d{yyyy-MM-dd HH:mm:ss}] [%c{1}-%p %l] %m%n"/> <Policies> <!-- 基于指定文件大小的滚动策略,设置日志文件满1MB后打包,,size属性用来定义每个日志文件的大小 --> <SizeBasedTriggeringPolicy size="1M"/> </Policies> <!-- DefaultRolloverStrategy属性如不设置,默认最多7个文件,这里设置20 --> <DefaultRolloverStrategy max="20"/> </RollingFile> </appenders> <loggers> <!--记录执行的HQL语句 --> <!-- additivity="false"是为了避免日志在root里再次输出 --> <Logger name="TestLogger" level="debugr" additivity="false"> <AppenderRef ref="rolling" /> </Logger> <root level="debug"> <AppenderRef ref="rolling"/> </root> </loggers> </configuration>
-
配置文件节点解析
根节点Configuration
-
有两个属性:status和monitorinterval
- status用来指定log4j本身的打印日志的级别.
- monitorinterval用于指定log4j自动重新配置的监测间隔时间,单位是s,最小是5s.
-
有两个子节点:Appenders和Loggers(表明可以定义多个Appender和Logger).
-
Appenders节点,常见的有三种子节点:Console、RollingFile、File.
-
Console节点用来定义输出到控制台的Appender.
name:指定Appender的名字.
target:SYSTEM_OUT 或 SYSTEM_ERR,一般只设置默认:SYSTEM_OUT. PatternLayout:输出格式,不设置默认为:%m%n.
-
File节点用来定义输出到指定位置的文件的Appender.
name:指定Appender的名字.
fileName:指定输出日志的目的文件带全路径的文件名.
PatternLayout:输出格式,不设置默认为:%m%n.
append:当为true时,会在之前的日志里面续加内容,而不清空
-
RollingFile节点用来定义超过指定大小自动删除旧的创建新的的Appender. name:指定Appender的名字.
fileName:指定输出日志的目的文件带全路径的文件名.
filePattern:指定新建日志文件的名称格式.
PatternLayout:输出格式,不设置默认为:%m%n.
Policies:指定滚动日志的策略,就是什么时候进行新建日志文件输出日志. TimeBasedTriggeringPolicy:Policies子节点,基于时间的滚动策略,interval属性用来指定多久滚动一次,默认是1 hour。
modulate=true用来调整时间:比如现在是早上3am,interval是4,那么第一次滚动是在4am,接着是8am,12am…而不是7am.
SizeBasedTriggeringPolicy:Policies子节点,基于指定文件大小的滚动策略,size属性用来定义每个日志文件的大小.
DefaultRolloverStrategy:用来指定同一个文件夹下最多有几个日志文件时开始删除最旧的,创建新的(通过max属性)。
-
-
Loggers节点,常见的有两种:Root和Logger.
-
Root节点用来指定项目的根日志,如果没有单独指定Logger,那么就会默认使用该Root日志输出
level:日志输出级别,共有8个级别,见下面注
AppenderRef:Root的子节点,用来指定该日志输出到哪个Appender.
-
Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等。 level:日志输出级别,共有8个级别,见下面注
name:用来指定该Logger所适用的类或者类所在的包全路径,继承自Root节点. AppenderRef:Logger的子节点,用来指定该日志输出到哪个Appender,如果没有指定,就会默认继承自Root.如果指定了, 那么会在指定的这个Appender和Root的Appender中都会输出,此时我们可以设置Logger的additivity=“false” 只在自定义的Appender中进行输出。
-
-
-
MarkerFilter: marker过滤tag的标志
-
onMatch和onMismatch都有三个属性值,分别为Accept、DENY和NEUTRAL
分别介绍这两个配置项的三个属性值:
onMatch=“ACCEPT” 表示匹配该级别及以上
onMatch=“DENY” 表示不匹配该级别及以上
onMatch=“NEUTRAL” 表示该级别及以上的,由下一个filter处理,如果当前是最后一个,则表示匹配该级别及以上
onMismatch=“ACCEPT” 表示匹配该级别以下
onMismatch=“NEUTRAL” 表示该级别及以下的,由下一个filter处理,如果当前是最后一个,则不匹配该级别以下的
onMismatch=“DENY” 表示不匹配该级别以下的
ps:关于日志level.共有8个级别
按照从低到高为:All < **Trace **< Debug <Info < Warn < **Error **< **Fatal **< OFF.
1. **All**:最低等级的,用于打开所有日志记录. 2. **Trace**:是追踪,就是程序推进以下,你就可以写个trace输出,所以trace应该会特别多,不过没关 3. **Debug**:指出细粒度信息事件对调试应用程序是非常有帮助的. 4. **Info**:消息在粗粒度级别上突出强调应用程序的运行过程. 5. **Warn**:输出警告及warn以下级别的日志. 6. **Error**:输出错误信息日志. 7. **Fatal**:输出每个严重的错误事件将会导致应用程序的退出的日志. 8. **OFF**:最高等级的,用于关闭所有日志记录.
程序会打印高于或等于所设置级别的日志,设置的日志等级越高,打印出来的日志就越少,默认会打印Error和Fatal等级的日志信息
-
使用配置文件:
-
将xml文件放在asstes文件夹下:
class:
private static final Marker NAME = MarkerManager.getMarker("NAME"); private static final Marker ERVIN = MarkerManager.getMarker("ERVIN");
ExtendedLogger logger=null; InputStream open = null; try { open = getAssets().open("log4j2.xml"); ConfigurationSource source = new ConfigurationSource(open); LoggerContext initialize = Configurator.initialize(null, source); logger = initialize.getLogger(Main.class); } catch (IOException e) { e.printStackTrace(); try { open.close(); } catch (IOException ioException) { ioException.printStackTrace(); } } while (true) { logger.error("error"); logger.debug("debug"); logger.fatal("fatal"); logger.warn("warn"); logger.info("info"); logger.trace("trace"); logger.log(Level.DEBUG, NAME, "marker debug"); logger.log(Level.ERROR, ERVIN, "marker error"); logger.log(Level.FATAL, NAME, "marker fatal"); logger.log(Level.WARN, ERVIN, "marker warn"); logger.log(Level.INFO, NAME, "marker info"); logger.log(Level.TRACE, NAME, "marker trace"); }
-
将xml文件放在设备的内存中:
class:
LoggerContext context = (org.apache.logging.log4j.core.LoggerContext) LogManager.getContext(false); File file = new File("/sdcard/log4j2.xml"); Log.d(TAG, "onCreate: " + file.exists()); if (file == null) { Log.d(TAG, "onCreate: =========="); } context.setConfigLocation(file.toURI()); ExtendedLogger logger = context.getLogger(Main.class);
这两种方式其实道理都一样,读出xml配置到LoggerContext中然后通过getLogger()方法得到ExtendedLogger然后就可以打印信息了。只要注意怎么读取xml文件就行了。
-
-
使用代码的方式配置
直接上代码:
ConfigurationBuilder< BuiltConfiguration > builder = ConfigurationBuilderFactory.newConfigurationBuilder(); builder.setStatusLevel( Level.DEBUG); builder.setConfigurationName("RollingBuilder"); builder.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.NEUTRAL) .addAttribute("level", Level.TRACE));//过滤日志级别的 // create a console appender AppenderComponentBuilder appenderBuilder = builder.newAppender("Stdout", "CONSOLE").addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT); appenderBuilder.add(builder.newLayout("PatternLayout") .addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable")); builder.add( appenderBuilder ); // create a rolling file appender LayoutComponentBuilder layoutBuilder = builder.newLayout("PatternLayout") .addAttribute("pattern", "%d [%t] %-5level: %msg%n"); ComponentBuilder triggeringPolicy = builder.newComponent("Policies") //.addComponent(builder.newComponent("CronTriggeringPolicy").addAttribute("schedule", "0 0 0 * * ?"))//每天凌晨清理文件 .addComponent(builder.newComponent("SizeBasedTriggeringPolicy").addAttribute("size", "1M")); ComponentBuilder defaultRolloverStrategy = builder.newComponent("DefaultRolloverStrategy") .addAttribute("max",20);//设置文件夹下有几个日志文件 appenderBuilder = builder.newAppender("rolling", "RollingFile") .addAttribute("fileName", "mnt/sdcard/rolling.log") .addAttribute("filePattern", "mnt/sdcard/rolling-%d{yyyy-MM-dd}-%i.txt") .add(builder.newFilter("MarkerFilter", Filter.Result.ACCEPT, Filter.Result.DENY) .addAttribute("marker", "NAME"))//过滤"NAME"的log .add(layoutBuilder) .addComponent(triggeringPolicy) .addComponent(defaultRolloverStrategy); builder.add(appenderBuilder); // create the new logger builder.add( builder.newLogger( "TestLogger", Level.DEBUG ) .add( builder.newAppenderRef( "rolling" ) ) .addAttribute( "additivity", false ) ); builder.add( builder.newRootLogger( Level.DEBUG ) .add( builder.newAppenderRef( "rolling" ) ) ); LoggerContext ctx = Configurator.initialize(builder.build()); ExtendedLogger logger = ctx.getLogger(MainActivity.class);
其实这代码配置也是和xml配置是一一对应的,ThresholdFil、tertarget、PatternLayout…对照一下这些关键词就能懂了。
日志信息格式中符号所代表的含义
(1)-X号: X信息输出时左对齐。
(2)%p: 输出日志信息优先级,即DEBUG,INFO,WARN,ERROR,FATAL。
(3)%d: 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,921。
(4)%r: 输出自应用启动到输出该log信息耗费的毫秒数。
(5)%c: 输出日志信息所属的类目,通常就是所在类的全名。
(6)%t: 输出产生该日志事件的线程名。
(7)%l: 输出日志事件的发生位置,相当于%C.%M(%F:%L)的组合,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10)。
(8)%x: 输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像java servlets这样的多客户多线程的应用中。
(9)%%: 输出一个"%“字符。
(10)%F: 输出日志消息产生时所在的文件名称。
(11)%L: 输出代码中的行号。
(12)%m: 输出代码中指定的消息,产生的日志具体信息。
(13)%n: 输出一个回车换行符,Windows平台为”\r\n",Unix平台为"\n"输出日志信息换行。
参考文章地址:从assets中读取xml