Java日志记录:处理程序
"处理程序"是负责实际记录到外界的组件。
我们可以将一个或者多个"处理程序"添加到"记录器"中。当通过Logger记录消息时,如果没有被Filter或者Logger的最低日志级别拒绝,则消息最终会转发到Handler。
这是将Handler
添加到Logger
的方法:
logger.addHandler(new ConsoleHandler());
处理程序和格式化程序
"处理程序"通常在记录消息之前使用"格式化程序"来格式化消息。我们既可以创建自己的Formatter,也可以使用两个内置的Formatter之一。要了解有关Formatter
的更多信息,请参阅Formatters上的文字。
这是在"处理程序"上获取和设置格式程序的方法:
ConsoleHandler handler = new ConsoleHandler(); handler.setFormatter(new SimpleFormatter()); Formatter formatter = handler.getFormatter();
对于某些内置的"处理程序",格式化程序也可以通过配置文件进行设置。有关更多详细信息,请参见配置文本。
内置处理程序
我们可以根据需要创建自己的Handler
,但是Java已经附带了4个内置的Handler
:
- 控制台处理程序 ConsoleHandler
- 文件处理程序 FileHandler
- 流处理程序 StreamHandler
- 套接字处理程序 SocketHandler
- 内存处理程序 MemoryHandler
我们将最常使用FileHandler
,但以下各节将对每个内置Handler
进行简要说明。
控制台处理程序
" ConsoleHandler"会将所有消息记录到" System.err"。默认情况下,ConsoleHandler使用SimpleFormatter格式化消息,然后再将它们写入System.err。这是创建ConsoleHandler
的方法:
ConsoleHandler handler = new ConsoleHandler();
文件处理程序
FileHandler将所有消息写入文件。这可以是单个文件,也可以是一组旋转文件。如果使用旋转文件,则将每个文件填充到特定大小限制,然后创建一个新文件。每个文件名均由基本名和序列号组成。例如" mylog.0.txt"," mylog.1.txt"等。
默认情况下,FileHandler使用XMLFormatter格式化所有消息,然后再将它们写入文件。
以下是可用于创建FileHandler
的各种构造函数:
FileHandler handler = new FileHandler(); FileHandler handler = new FileHandler(String pattern); FileHandler handler = new FileHandler(String pattern, boolean append); FileHandler handler = new FileHandler(String pattern, int limit, int count); FileHandler handler = new FileHandler(String pattern, int limit, int count, boolean append);
第一个构造函数创建一个默认的FileHandler。这个" FileHandler"是通过配置文件完全配置的。
第二个构造函数创建一个具有预定义模式的FileHandler,用于为日志文件生成文件名。
第三个构造函数创建带有文件名模式的FileHandler
和一个布尔值,该布尔值指示FileHandler
是否应追加到任何现有文件中。没有文件大小限制,并且文件计数设置为1.
第四个构造函数创建一个具有文件名模式,文件大小限制和文件计数的FileHandler
。当日志文件达到给定的文件大小限制时,将创建一个新文件,直到达到文件计数的最大值。然后,FileHandler
再次从第一个文件开始,将其删除并从头开始登录。
第五个构造函数创建一个具有文件名模式,文件大小限制,文件计数和布尔值的" FileHandler",该布尔值指示" FileHandler"是否应该添加到任何现有文件上。
这里有一些例子:
FileHandler handler = new FileHandler("myapp-log.%u.%g.txt"); FileHandler handler = new FileHandler("myapp-log.%u.%g.txt", true); FileHandler handler = new FileHandler("myapp-log.%u.%g.txt", 1024 * 1024, 10); FileHandler handler = new FileHandler("myapp-log.%u.%g.txt", 1024 * 1024, 10, true);
文件名模式
文件名模式是一个包含文件名和一个或者多个特殊代码的字符串,告诉FileHandler
如何生成文件名。可以使用的特殊代码是:
代码 | 含义 |
/ | 系统的文件名分隔符。通常是\或者/。 |
%t | 系统的临时目录。 |
%h | 系统的用户主目录。 |
%g | 将轮换的日志文件彼此区分开的世代号。 |
%u | 一个唯一的编号,以避免命名冲突。 |
%% | 单个百分号,以防我们要在文件名中使用它。 |
如果未指定%g代码,并且FileHandler的文件计数大于1,则将世代号(文件序列号)添加在文件名的末尾,并在点号(。)之后。
通常将%u代码设置为0。如果已经存在具有该名称的文件,该文件已被另一个进程使用,则将%u代码设置为1、2等,直到找到未使用的基本文件名为止。如果在文件名模式中未使用%u代码,并且与另一个进程发现文件名冲突,则在自动添加的世代号之后,将唯一号添加到文件名的末尾。注意:仅保证使用%u为基本文件名生成唯一编号,才能在本地文件系统上使用。
这里有一些例子:
文件名模式 | 含义 |
logfile.txt | 该文件称为日志文件,位于应用程序的当前目录中。 |
logfile%g.txt | 该文件称为日志文件,位于应用程序的当前目录中。 在文件名中的文本“ logfile”之后插入了世代号。例如, logfile0.txt ,logfile1.txt 等。 |
logfile%u。%g.txt | 该文件称为日志文件,位于应用程序的当前目录中。 在文件名中输入文本“ logfile”。例如, logfile0.0.txt ,logfile0.1.txt 等。 |
流处理程序
StreamHandler将日志消息写入OutputStream。这是一个如何创建StreamHandler
的例子:
StreamHandler handler = new StreamHandler(); StreamHandler handler = new StreamHandler(outputStream, formatter);
第一个构造函数创建一个没有OutputStream
的空StreamHandler
。在使用处理程序之前,必须使用方法setOutputStream()
设置一个。
第二个构造函数创建一个带有OutputStream和Formatter的StreamHandler。outputStream参数应该是我们创建或者从其他对象获取的某些OutputStream。例如,它可以是FileOutputStream。
"格式化程序"应为我们要使用的任何格式化程序(内置或者自定义实现)。在默认情况下,StreamHandler使用SimpleFormatter(如果我们使用零参数构造函数)。
套接字处理程序
一个" SocketHandler"通过一个套接字将日志消息写到某个网络地址。日志消息通过网络原始发送(作为文本)。它们没有包装在HTTP请求或者类似的请求中。
这是创建SocketHandler
的方法:
SocketHandler socketHandler = new SocketHandler(host, port);
host参数应该是一个指向域名(主机)的字符串。 " port"参数应该是要连接的TCP端口。
这是在构造函数中使用具体值的示例:
SocketHandler socketHandler = new SocketHandler("Hyman.com", 80);
内存处理程序
" MemoryHandler"是一种将" LogRecords"内部保存在缓冲区中的处理程序。当内部缓冲区已满时,新的LogRecords开始覆盖缓冲区中最旧的记录。
当某个触发事件发生时,内部缓冲区中的LogRecord会刷新到目标Handler,该LogHandler会将LogRecords写入外部系统。例如,当记录某个最低日志级别的" LogRecord"时,可能会推入" LogRecord"的整个缓冲区。
我们还可以调用push()
方法来强制将缓冲区中的LogRecord
刷新到目标Handler
。
这是创建MemoryHandler
的两个例子:
MemoryHandler handler = MemoryHandler(); MemoryHandler handler = MemoryHandler( targetHandler, bufferSize, pushLevel);
第一个构造函数创建一个MemoryHandler
,它使用从配置文件获得的配置。
第二个构造函数使用目标Handler,特定的内部缓冲区大小以及将LogRecord推送到目标Handler的最小推送级别来创建MemoryHandler。
这是在第二个构造函数中使用缓冲区大小和推入级别参数的具体值的示例:
MemoryHandler handler = MemoryHandler( targetHandler, 10, Level.WARNING);