平时使用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的
例子如下:
class="java">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