Java 内部的log的使用
介绍
JDK自带的log的使用与运行方式
使用方法
最简单的使用
代码示例
1 |
|
会按默认格式,在console中输出日志
控制输出级别
级别控制可以在代码中直接写。
也可以在配置文件中写。是等效的。后设置的起作用。就是代码中的优先级高。
配置文件中的.level
(全局的)和java.util.logging.ConsoleHandler.level
是共同起作用,按最严格的输出。
1 |
|
logger.setLevel(Level.WARNING);
与.level = WARNING
等效logger.getHandlers()[0].setLevel(Level.FINE);
与java.util.logging.ConsoleHandler.level=FINE
等效
读取自定义的配置文件的日志输出
除代码方式外,还可以通过java命令行的方式指定配置文件。
如在启动时,指定参数java -Djava.util.logging.config.file="abc.properties"
1 |
|
输出到文件
1 |
|
默认的的格式为xml,可以设置fromatter来改变格式
handler
Handler对象从Logger中获取日志信息,并将这些信息导出。例如,它可将这些信息写入控制台或文件中,也可以将这些信息发送到网络日志服务中,或将其转发到操作系统日志中。
Logger默认的输出处理者是ConsoleHandler。ConsoleHandler的输出是使用System.err对象,而信息的默认等级是INFO,这可以在JRE安装目录下lib目录的logging.properties中看到配置。
Java SE实现了5个Handler:
- java.util.logging.ConsoleHandler 以System.err输出日志。
- java.util.logging.FileHandler 将信息输出到文件。
- java.util.logging.!StreamHandler以指定的!OutputStream实例输出日志。
- java.util.logging.!SocketHandler将信息通过Socket传送至远程主机。
- java.util.logging.!MemoryHandler将信息暂存在内存中。
FileHandler默认的输出格式是XML格式。输出格式由java.util.logging.Formatter来控制
用户可以定制自己输出媒介控制器,继承Handler即可。
Formatter
Formatter为格式化LogRecords提供支持。
一般来说,每个Handler都有关联的Formatter。Formatter接受LogRecord,并将它转换为一个字符串。
默认提供了两种Formatter:java.util.logging.SimpleFormatter':标准日志格式,
java.util.logging.XMLFormatter’: XML形式的日志格式。
也可以自定义日志的输出格式,只要继承抽象类Formatter,并重新定义其format()方法即可。format()方法会传入一个java.util.logging.LogRecord对象作为参数,可以使用它来取得一些与程序执行有关的信息。
Filter
实现java.util.logging.Filter
的isLoggable
的方法。按LogRecord
对象来返回是否过滤。
再配置到配置文件中。
JDK内置Logger 如何读取的默认配置文件
默认情况下,JDK的LogManager会在java.home/lib/logging.properties
这个文件中读取配置。。
如何读取的呢,核心代码在java.util.logging.LogManager
类
下面简化readConfiguration
中的代码(除去了非正常的分支)
1 |
|
读取之后,会把文件的key-value读取成Properties
对象。
如何修改日志格式
SimpleFormatter中的默认格式为%1$tb %1$td, %1$tY %1$tl:%1$tM:%1$tS %1$Tp %2$s%n%4$s: %5$s%6$s%n
SimpleFormatter中关键代码为:
1 |
|
输出示例:
1 |
|
关于String格式化的详见,比如%1$tb
对第一个参数,进行月份简称的格式化。
通过修改logging.properties
,java.util.logging.SimpleFormatter.format
中的参数,就是传到SimpleFormatter的中format
参数。
当然只能格式化上面有的信息,上面没有的信息,就不能输出的,比如说线程id,序列号就输出不了。
如何配置logging.properties
文件
一些关于java.util.logging
的日志配置文件的说明,都比较零散,还没有文件中的注释说明写得清楚。
了解这个配置文件怎么使用的,最容易的就看日志代码中怎么处理这个解析这个文件的,怎么使用这些配置的。
这里我就从源码入手,看系统怎么读取并初始化日志配置的。
比如:
1 |
|
因为logging.properties
文件读取成Properties
对象,给代码中其它位置使用,所以必定handlers
会是一个key。
在logging
包下搜索下"handlers"
。
发现LogManager.java
文件中的1578行,initializeGlobalHandlers
中发生了调用loadLoggerHandlers(rootLogger, null, "handlers");
(用的jdk1.8.0_101的源码),从函数名可以看到是找对位置了。loadLoggerHandlers
中做了什么事呢
简化后的代码:
1 |
|
parseClassNames
通key拿到value,按,
分割,返回数组对象,也就是多个hander的类名。
在loadLoggerHandlers
进行newInstance
,同时读取类名加”.level”的key,设置为handler的level。
然后增加到root的logger中。
这样,下面的关于level的配置就读取并配置好了。
1 |
|
那formatter是怎么读取的呢。按".formatter"
搜索。
可以看到在ConsoleHandler
初始化的时候,调用configure()
方法,里面有对level
,filter
,formatter
,encoding
的配置的使用。filter和formatter都是可以自定义,代码中通过newInstance
来初始化。
小插曲
在上面logger.addHandler(hdl);
处理中,还会以调用者的class类名加上”.handler”的配置再加一次handler。
就是说在配置文件中加上com.xyz.foo.handlers
的handler, 也加进来
同样的道理。
其它的handler与filter及formatter也可以这样配置
总结
看起来很平常的日志框架,读起源码的实现,还是能学到不少前人对模块设计的智慧。
JDK自带日志框架是个很基础但重要的功能。熟悉它的原理,对其它的日志框架的学习是非常有借鉴作用的。
对于个性化配置tomcat内部日志有一些帮助。
参考
- Java内置Logger详解
- JDK Logging 深入分析
- 那些年我们用过的日志框架
- Java 日志管理最佳实践
- java.util.logging.Logger 使用详解
- JAVA字符串格式化-String.format()的使用
遇到的问题
missing line number attributes
参考 http://www.cnblogs.com/wavky/p/3802537.html 解决了
正确的情况应该是引入JDK本身而不是JRE,点击Edit,更改Location指向正确的JDK目录,点击Restore Default更新左侧所有jar包的引用目录(指向jdk文件夹下的jre目录),确认必需的jar包已配置源代码包路径(主要是rt.jar),Finish确认。
调试时无法查看局部变量
参考 http://blog.csdn.net/appleprince88/article/details/21873807
首先我们要明白JDK source为什么在debug的时候无法观察局部变量,因为在jdk中,sun对rt.jar中的类编译时,去除了调试信息,这样在eclipse中就不能看到局部变量的值。这样的话,如果在debug的时候查看局部变量,就必须自己编译相应的源码使之拥有调试信息。