Java日志工具之java.util.logging.Logger

摘要:
今天,我总结了JDK附带的测井工具Logger。虽然它是未知的,但有时使用它很方便。如果创建了具有给定名称的记录器,则返回该记录器。Logger的级别类定义了一组可用于控制日志输出的标准日志级别。Logger的级别相对详细。它都是在java.util.logging.Level中定义的。每个级别按降序列出,如下:SEVERE(最高值)WARNINGINFOCONFIGFINERFINEST(最低值)。此外,还有一个级别为OFF,可用于关闭日志记录,并使用级别ALL启用所有消息的日志记录。每个Logger只关心其最低级别。

今天总结下JDK自带的日志工具Logger,虽然它一直默默无闻,但有时使用它却比较方便。更详细的信息可以查看JDK API手册,本文只是简单示例入门。

创建Logger

我们可以使用Logger的工厂方法

public static Logger getLogger(String name)

来创建,其中name是logger 的名称,这应该是一个圆点分隔的名称,并且通常应该基于子系统的包名或类名(如net.oseye),这是就Logger的名称空间。如果已经创建了具有给定名称的 logger,则返回该 logger。否则创建一个新的 logger。

每个Logger都有一个"父"Logger,也就是 Logger 名称空间中与其最近的现有祖先,而最顶层有个“Root”Logger,是所有Logger的顶级祖先。

Logger的级别

Level 类定义了一组可用来控制日志输出的标准日志级别。日志 Level 对象是有序的,并且是通过有序的整数来指定。在给定的级别上启用日志记录也就启用了所有较高级别的日志记录。 客户机一般应该使用预定义的 Level 常量(如 Level.SEVERE)。

Logger的级别是比较详细,全部定义在java.util.logging.Level里面,各级别按降序排列如下:

SEVERE(最高值)
WARNING
INFO
CONFIG
FINE
FINER
FINEST(最低值)

此外,还有一个级别 OFF,可用来关闭日志记录,使用级别 ALL 启用所有消息的日志记录。

每个Logger都只关心自己的最低 Level。如果将 Logger 的级别设置为 null,那么它的有效级别继承自父 Logger,这可以通过其父 Logger 一直沿树向上递归得到。 

logger默认的级别是INFO,比INFO更低的日志将不显示,Logger的默认级别定义是在jre安装目录的lib下的logging.properties(properties的使用讲解)文件中:

############################################################
#  	Global properties
############################################################
.....
# Default global logging level.
# This specifies which kinds of events are logged across
# all loggers.  For any given facility this global level
# can be overriden by a facility specific level
# Note that the ConsoleHandler also has a separate level
# setting to limit messages printed to the console.
.level= INFO

简单示例

package net.oseye;
import java.util.logging.Logger;
public class RunMain {

	public static void main(String[] args) {
		Logger log=Logger.getLogger("oseye");
		Logger logtmp=Logger.getLogger("oseye");
		log.fine("fine日志测试");
		log.info("info日志测试");
		log.warning("warning日志测试");
		System.out.println(log==logtmp);
		System.out.println(System.getProperty("java.home"));
	}
}

输出:

三月 15, 2014 11:14:04 上午 net.oseye.RunMain main
INFO: info日志测试
三月 15, 2014 11:14:04 上午 net.oseye.RunMain main
WARNING: warning日志测试
true
C:Program FilesJavajre7

可以看到比info级别低的fine日志没有显示,而log和logtmp都是名为"oseye"的Logger。

此时你可以修改logging.properties来设置级别,但首先需要确定你用的那个JRE(安装JDK后会有多个JRE),只有找到正确的JRE修改的配置才有效,本例中使用的JRE是:

C:Program FilesJavajre7

Logger的Handler

Handler 对象从 Logger 中获取日志信息,并将这些信息导出,而且向父级递归传递信息。例如,它可将这些信息写入控制台或文件中,也可以将这些信息发送到网络日志服务中,或将其转发到操作系统日志中。 Handler 类通常使用 LogManager 属性来设置 Handler 的 Filter、Formatter 和 Level 的默认值。Handler的子类如下:

Java日志工具之java.util.logging.Logger第1张

java.util.logging.Handler 
	java.util.logging.MemoryHandler 
	java.util.logging.StreamHandler 
		java.util.logging.ConsoleHandler 
		java.util.logging.FileHandler 
		java.util.logging.SocketHandler

可以使用下面的方法来操作Handler:

public void addHandler(Handler handler) //添加
public void removeHandler(Handler handler) //删除
public Handler[] getHandlers() //获取
public void setUseParentHandlers(boolean useParentHandlers) //是否应该将其输出发送到它的父 Logger

示例代码:

package net.oseye;

import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Logger;

public class RunMain {

	public static void main(String[] args) {
		Logger log=Logger.getLogger("oseye");
		Handler[] handleList=log.getHandlers();
		System.out.println("oseye的handler数:"+handleList.length);
		handleList=log.getParent().getHandlers();
		System.out.println("oseye的父级handler数:"+handleList.length);
		for(Handler h:handleList){
			System.out.println(h);
		}
		log.addHandler(new ConsoleHandler());
		log.info("两个handler处理,一个自定义,另一个是祖先");
	}
}

输出:

oseye的handler数:0
oseye的父级handler数:1
java.util.logging.ConsoleHandler@125844f
三月 15, 2014 11:35:12 上午 net.oseye.RunMain main
INFO: 两个handler处理,一个自定义,另一个是祖先
三月 15, 2014 11:35:12 上午 net.oseye.RunMain main
INFO: 两个handler处理,一个自定义,另一个是祖先

  • 默认的oseye是没有handler的,但其父级有默认的是ConsoleHander,这个可以在默认的logging.properties配置文件可以看到:
    handlers= java.util.logging.ConsoleHandler
  • 增加了一个ConsoleHandler,可以看到信息是向上传递的,直到达到顶层,但可以使用setUseParentHandlers来设置是否传递;
  • 每个handler也可以设置自己的Level,这个留给你当家庭作业吧。

日志内容的格式化

一般来说,每个日志记录 Handler 都有关联的 Formatter。Formatter 接受 LogRecord,并将它转换为一个字符串。 有些 Formatter(如 XMLFormatter)需要围绕一组格式化记录来包装头部和尾部字符串。可以使用 getHeader 和 getTail 方法来获得这些字符串。 

package net.oseye;

import java.io.File;
import java.util.logging.FileHandler;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;

public class RunMain {

	public static void main(String[] args) throws Exception {
		Logger log=Logger.getLogger("oseye");
		FileHandler fileHandler=new FileHandler("d:"+File.separator+"log.txt");
		fileHandler.setFormatter(new Formatter() {
			
			@Override
			public String format(LogRecord arg0) {
				return arg0.getLoggerName()+"	"+arg0.getLevel()+"	"+arg0.getMessage();
			}
		});
		fileHandler.setLevel(Level.WARNING);
		log.addHandler(fileHandler);
		
		log.setUseParentHandlers(false);
		log.warning("警告信息");
	}
}

示例中使用了FileHandler,而且禁止日志消息向上传递,在"d:log.txt"中可以看到:

oseye WARNING 警告信息

在setFormatter时我使用匿名类(你可以使用别的方式),其中LogRecord 对象用于在日志框架和单个日志 Handler 之间传递日志请求。

自定义配置文件

自定义配置文件有两种方式:

  1. Logger默认的是使用jre安装目录的lib下的logging.properties配置文件,但logging.properties明确的给出使用其他自定义配置文件的说明:
    ############################################################
    #  	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
    ############################################################
    因此如果你的配置文件是"d:logging.properties",当你执行的使用这样用即可:
    java -Djava.util.logging.config.file=d:logging.properties net.oseye.RunMain
  2. 使用LogManager
    Logger默认的是使用jre安装目录的lib下的logging.properties配置文件,这可以从java.util.logging.LogManager的代码看出:
    Java日志工具之java.util.logging.Logger第2张
    从代码中我们可以有两种方式加载自定义配置文件,第一种是指定加载自定义的LogManager类,然后再在LogManager来加载自定义配置文件;第二种方式是通过设置"java.util.logging.config.file"系统属性,从而加载自定义配置文件。
    我们用第二种示例,第一种作为家庭作业吧
    package net.oseye;
    import java.util.logging.Logger;
    
    public class RunMain {
    	public static void main(String[] args) throws Exception {
    		System.setProperty("java.util.logging.config.file", "d:\logging.properties");
    		Logger log = Logger.getLogger("oseye");
    		log.warning("警告信息");		
    	}
    }
    上面示例我用的是绝对路径,实际生成中切记不可如此,可根据需求自己修改。

免责声明:文章转载自《Java日志工具之java.util.logging.Logger》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇react踩坑-各种异常解决方案UI线程异常处理方法下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

子线程更新UI界面的2种方法

一、一般我们都会在子线程完成一些耗时的操作。 1、Android中消息机制: 2、知识点: Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message m...

安卓中的线程

 1. Android进程    在了解Android线程之前得先了解一下Android的进程。当一个程序第一次启动的时候,Android会启动一个LINUX进程和一个主线程。默认的情况下,所有该程序的组件都将在该进程和线程中运行。同时,Android会为每个应用程序分配一个单独的LINUX用户。Android会尽量保留一个正在运行进程,只在内存资源出现...

qt quick中qml编程语言

Qt QML 入门 — 使用C++定义QML类型 发表于2013 年 3 月 11 日 注册C++类 注册可实例化的类型 注册不实例化的QML类型 附带属性 注册C++类 注册可实例化的类型 如果一个C++类继承自QObject,如果需要在QML中使用创建对象,则需要注册为可实例化的QML类型。 使用qmlRegisterType()注册可...

Android 使用官方下拉刷新

网上关于下拉刷新的文章也不少,不过都太长了,看得挺难受的。恰好发现了官方的下拉刷新库,而且效果还是不错的,简洁美观,用得也挺方便。 下面是效果图: 我的好友原来是空的,刷新后多了两个。 使用还是挺方便的,在布局文件中加入SwipeRefreshLayout ,这个就是下拉刷新的布局。 我在SwipeRefreshLayout的里面还加入了一个ListVi...

[Android Memory] App调试内存泄露之Context篇(上)

转载自:http://www.cnblogs.com/qianxudetianxia/p/3645106.html Context作为最基本的上下文,承载着Activity,Service等最基本组件。当有对象引用到Activity,并不能被回收释放,必将造成大范围的对象无法被回收释放,进而造成内存泄漏。 下面针对一些常用场景逐一分析。 1. CallBa...

java后台解决跨域问题

解决跨域问题的方式有很多,这里主要是添加注解的方式和采用添加拦截器的方法: 方法一、spring boot中只用在Controller类上添加一个“@CrossOrigin“注解就可以实现对当前controller 的跨域 访问了,当然这个标签也可以加到方法上。 @CrossOrigin public classCommonController { }...