1. Level对象
1.1. Level类定义了一组可用来控制日志输出的标准日志级别。日志Level对象是有序的, 并且是通过有序的整数来指定。在给定的级别上启用日志记录也就启用了所有较高级别的日志记录。
1.2. 各级别按降序排列如下:
- SEVERE(最高值)
- WARNING
- INFO
- CONFIG
- FINE
- FINER
- FINEST(最低值)
1.3. 此外, 还有一个级别OFF, 可用来关闭日志记录, 使用级别ALL启用所有消息的日志记录。
1.4. public static final Level OFF是一个可用于关闭日志记录的特殊级别。此级别初始化为Integer.MAX_VALUE。
1.5. public static final Level SEVERE是指示严重失败的消息级别。通常, SEVERE消息应该描述相当重要的事件, 这些事件会阻止正常程序的执行。它们对于最终用户和系统管理员来说应该是很容易理解的。此级别初始化为1000。
1.6. public static final Level WARNING是指示潜在问题的消息级别。通常, WARNING消息应该描述最终用户或系统管理员感兴趣的事件或者那些指示潜在问题的事件。此级别初始化为900。
1.7. public static final Level INFO是报告消息的消息级别。通常, INFO消息被写入到控制台或与之相当的地方。因此, INFO 级别应该只用于相当重要的, 对于最终用户和系统管理员有意义的消息。此级别初始化为800。
1.8. public static final Level CONFIG是用于静态配置消息的消息级别。CONFIG消息提供各种静态配置信息, 并协助调试那些与特定配置有关的问题。例如, CONFIG消息可能包括CPU类型、图形色深、GUI外观等等。此级别初始化为700。
1.9. public static final Level FINE是提供跟踪信息的消息级别。FINE、FINER和FINEST都适合用于相对详细的跟踪。三个级别的准确意义在不同子系统间有所不同, 但是通常来说, FINEST 应该用于最为详细的输出, FINER 用于不太详细的输出, FINE用于极少量(且非常重要)的消息。通常, FINE级别应该用于开发人员比较感兴趣的信息, 而这些开发人员对特定子系统则没有特别的兴趣。
FINE消息可能包括诸如次要的(可恢复的)失败之类的信息。指示潜在性能问题的信息也可以作为FINE记录到日志。此级别初始化为500。
1.10. public static final Level FINER指示一条相当详细的跟踪消息。在默认情况下, 对于输入、返回或抛出异常的日志记录调用在此级别进行跟踪。此级别初始化为400。
1.11. public static final Level FINEST指示一条最详细的跟踪消息。此级别初始化为300。
1.12. public static final Level ALL指示应该记录所有消息。此级别初始化为Integer.MAX_VALUE。
2. Logger对象
2.1. Logger对象用来记录特定系统或应用程序组件的日志消息。一般使用圆点分隔的层次名称空间来命名Logger。如java.net或javax.swing。
2.2. public static Logger getLogger(String name)方法, 为指定子系统查找或创建一个logger。如果已经创建了具有给定名称的logger, 则返回该logger。否则创建一个新的logger。
Logger logger1 = Logger.getLogger(MyLogger.class.getName()); // 第一次是创建
Logger logger2 = Logger.getLogger(MyLogger.class.getName()); // 第二次是查找
System.out.println(logger1 == logger2); // 输入true
2.3. public void setLevel(Level newLevel) throws SecurityException方法, 设置日志级别, 指定此logger记录的消息级别。将级别低于此值的消息丢弃。可以使用级别值Level.OFF来关闭日志记录。如果将Logger的级别设置为null, 那么它的有效级别继承自父Logger, 这可以通过其父Logger一直沿树向上递归得到。
2.4. 日志消息被转发到已注册的Handler对象, 该对象可以将消息转发到各种目的地, 包括控制台、文件、OS日志等等。
2.5. public void severe(String msg)记录一条SEVERE消息。如果当前对于SEVERE消息级别而言logger是启用的, 那么将给定的消息转发到所有已注册的输出Handler对象。
2.6. public void warning(String msg)记录一条WARNING消息。如果当前对于WARNING消息级别而言logger是启用的, 那么将给定的消息转发到所有已注册的输出Handler对象。
2.7. public void info(String msg)记录一条INFO消息。如果当前对于INFO消息级别而言logger是启用的, 那么将给定的消息转发到所有已注册的输出Handler对象。
2.8. public void config(String msg)记录一条CONFIG消息。如果当前对于CONFIG消息级别而言logger是启用的, 那么将给定的消息转发到所有已注册的输出Handler对象。
2.9. public void fine(String msg)记录一条FINE消息。如果当前对于FINE消息级别而言logger是启用的, 那么将给定的消息转发到所有已注册的输出Handler对象。
2.10. public void finer(String msg)记录一条FINER消息。如果当前对于FINER消息级别而言logger是启用的, 那么将给定的消息转发到所有已注册的输出Handler对象。
2.11. public void finest(String msg)记录一条FINEST消息。如果当前对于FINEST消息级别而言logger是启用的, 那么将给定的消息转发到所有已注册的输出Handler对象。
3. 简单例子
3.1. 代码
package com.rjbd.loggerjvm;
import java.util.logging.Level;
import java.util.logging.Logger;
public class MyLogger {
public static void main(String[] args) {
Logger logger1 = Logger.getLogger(MyLogger.class.getName());
Logger logger2 = Logger.getLogger(MyLogger.class.getName());
System.out.println(logger1 == logger2); // 输入true
logger1.setLevel(Level.ALL);
logger1.severe("severe level in java util logging Logger");
logger1.warning("warning level in java util logging Logger");
logger1.info("info level in java util logging Logger");
logger1.config("config level in java util logging Logger");
logger1.fine("fine level in java util logging Logger");
logger1.finer("finer level in java util logging Logger");
logger1.finest("finest level in java util logging Logger");
}
}
3.2. 运行结果
4. Handler对象
4.1. Handler继承结构, 常用的ConsoleHandler和FileHandler
4.2. 在我们的MyLogger例子中, 我们并没有为logger1对象设置Handler对象, 然而控制台却打印了日志, 这是因为默认的创建了一个最顶层的日志RootLogger, 而且RootLogger的日志级别是INFO, 同时RootLogger的处理器是ConsoleHandler, 这就是为什么控制台打印出了info及其更高级别的日志。
4.3. 创建Logger对象的时候设置了它的parent为RootLogger对象
4.4. RootLogger的ConsoleHandler创建过程
4.5. 读取配置文件
5. FileHandler例子
5.1. 代码
package com.rjbd.loggerjvm;
import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
public class MyHandler {
public static void main(String[] args) {
Logger logger = Logger.getLogger(MyHandler.class.getName());
logger.setLevel(Level.ALL);
logger.getParent().getHandlers()[0].setLevel(Level.ALL);
try {
FileHandler fileHandler = new FileHandler("MyLogger.log");
logger.addHandler(fileHandler);
} catch (SecurityException | IOException e) {
e.printStackTrace();
}
logger.severe("severe level in java util logging Logger");
logger.warning("warning level in java util logging Logger");
logger.info("info level in java util logging Logger");
logger.config("config level in java util logging Logger");
logger.fine("fine level in java util logging Logger");
logger.finer("finer level in java util logging Logger");
logger.finest("finest level in java util logging Logger");
}
}
5.2. 运行结果
5.3. 生成MyLogger.log文件
6. Formatter对象
6.1. Formatter为格式化LogRecords提供支持。
6.2. Formatter继承结构, 自带了XMLFormatter和SimpleFormatter
6.3. 一般来说, 每个日志记录Handler都有关联的Formatter。Formatter接受LogRecord, 并将它转换为一个字符串。FileHandler默认使用XMLFormatter, ConsoleHandler默认使用SimpleFormatter。我们也可以自定义Formatter。
7. 自定义Formatter例子
7.1. 代码
package com.rjbd.loggerjvm;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.EnumSet;
import java.util.Iterator;
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 MyFormatter {
public static void main(String[] args) {
Logger logger = Logger.getLogger(MyFormatter.class.getName());
logger.setLevel(Level.ALL);
try {
FileHandler fh = new FileHandler("MyFormatterLogger.log");
logger.addHandler(fh);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
String lineSperator = System.getProperty("line.separator");
fh.setFormatter(new Formatter() {
@Override
public String format(LogRecord record) {
String time = "[" + sdf.format(new Date(record.getMillis())) + "]";
String qualifiedMethod = "[" + record.getLoggerName() + ":" + record.getSourceMethodName() + "]";
String levelNameMsg = "[" + LevelToLocalName.get(record.getLevel().intValue()) + ": " + record.getMessage() + "]";
return "[" + time + " " + qualifiedMethod + " " + levelNameMsg + "]" + lineSperator;
}
});
} catch (SecurityException | IOException e) {
e.printStackTrace();
}
logger.severe("severe level in java util logging Logger");
logger.warning("warning level in java util logging Logger");
logger.info("info level in java util logging Logger");
logger.config("config level in java util logging Logger");
logger.fine("fine level in java util logging Logger");
logger.finer("finer level in java util logging Logger");
logger.finest("finest level in java util logging Logger");
}
}
enum LevelToLocalName {
SEVERE(Level.SEVERE.intValue(), "严重"),
WARNING(Level.WARNING.intValue(), "警告"),
INFO(Level.INFO.intValue(), "信息"),
CONFIG(Level.CONFIG.intValue(), "配置"),
FINE(Level.FINE.intValue(), "详细"),
FINER(Level.FINER.intValue(), "较详细"),
FINEST(Level.FINEST.intValue(), "非常详细");
private int level;
private String name;
LevelToLocalName(int level, String name) {
this.level = level;
this.name = name;
}
public int getLevel() {
return level;
}
public String getName() {
return name;
}
public static String get(int level) {
EnumSet<LevelToLocalName> es = EnumSet.allOf(LevelToLocalName.class);
Iterator<LevelToLocalName> it = es.iterator();
while (it.hasNext()) {
LevelToLocalName type = it.next();
if (level == type.getLevel()) {
return type.getName();
}
}
return "";
}
}
7.2. 运行结果