Java logging整理

常见的java logging

  • System.out与System.err

  • java.util.logging

  • apache log4j

  • apache commons logging

  • SLF4J

其中System.out与System.err就不多说了。我们学习的第一个程序可能就是它们两个。

Logging的通用概念

Logging拥有通用的概念,在logging中,包含以下几个元素:

  1. logger - 产生log record,并设置record的level

  2. level - 两个地方可以设置过滤信息,1)logger的level, 2)handler的level.

  3. logRecord

  4. formatter/render/layout - 将log record转换为格式化的语言

  5. handler/appender - 将message输出到console, file, stream...

  6. 以及隐藏的logger属性的继承概念。所有的logger总会有一个rootLogger,在其每个path下的logger总会继承其父路径的level与handler.

Java Util Logging

调用方法

Java logging是java自带的logging工具包,在java.util.logging包中。使用方法很简单

1public static Logger logger = LogManager.getLogger(A.class) 2public void test() { 3    logger.info("A.info"); 4    logger.warning("A.warning"); 5    logger.severe("A.servere"); 6    logger.fine("A.fine"); 7}

配置方法

默认的配置文件为:jre/lib/logging.properties
可以通过4种方法覆盖默认配置:

  1. java -Djava.util.logging.config.file=...

  2. java -Djava.util.logging.config.class=...

  3. 书写自己的LogManager, 在logManager初始化中使用readConfiguration()来读入新的配置。

  4. 在运行时,动态的new xxxHandler和logger.setHandler()来配置logger.

在logging.properties中可以配置Level,handler,formatter

Java自带Logging的Level有SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST, OFF, ALL。

logger的level与handler的level共同控制着消息的输出。只有当两个level都满足,才会真正的输出。

两个标准的Formatter: java.util.logging.XMLFormatter, java.util.logging.SimpleFormatter

五个标准Handler: ConsoleHandler, FileHandler, StreamHandler, SocketHandler, MemoryHandler

此外还可以自己复写handler与formatter.

一个logging.properties的例子:

注意handlers不是overwrite的,而是累加的。例如,handlers声明的所有handler都应用于每个类。而每个类再次声明的handler将累加到前面的handler上。

1handlers =  2.level   = 3config   = 4 5"logger".handlers           = 6"logger".useParentHandlers  = 7"logger".level              = 8 9java.util.logging.SimpleFormatter.format=%4$s: %5$s [%1$tc]%n 10 11java.util.logging.FileHandler.level     = WARNING 12java.util.logging.FileHandler.filter    = 13java.util.logging.FileHandler.formatter = 14java.util.logging.FileHandler.encoding  = 15java.util.logging.FileHandler.limit     = 16java.util.logging.FileHandler.count     = 17java.util.logging.FileHandler.append    = false 18java.util.logging.FileHandler.pattern   = log.%u.%g.txt 19 20java.util.logging.ConsoleHandler.level     = WARNING 21java.util.logging.ConsoleHandler.filter    = 22java.util.logging.ConsoleHandler.formatter = 23java.util.logging.ConsoleHandler.encoding  =

Apache log4j

log4j2很快就会出来了,它将取代Log4j. 但log4j还是在很多地方被使用。Maven引入log4j的方法是

1<dependency> 2  <groupId>log4j</groupId> 3  <artifactId>log4j</artifactId> 4  <version>1.2.17</version> 5</dependency>

在log4j中,没有LogFactory, LoggerFactory或LogManager,直接调用Logger.getLogger()即可初始化logger。

1import org.apache.log4j.Logger; 2public class App { 3    private static Logger logger = Logger.getLogger(App.class); 4    public static void main( String[] args ) { 5        if (logger.isInfoEnabled()) { 6         logger.info("app.info"); 7        } 8        if (logger.isDebugEnabled()) { 9         logger.info("app.debug"); 10        } 11    } 12}

log4j跟其它logger机制一样,存在着基本的logger所有基本概念,只是它的fomatter叫做patternLayout, 而handler则叫做appender. 另外log4j和java util logging在level的划分上有所不同,log4j的level分为:TRACE,DEBUG,INFO,WARN,ERROR,FATAL,ALL。

 log4j的所有配置可以放在一个log4j.properties中:

1#log4j.logger.[package name]=level, appender1, appender2... 2 3#define rootlogger 4log4j.rootLogger=info, RF 5log4j.appender.RF=org.apache.log4j.RollingFileAppender 6log4j.appender.RF.File=example.log 7log4j.appender.RF.MaxFileSize=100KB 8# Keep one backup file 9log4j.appender.RF.MaxBackupIndex=1 10log4j.appender.RF.layout=org.apache.log4j.PatternLayout 11log4j.appender.RF.layout.ConversionPattern=%%%- %m%n 12 13#define logger for com.my.test 14log4j.logger.com.my.test=debug, stdout 15log4j.appender.stdout=org.apache.log4j.ConsoleAppender 16log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 17# Pattern to output the caller's file name and line number. 18log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n 19 20#com.my.test log messages do not transfer to parent's appenders. 21log4j.additivity.com.my.test=false

将log4j.properties放在classpath下面,就可以被自动加载了。如果log4j.properties不在classpath下,或者其名字叫other.properties, 则可以指定system property: 

java -Dlog4j.configuration=other.properties ....

Apache Commons Logging

也叫Jakarta Commons logging, 简称JCL, 其的目的是为所有流行的logging提供一个通用接口。用户在开发的时候只需要调用commons logging的接口。而运行环境中具体使用的是log4j,util logging或其它的logging, 则由commons logging配置文件或者commons logging的自动探测来决定。

Commons Logging包含三个jar:

  1. commons-logging-api.jar  这里面包含了commons logging的通用接口以及两个logger的实现:SimpleLog和NoOpLog.

  2. commons-logging.jar 这里面包含了通用接口,以及Log4j,JDK logger等的适配器。这个是最常用的包。

  3. commons-logging-adapters.jar 只包含了第三方logger的适配器。必须和上面两个包中的一个搭配使用。

Maven引入commons-logging.jar的方法:

1    <dependency> 2     <groupId>commons-logging</groupId> 3     <artifactId>commons-logging</artifactId> 4     <version>1.1.3</version> 5    </dependency>

Commons logging采用的是自动探测加载logging工具。在复杂的环境中,可能因为classpath中的某个文件,导致Commons logging加载跟我们的预期不一致,我们可以启动诊断功能将其探测决断的过程输出到STDOUT或STDERR中

java -Dorg.apache.commons.logging.diagnostics.dest=STDERR ...

Commons logging的使用方法:

1import org.apache.commons.logging.Log; 2import org.apache.commons.logging.LogFactory; 3public class App { 4    private static Log log = LogFactory.getLog(App.class); 5    public static void main( String[] args ) { 6     if (log.isInfoEnabled()) { 7     log.info("app.info"); 8        } 9        if (log.isDebugEnabled()) { 10         log.debug("app.debug"); 11        } 12    } 13}

在初始化Abstract LogFactory时,系统需要探测真正LogFactory Implementation, 其的探测顺序:

  1. Java System property: org.apache.commons.logging.LogFactory

  2. Commons-logging.properties中的org.apache.commons.logging.LogFactory

  3. 使用类org.apache.commons.logging.impl.LogFactoryImpl

    LogFactoryImpl对依次试图初始化

  4. commons-logging.properties中指定的org.apache.commons.logging.Log

  5. Java system properties中指定的org.apache.commons.logging.Log

  6. Log4j

  7. JDK4Logger

  8. SimpleLog

对于上面的代码,如果没有任何配置,则使用的是JDK4Logger. 如果将log4j放入classpath中,根据上面探测优先顺序,将会优先使用log4j。

Log的level与log4j的level分类相同。

SLF4J

Simple logging facades for java也是一种通用的logging接口。它跟commons logging类似,区别在于commons logging是运行时运用classLoader动态探测实际logging,而SLF4J是开发时使用import class静态声明binding。这解决了在类似OSGI下,commons logging工作存在的问题。SLF4J的产生,就是为了改变commons logging的动态探测。

Maven引入SLF4J接口的方法

1<dependency> 2     <groupId>org.slf4j</groupId> 3     <artifactId>slf4j-api</artifactId> 4     <version>1.7.6</version> 5</dependency>

slf4j-api.jar主要包含了接口,它并不包含logging的实现类,也不包含其它logger的装饰器。它必须和它的bindings一起工作。它的bindings里面包含了其它logger的装饰器。bindings有以下几个:

  1. slf4j-log4j12 包含了log4j的装饰器

    1<dependency> 2     <groupId>org.slf4j</groupId> 3     <artifactId>slf4j-log4j12</artifactId> 4     <version>1.7.6</version> 5</dependency>
  2. slf4j-jdk14 顾名思义

    1<dependency> 2     <groupId>org.slf4j</groupId> 3     <artifactId>slf4j-jdk14</artifactId> 4     <version>1.7.6</version> 5</dependency>
  3. slf4j-nop  no operation的意思是忽略丢弃所有的logging message

  4. slf4j-simple 包含了simple logging的实现。

  5. slf4j-jcl 包含了commons logging的装饰类。

    1<dependency> 2     <groupId>org.slf4j</groupId> 3     <artifactId>slf4j-jcl</artifactId> 4     <version>1.7.6</version> 5</dependency>

slf4j的调用方法:

1import org.slf4j.Logger; 2import org.slf4j.LoggerFactory; 3public class App { 4    private static Logger logger = LoggerFactory.getLogger(App.class); 5    public static void main( String[] args ) { 6     if (logger.isInfoEnabled()) { 7     logger.info("app.info"); 8        } 9        if (logger.isDebugEnabled()) { 10         logger.debug("app.debug"); 11        } 12    } 13}

而配置上非常简单。如果想使用log4j,只需要在pom.xml中引入slf4j-log4j12的binding,binding自动引入依赖模块log4j.还需要在classpath下面创建log4j.properties就可以使log4j工作。同样的,可以方法可以使用commons logging或jdk14logging.

建议使用SLF4J。对于旧的系统,无法改动为SLF的,可以使用SLF的桥接功能。SLF4J提供了几个桥接包,可以是对log4j,jdk14log,commons logging的调用,转发给SLF4J. 这几个桥接包就是jcl-over-slf4j.jar,log4j-over-slf4j.jar以及jul-over-slf4j.jar.

Tomcat 8 logging

顺带说下tomcat自身代码的logging,tomcat 8使用的是自己开发的org.apache.juli.logging. 它类似于commons-logging. 是在commons logging的帮助下开发的。 我猜之所以不直接用commons logging,可能是tomcat不想在自己的最小发布包中包含其它的依赖。

juli logging默认支持的是jdk14 logging. 如果想支持Log4J,则需要使用juli adapter。在adapter中包含了对外的适配器。

以上是tomcat8自身的logging系统。接下来,对于开发的web应用,可以使用javax.servlet.ServletContext.log(...)把log写到tomcat的log中。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )