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

[b](一) JDK内置Logger的类结构[/b]

展开java.util.logging包,我们可以看到JDK内置Logger的类,包括Formatter, Handler等。

[img]http://dl2.iteye.com/upload/attachment/0088/2835/b17e72f2-9549-3344-b9e9-998a7abf322b.jpg[/img]

JDK内置Logger大致的类图关系如下:(方法和关系没有全部标记出来)
[img]http://dl2.iteye.com/upload/attachment/0088/2831/6586e0b4-a083-3133-82f1-80665987c115.jpg[/img]
[b]

(二) JDK内置Logger支持的Level[/b]
JDK内置 Logger提供了如下七种Logger级别,从高到低依次是:
SEVERE->WARNING->INFO->CONFIG->FINE->FINER->FINESET。

另外,可以使用OFF关闭日志记录,使用 ALL 启用所有消息的日志记录。

[b](三) JDK内置Logger支持的Formatter[/b]

JDK Logger支持2种Formatter,包括SimpleFormatter 和 XMLFormatter。其中,
SimpleFormatter以文本的形式记录日志信息;XMLFormatter 以XML格式的形式记录日志信息。

[b](四) JDK内置Logger支持的Handler[/b]
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 一个唯一的数字以处理冲突问题
%% 一个%

[b]SocketHanlder[/b]的例子如下:

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程序,控制输出成功的信息。

[img]http://dl2.iteye.com/upload/attachment/0088/2845/76aa0da7-cb9f-34b8-91b9-524775566766.jpg[/img]

第二种情况:关闭Tomcat服务.执行SocketHandlerTest程序,控制输出出错的信息。

[img]http://dl2.iteye.com/upload/attachment/0088/2843/1044c84c-ce69-3cfc-a982-b5c68595cf03.jpg[/img]

再来一个[b]MemoryHanlder[/b]的例子:
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);

}

}


[b](五) JDK内置Logger 默认配置文件[/b]
JDK内置Logger默认读取的配置文件是[b]jre\lib\logging.properties[/b]
这个可以从LogManager的readConfiguration方法中看出:

[img]http://dl2.iteye.com/upload/attachment/0088/2833/70fefadd-9807-3d2d-8608-29ddeff0a9f1.jpg[/img]

logging.properties文件截图如下:

[img]http://dl2.iteye.com/upload/attachment/0088/2837/e28b1f82-6002-367f-91a3-85a59e47ff96.jpg[/img]

从上述默认配置截图的内容可以看出:
1. handlers默认配置了一个ConsoleHandler, 这个就是为什么我们每次记录信息时,控制台会输出信息的原因,去掉ConsoleHandler,那么在控制台将不会有日志信息输出了。
2. FileHandler默认以XML形式输出。
3. ConsoleHandler默认采用文本形式输出。
4. 默认level为INFO.

5. [b]如果想指定其它的文件作为logger的配置文件[/b],默认配置文件中提供了如下的信息:
############################################################
# 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 [color=red]java -Djava.util.logging.config.file=myfile[/color]############################################################

另外LogManager中有个public的方法[b]readConfiguration[/b](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;
}
}


相信这个方法也会是一个实现自定义配置文件的方法。

[b](六)如何使用JDK内置logger[/b]

使用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");
}
}


这样,日志信息就会输出到指定的文件中去,查看一下文件内容如下:


[img]http://dl2.iteye.com/upload/attachment/0088/2876/b67cd87b-6d60-3d4f-a46c-6ddca9ce3800.jpg[/img]


这样,JDK Logger就可以方便的使用起来了。使用时,首先创建一个logger,比如:
private static Logger logger = MyLoggerUtil.setLoggerHanlder(Logger.getLogger("my.logger"));

然后在需要记录日志信息的地方调用logger相应的方法来完成日志信息记录即可。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值