Java 日志记录简介
日志是软件应用程序中的记录信息,我们可以选择将其保存到文件中,或显示在控制台上。这些记录可以描述任何内容:程序中的一个事件、变量的值、错误或异常等。日志主要用于调试目的。
今天,我们将学习 Java 标准 SDK 中用于日志记录的 java.util.logging
包。要使用 Java 的日志功能,你需要了解以下几个组件:
-
Logger
-
FileHandler
-
ConsoleHandler
-
SimpleFormatter
-
XMLFormatter
-
Level
-
LogRecord
-
LogManager
在本主题中,我们将重点介绍前六个组件,并学习 Logger、Handler、Filter 和 Formatter 是如何协同工作的。
Logger 类
Logger
是整个日志系统中最核心的组件。标准做法是:为每一个类创建一个对应的 Logger 实例。
Logger 提供了多种记录日志的方法,其中 log()
是最基本的一种。来看一个简单示例:
import java.util.logging.Level
import java.util.logging.Logger
object Main {
@JvmStatic
fun main(args: Array<String>) {
val logger = Logger.getLogger(Main::class.java.name)
logger.log(Level.WARNING, "Hello " + logger.name)
}
}
解释:
-
创建了一个 Logger 实例,名称为
Main
类的名字。 -
使用
log()
方法记录一条日志。 -
第一个参数是日志级别(Level),第二个是日志消息。
输出如下:
WARNING: Hello Main
日志级别(Level)
每条日志都对应一个级别。在上面的例子中是 WARNING
。Java 默认的日志级别是 INFO
。
Java 中的日志级别,从严重到轻微如下:
日志级别(Level) | 中文含义 | 说明 |
---|---|---|
SEVERE | 严重错误 | 表示严重的问题,程序可能会中断,例如系统崩溃、异常终止等。 |
WARNING | 警告 | 表示可能的问题,程序可以继续运行,但可能会出错或存在风险。 |
INFO | 信息 | 一般性的信息,表示程序正常运行过程中的关键信息,如启动、配置成功等。 |
CONFIG | 配置信息 | 表示一些配置信息,通常在系统初始化或模块加载时记录。 |
FINE | 详细调试信息 | 用于提供比 INFO 更细致的调试信息,开发调试时较为常见。 |
FINER | 更详细的调试信息 | 更进一步的调试信息,用于跟踪程序内部流程。 |
FINEST | 最详细的调试信息 | 提供最细致的调试信息,几乎包括所有可跟踪的操作。 |
Logger 还提供了快捷方法,比如 info()
、config()
等,不需要指定 Level 参数:
import java.util.logging.Logger
object Main {
@JvmStatic
fun main(args: Array<String>) {
val logger = Logger.getLogger(Main::class.java.name)
logger.severe("Severe Log")
logger.warning("Warning Log")
logger.info("Info Log")
}
}
输出示例:
2023年1月9日 上午9:26:04 Main main
SEVERE: Severe Log
2023年1月9日 上午9:26:04 Main main
WARNING: Warning Log
2023年1月9日 上午9:26:04 Main main
INFO: Info Log
Handlers 和 Formatters
在日志系统中,Handler 负责将日志信息输出到外部系统,如控制台或文件。
Java 提供了 Handler
抽象类,以及几个具体实现类,其中重要的两个是:
-
ConsoleHandler
:将日志输出到控制台(默认是System.err
) -
FileHandler
:将日志写入到指定文件中
每个 Handler 都可以搭配 Formatter 使用,用于设置输出格式:
-
SimpleFormatter
:普通文本格式 -
XMLFormatter
:XML 格式输出
示例:
import java.util.logging.FileHandler
import java.util.logging.Handler
import java.util.logging.Logger
import java.util.logging.XMLFormatter
object Main {
@JvmStatic
fun main(args: Array<String>) {
val logger = Logger.getLogger(Main::class.java.name)
val fileHandler: Handler = FileHandler("default.log")
logger.addHandler(fileHandler)
fileHandler.formatter = XMLFormatter()
logger.info("Info log message")
}
}
这段代码会在当前目录下生成 default.log
文件,内容如下:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE log SYSTEM "logger.dtd">
<log>
<record>
<date>2023-01-09T07:29:56.688157Z</date>
<millis>1673249396688</millis>
<nanos>157000</nanos>
<sequence>0</sequence>
<logger>Main</logger>
<level>INFO</level>
<class>Main</class>
<method>main</method>
<thread>1</thread>
<message>Info log message</message>
</record>
</log>
Filter(过滤器)
在开发中,我们往往会记录大量日志信息,但在运行时并不需要全部输出,以免浪费资源。这时候就可以用 Filter
来控制输出哪些日志。
例如,下面的 Filter 只允许 INFO
级别的日志被记录:
import java.util.logging.Filter
import java.util.logging.Level
import java.util.logging.LogRecord
class FilterExample : Filter {
override fun isLoggable(record: LogRecord): Boolean {
return record.level == Level.INFO
}
}
使用这个 Filter 的示例:
import java.util.logging.Filter
import java.util.logging.Level
import java.util.logging.Logger
object Main {
@JvmStatic
fun main(args: Array<String>) {
val logger = Logger.getLogger(Main::class.java.name)
val filter: Filter = FilterExample()
logger.filter = filter
logger.severe("Severe Log")
logger.info("Info Log")
logger.warning("Warning Log")
}
}
输出结果:
2023年1月9日 上午9:36:42 Main main
INFO: Info Log
只有 INFO 级别的日志被打印出来,其他被过滤掉了。
总结
-
java.util.logging
是 Java SDK 自带的日志系统。 -
Logger
用于创建日志对象,通常每个类一个。 -
Handler
决定日志信息的输出方式,常用的有ConsoleHandler
和FileHandler
。 -
Formatter
用于设置日志格式,如SimpleFormatter
或XMLFormatter
。 -
Filter
用于在运行时控制日志的输出内容。