`
MouseLearnJava
  • 浏览: 467400 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Java内置Logger详解

阅读更多
平时使用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的例子如下:

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相应的方法来完成日志信息记录即可。


  • 大小: 65.7 KB
  • 大小: 52.3 KB
  • 大小: 22.6 KB
  • 大小: 120.3 KB
  • 大小: 61.9 KB
  • 大小: 15.8 KB
  • 大小: 42.6 KB
0
5
分享到:
评论
2 楼 lgh1992314 2017-04-24  
simpleDean 写道
请问,Logger.setLevel()这个方法就是设置全局的level吗?还有,如果控制这个默认的consolehandler的level?

非全局,Logger.setLevel()控制的是logging.properties的ConsoleHandler
1 楼 simpleDean 2014-03-03  
请问,Logger.setLevel()这个方法就是设置全局的level吗?还有,如果控制这个默认的consolehandler的level?

相关推荐

    JAVA WEB 开发详解:XML+XSLT+SERVLET+JSP 深入剖析与实例应用.part2

    4.9 内置的模板规则 114 4.10 对空白的处理 115 4.11 xpath语言 116 4.11.1 xpath上下文 116 4.11.2 位置路径 117 4.11.3 表达式 121 4.11.4 核心函数库 123 4.12 创建结果树 126 4.12.1 创建元素和属性 127...

    JAVA WEB 开发详解:XML+XSLT+SERVLET+JSP 深入剖析与实例应用.part4

    4.9 内置的模板规则 114 4.10 对空白的处理 115 4.11 xpath语言 116 4.11.1 xpath上下文 116 4.11.2 位置路径 117 4.11.3 表达式 121 4.11.4 核心函数库 123 4.12 创建结果树 126 4.12.1 创建元素和属性 127...

    JAVA WEB 开发详解:XML+XSLT+SERVLET+JSP 深入剖析与实例应用.part5

    4.9 内置的模板规则 114 4.10 对空白的处理 115 4.11 xpath语言 116 4.11.1 xpath上下文 116 4.11.2 位置路径 117 4.11.3 表达式 121 4.11.4 核心函数库 123 4.12 创建结果树 126 4.12.1 创建元素和属性 127...

    JAVA WEB 开发详解:XML+XSLT+SERVLET+JSP 深入剖析与实例应用.part3

    4.9 内置的模板规则 114 4.10 对空白的处理 115 4.11 xpath语言 116 4.11.1 xpath上下文 116 4.11.2 位置路径 117 4.11.3 表达式 121 4.11.4 核心函数库 123 4.12 创建结果树 126 4.12.1 创建元素和属性 127...

    Java Log4j使用详解

    ### Java Log4j 使用详解 #### 一、Java 日志管理概述 在Java应用程序中,良好的日志管理对于系统的维护和故障排查至关重要。本篇文章旨在详细介绍如何在Java中使用Log4j来管理日志,包括其配置方法以及与其他日志...

    Python实现Logger打印功能的方法详解

    ### Python 实现 Logger 打印功能的方法详解 #### 前言 在开发过程中,日志记录是一项重要的工作,它不仅有助于我们理解程序运行时的行为,还能帮助我们追踪错误、调试问题。Python 提供了内置的 `logging` 模块来...

    2022年Hibernate包作用详解Java教程.docx

    它可以适配多种日志实现,如log4j或Java内置的日志系统。虽然其自身包含一个简单的logger,但推荐使用性能更优、功能更全的log4j。 除了以上这些核心库,还有一些可选的jar包。比如`ant.jar`和`optional.jar`,它们...

    JAR包的详解(推荐)

    8. commons-logging.jar: Apache Commons Logging是一个日志抽象层,使得应用程序可以在运行时选择不同的日志实现,如log4j或Java内置的日志框架。尽管其自身包含一个简单的logger,但推荐使用功能更强大、性能更好...

    Log4j详解与实战

    - 与Java内置的日志框架java.util.logging相比,Log4j提供了更丰富的功能和更好的可配置性。 - SLF4J(Simple Logging Facade for Java)是一个抽象层,可以用来替换不同的日志实现,包括Log4j。 在实际项目中,...

    Logger.rar

    在Java开发中,常见的日志框架有Log4j、Logback和Java内置的java.util.logging。这些框架提供了丰富的功能,包括不同级别的日志记录、定制化日志格式、过滤策略等。Logger.rar可能使用了其中之一,或者自定义实现。 ...

    Java_log.pdf

    【Java 日志操作详解】 日志在软件开发中扮演着至关重要的角色,它能帮助开发者追踪和诊断程序运行时的问题。在Java世界里,有多种日志框架可供选择,其中包括Jakarta Commons Logging(JCL)、JDK 1.4自带的Logger...

    log4j使用详解

    《log4j使用详解》 在Java开发中,日志记录是不可或缺的一部分,它帮助开发者追踪程序运行状态、定位问题和优化性能。Log4j作为Apache的一个开源项目,是Java领域广泛使用的日志框架,其灵活性和高效性使得它成为...

    Logger.getLogger()与LogFactory.getLog()的区别详解

    它的查找逻辑包括检查`commons-logging.properties`配置文件,系统环境变量,或者查找特定日志框架(如log4j)的存在,最后如果都没有找到,它会回退到使用JDK自带的日志实现,或者是其内置的SimpleLog类。...

    log4j入门到详解

    **日志框架Log4j详解** 日志框架在软件开发中扮演着至关重要的角色,它提供了记录应用程序运行过程中的各种信息的功能,便于调试、监控和问题排查。Log4j是Apache组织开发的一个开源日志记录工具,广泛应用于Java...

    java如何自定义异常用代码.doc

    ### Java自定义异常详解 #### 一、Java异常机制简介 在Java中,异常处理是一种用来可靠地处理程序运行时错误的重要机制。它允许程序员通过`try`、`catch`和`finally`等关键字来组织代码,从而有效地处理程序执行...

    详解面向切面编程

    1. **基于接口的Java内置动态代理**:使用`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口。这种方式要求被代理的对象必须实现至少一个接口。以下是一个简单的例子: - 定义业务接口`...

    IT java 面试题库

    ### IT Java面试题库知识点详解 #### 一、面向对象语言特性 1. **描述一下“Java中面向对象几个典型的面向对象特性”?** - **封装**: 封装是将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息...

    java日志操作之Log4j

    ### Java日志操作之Log4j详解 #### Log4j简介 Log4j是一个非常流行的开源日志框架,由Apache基金会维护。它最初是作为Jakarta项目的一部分出现的,随着时间的发展,Log4j逐渐成为了一个独立且功能强大的日志解决...

Global site tag (gtag.js) - Google Analytics