平时使用Log4j记录日志信息,对JDK内置的Logger还真没有去关注和使用过,只知道这个是在JDK 1.4引入的。这次,抽空去看了一下JDK内置Logger(java.util.logging)。在这篇博文中将记录如下几个方面的信息:
1. JDK内置Logger的类结构
2. JDK内置Logger支持的Level
3. JDK内置Logger支持的Formatter
4. JDK内置Logger支持的Handler
5. JDK内置Logger 默认配置文件
6. 如何使用JDK内置logger
(一) JDK内置Logger的类结构
展开java.util.logging包,我们可以看到JDK内置Logger的类,包括Formatter, Handler等。
JDK内置Logger大致的类图关系如下:(方法和关系没有全部标记出来)
(二) JDK内置Logger支持的Level
JDK内置 Logger提供了如下七种Logger级别,从高到低依次是:
SEVERE->WARNING->INFO->CONFIG->FINE->FINER->FINESET。
另外,可以使用OFF关闭日志记录,使用 ALL 启用所有消息的日志记录。
(三) JDK内置Logger支持的Formatter
JDK Logger支持2种Formatter,包括SimpleFormatter 和 XMLFormatter。其中,
SimpleFormatter以文本的形式记录日志信息;XMLFormatter 以XML格式的形式记录日志信息。
(四) JDK内置Logger支持的Handler
Handler,实现将日志写入指定目的地,JDK Logger主要支持MemoryHandler和StreamHandler两个大类Handler,另外ConsoleHanler, FileHandler以及SocketHandler都是继承自StreamHandler,分别添加了一些自己的功能,分别将日志写入控制台、文件、Socket端口。
ConsoleHandler只是将OutputStream设置为System.err,其他实现和StreamHandler类似。
而SocketHandler将OutputStream绑定到对应的端口号中,其他也和StreamHandler类似。另外它还增加了两个配置:java.util.logging.SocketHandler.port和java.util.logging.SocketHandler.host分别对应端口号和主机。
FileHandler支持指定文件名模板(java.util.logging.FileHandler.pattern),文件最大支持大小(java.util.logging.FileHandler.limit,字节为单位,0为没有限制),循环日志文件数(java.util.logging.FileHandler.count)、对已存在的日志文件是否往后添加(java.util.logging.FileHandler.append)。
FileHandler支持的文件模板参数有:
/ 目录分隔符
%t 系统临时目录
%h 系统当前用户目录
%g 生成的以区别循环日志文件名
%u 一个唯一的数字以处理冲突问题
%% 一个%
SocketHanlder 的例子如下:
第一种情况:开启一个Tomcat服务,端口是8080.执行SocketHandlerTest程序,控制输出成功的信息。
第二种情况:关闭Tomcat服务.执行SocketHandlerTest程序,控制输出出错的信息。
再来一个 MemoryHanlder 的例子:
(五) JDK内置Logger 默认配置文件
JDK内置Logger默认读取的配置文件是 jre\lib\logging.properties
这个可以从LogManager的readConfiguration方法中看出:
logging.properties文件截图如下:
从上述默认配置截图的内容可以看出:
1. handlers默认配置了一个ConsoleHandler, 这个就是为什么我们每次记录信息时,控制台会输出信息的原因,去掉ConsoleHandler,那么在控制台将不会有日志信息输出了。
2. FileHandler默认以XML形式输出。
3. ConsoleHandler默认采用文本形式输出。
4. 默认level为INFO.
5. 如果想指定其它的文件作为logger的配置文件 ,默认配置文件中提供了如下的信息:
############################################################
# Default Logging Configuration File
#
# You can use a different file by specifying a filename
# with the java.util.logging.config.file system property.
# For example java -Djava.util.logging.config.file=myfile ############################################################
另外LogManager中有个public的方法 readConfiguration (InputStream ins).
相信这个方法也会是一个实现自定义配置文件的方法。
(六)如何使用JDK内置logger
使用JDK内置Logger可以分成三个步骤来完成:
1. 创建Logger
2. 创建Handler,为handler指定Formmater, 然后将Handler添加到logger中去。
3. 设定Level级别
我们可以自己写一个简单的JDK内置Logger使用的实用类:
使用起来也是很方便的。
package my.logger;
这样,日志信息就会输出到指定的文件中去,查看一下文件内容如下:
这样,JDK Logger就可以方便的使用起来了。使用时,首先创建一个logger,比如:
private static Logger logger = MyLoggerUtil.setLoggerHanlder(Logger.getLogger("my.logger"));
然后在需要记录日志信息的地方调用logger相应的方法来完成日志信息记录即可。
1. JDK内置Logger的类结构
2. JDK内置Logger支持的Level
3. JDK内置Logger支持的Formatter
4. JDK内置Logger支持的Handler
5. JDK内置Logger 默认配置文件
6. 如何使用JDK内置logger
(一) JDK内置Logger的类结构
展开java.util.logging包,我们可以看到JDK内置Logger的类,包括Formatter, Handler等。
JDK内置Logger大致的类图关系如下:(方法和关系没有全部标记出来)
(二) JDK内置Logger支持的Level
JDK内置 Logger提供了如下七种Logger级别,从高到低依次是:
SEVERE->WARNING->INFO->CONFIG->FINE->FINER->FINESET。
另外,可以使用OFF关闭日志记录,使用 ALL 启用所有消息的日志记录。
(三) JDK内置Logger支持的Formatter
JDK Logger支持2种Formatter,包括SimpleFormatter 和 XMLFormatter。其中,
SimpleFormatter以文本的形式记录日志信息;XMLFormatter 以XML格式的形式记录日志信息。
(四) JDK内置Logger支持的Handler
Handler,实现将日志写入指定目的地,JDK Logger主要支持MemoryHandler和StreamHandler两个大类Handler,另外ConsoleHanler, FileHandler以及SocketHandler都是继承自StreamHandler,分别添加了一些自己的功能,分别将日志写入控制台、文件、Socket端口。
ConsoleHandler只是将OutputStream设置为System.err,其他实现和StreamHandler类似。
而SocketHandler将OutputStream绑定到对应的端口号中,其他也和StreamHandler类似。另外它还增加了两个配置:java.util.logging.SocketHandler.port和java.util.logging.SocketHandler.host分别对应端口号和主机。
FileHandler支持指定文件名模板(java.util.logging.FileHandler.pattern),文件最大支持大小(java.util.logging.FileHandler.limit,字节为单位,0为没有限制),循环日志文件数(java.util.logging.FileHandler.count)、对已存在的日志文件是否往后添加(java.util.logging.FileHandler.append)。
FileHandler支持的文件模板参数有:
/ 目录分隔符
%t 系统临时目录
%h 系统当前用户目录
%g 生成的以区别循环日志文件名
%u 一个唯一的数字以处理冲突问题
%% 一个%
SocketHanlder 的例子如下:
- package my.logger;
- import java.io.IOException;
- import java.util.logging.Logger;
- import java.util.logging.SocketHandler;
- public class SocketHandlerTest {
- private SocketHandler handler = null;
- private static Logger logger = Logger
- .getLogger("my.logger.SocketHandlerTest");
- public SocketHandlerTest(String host, int port) {
- try {
- handler = new SocketHandler(host, port);
- logger.addHandler(handler);
- logger.info("SocketHandler运行成功......");
- } catch (IOException e) {
- logger.severe("请检查地址和端口是否正确......");
- StringBuilder sb = new StringBuilder();
- sb.append(e.toString()).append("\n");
- for(StackTraceElement elem : e.getStackTrace())
- {
- sb.append("\tat ").append(elem).append("\n");
- }
- logger.severe(sb.toString());
- }
- }
- public static void main(String args[]) {
- new SocketHandlerTest("localhost", 8080);
- }
- }
第一种情况:开启一个Tomcat服务,端口是8080.执行SocketHandlerTest程序,控制输出成功的信息。
第二种情况:关闭Tomcat服务.执行SocketHandlerTest程序,控制输出出错的信息。
再来一个 MemoryHanlder 的例子:
- package my.logger;
- import java.util.logging.ConsoleHandler;
- import java.util.logging.Level;
- import java.util.logging.LogRecord;
- import java.util.logging.Logger;
- import java.util.logging.MemoryHandler;
- public class MemoryHandlerTest {
- public static void main(String[] args) {
- Logger logger = Logger.getLogger("my.logger.MemoryHandlerTest");
- ConsoleHandler handler = new ConsoleHandler();
- MemoryHandler mHandler = new MemoryHandler(handler, 10, Level.ALL);
- logger.addHandler(mHandler);
- logger.setUseParentHandlers(false);
- LogRecord record1 = new LogRecord(Level.SEVERE, "This is SEVERE level message");
- LogRecord record2 = new LogRecord(Level.WARNING, "This is WARNING level message");
- logger.log(record1);
- logger.log(record2);
- }
- }
(五) JDK内置Logger 默认配置文件
JDK内置Logger默认读取的配置文件是 jre\lib\logging.properties
这个可以从LogManager的readConfiguration方法中看出:
logging.properties文件截图如下:
从上述默认配置截图的内容可以看出:
1. handlers默认配置了一个ConsoleHandler, 这个就是为什么我们每次记录信息时,控制台会输出信息的原因,去掉ConsoleHandler,那么在控制台将不会有日志信息输出了。
2. FileHandler默认以XML形式输出。
3. ConsoleHandler默认采用文本形式输出。
4. 默认level为INFO.
5. 如果想指定其它的文件作为logger的配置文件 ,默认配置文件中提供了如下的信息:
############################################################
# Default Logging Configuration File
#
# You can use a different file by specifying a filename
# with the java.util.logging.config.file system property.
# For example java -Djava.util.logging.config.file=myfile ############################################################
另外LogManager中有个public的方法 readConfiguration (InputStream ins).
- /**
- * Reinitialize the logging properties and reread the logging configuration
- * from the given stream, which should be in java.util.Properties format.
- * A PropertyChangeEvent will be fired after the properties are read.
- * <p>
- * Any log level definitions in the new configuration file will be
- * applied using Logger.setLevel(), if the target Logger exists.
- *
- * @param ins stream to read properties from
- * @exception SecurityException if a security manager exists and if
- * the caller does not have LoggingPermission("control").
- * @exception IOException if there are problems reading from the stream.
- */
- public void readConfiguration(InputStream ins) throws IOException, SecurityException {
- checkAccess();
- reset();
- // Load the properties
- props.load(ins);
- // Instantiate new configuration objects.
- String names[] = parseClassNames("config");
- for (int i = 0; i < names.length; i++) {
- String word = names[i];
- try {
- Class clz = ClassLoader.getSystemClassLoader().loadClass(word);
- clz.newInstance();
- } catch (Exception ex) {
- System.err.println("Can't load config class \"" + word + "\"");
- System.err.println("" + ex);
- // ex.printStackTrace();
- }
- }
- // Set levels on any pre-existing loggers, based on the new properties.
- setLevelsOnExistingLoggers();
- // Notify any interested parties that our properties have changed.
- changes.firePropertyChange(null, null, null);
- // Note that we need to reinitialize global handles when
- // they are first referenced.
- synchronized (this) {
- initializedGlobalHandlers = false;
- }
- }
相信这个方法也会是一个实现自定义配置文件的方法。
(六)如何使用JDK内置logger
使用JDK内置Logger可以分成三个步骤来完成:
1. 创建Logger
2. 创建Handler,为handler指定Formmater, 然后将Handler添加到logger中去。
3. 设定Level级别
我们可以自己写一个简单的JDK内置Logger使用的实用类:
- package my.logger;
- import java.io.File;
- import java.io.IOException;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- import java.util.logging.FileHandler;
- import java.util.logging.Level;
- import java.util.logging.Logger;
- import java.util.logging.SimpleFormatter;
- public class MyLoggerUtil {
- private static final SimpleDateFormat sdf = new SimpleDateFormat(
- "yyyy-MM-dd");
- private static final String LOG_FOLDER_NAME = "MyLoggerFile";
- private static final String LOG_FILE_SUFFIX = ".log";
- private synchronized static String getLogFilePath() {
- StringBuffer logFilePath = new StringBuffer();
- logFilePath.append(System.getProperty("user.home"));
- logFilePath.append(File.separatorChar);
- logFilePath.append(LOG_FOLDER_NAME);
- File file = new File(logFilePath.toString());
- if (!file.exists())
- file.mkdir();
- logFilePath.append(File.separatorChar);
- logFilePath.append(sdf.format(new Date()));
- logFilePath.append(LOG_FILE_SUFFIX);
- return logFilePath.toString();
- }
- public synchronized static Logger setLoggerHanlder(Logger logger) {
- return setLoggerHanlder(logger, Level.ALL);
- }
- public synchronized static Logger setLoggerHanlder(Logger logger,
- Level level) {
- FileHandler fileHandler = null;
- try {
- //文件日志内容标记为可追加
- fileHandler = new FileHandler(getLogFilePath(), true);
- //以文本的形式输出
- fileHandler.setFormatter(new SimpleFormatter());
- logger.addHandler(fileHandler);
- logger.setLevel(level);
- } catch (SecurityException e) {
- logger.severe(populateExceptionStackTrace(e));
- } catch (IOException e) {
- logger.severe(populateExceptionStackTrace(e));
- }
- return logger;
- }
- private synchronized static String populateExceptionStackTrace(Exception e) {
- StringBuilder sb = new StringBuilder();
- sb.append(e.toString()).append("\n");
- for (StackTraceElement elem : e.getStackTrace()) {
- sb.append("\tat ").append(elem).append("\n");
- }
- return sb.toString();
- }
- }
使用起来也是很方便的。
package my.logger;
- import java.util.logging.Logger;
- public class JDKLoggerExample {
- private static Logger logger = MyLoggerUtil.setLoggerHanlder(Logger.getLogger("my.logger"));
- public static void main(String[] args) {
- logger.info("JDK Logger is logging information at INFO Level");
- }
- }
这样,日志信息就会输出到指定的文件中去,查看一下文件内容如下:
这样,JDK Logger就可以方便的使用起来了。使用时,首先创建一个logger,比如:
private static Logger logger = MyLoggerUtil.setLoggerHanlder(Logger.getLogger("my.logger"));
然后在需要记录日志信息的地方调用logger相应的方法来完成日志信息记录即可。