初始化servlet
还可以使用一个特别的servlet来进行log4j初始化。这里就是个示例:
package com.foo;
import org.apache.log4j.PropertyConfigurator;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.io.IOException;
public class Log4jInit extends HttpServlet {
public
void init()
{
String prefix = getServletContext().getRealPath("/");
String file = getInitParameter("log4j-init-file");
// if the log4j-init-file is not set, then no point in trying
if(file != null) {
PropertyConfigurator.configure(prefix+file);
}
}
public
void doGet(HttpServletRequest req, HttpServletResponse res) {
}
}
|
在web.xml文件里为你的网络应用程序定义下面的servlet。
<servlet>
<servlet-name>log4j-init</servlet-name>
<servlet-class>com.foo.Log4jInit</servlet-class>
<init-param>
<param-name>log4j-init-file</param-name>
<param-value>WEB-INF/classes/log4j.lcf</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
|
编写一个initialization servlet 是最灵活的方式来初始化log4j。不受任何限制,你可以在这个servlet的init()
方法里放入任何代码。
Nested Diagnostic Contexts
实际情况下的大多数系统都需要同时处理多个客户端问题。在这种系统的典型的多线程实施中,通常是不同的线程去分别处理不同的客户需求。Logging特别适合于复杂的程序跟踪和排错。一个通常的处理办法是通过给每个客户产生一个新的分离开的logger来达到把不同的客户的日志输出信息区分开来。但这促进了loggers的增殖,加大了logging的管理负担。
一个更简洁的技术是独特地标记来自于同一个客户的每一个日志请求。Neil Harrison 在他的书中"Patterns for Logging Diagnostic Messages," in Pattern Languages of Program Design 3, edited by R. Martin, D. Riehle, and F. Buschmann (Addison-Wesley, 1997) 对这个方法进行了描述。 Pattern Languages of Program Design 3
要独特地标记每个日志请求,用户把上下文信息送入NDC,NDC是 Nested Diagnostic Context 的缩写。NDC类展示如下。
public class NDC {
// Used when printing the diagnostic
public static
String get();
// Remove the top of the context from the NDC.
public static
String pop();
// Add diagnostic context for the current thread.
public static
void push(String message);
// Remove the diagnostic context for this thread.
public static
void remove();
}
NDC类是作为一个保存线程上下文的stack 来独个线程(per thread) 管理的。注意,org.apache.log4j.NDC
类中所有的方法都是静态的。假设NDC打印功能被打开,每一次若有日志请求,相应的log4j组件就把这个当前线程的整个 NDC stack包括在日志输出中打印出来。这样做不需要用户干预,用户只需要在代码中明确指定的几点通过push
和pop
方法将正确的信息放到NDC中就行了。相反,per-client logger方法需要在代码中作很多更改。
为了说明这一点,我们举个有关一个servlet把信息内容发送到多个客户的例子。这个Servlet程序在开始接到客户端的请求,执行其它代码之前,首先创建一个NDC。该上下文信息可能是客户端的主机名,以及其他请求中固有的信息,通常是包含在cookies中的信息。因此即便这个Servlet程序可能同时要服务于多个客户,由相同的代码启动的这些logs,比如属于同一个logger,它们仍然能够被区分开来,因为不同的客户端请求具有不同的NDC stack。这与在客户请求期间把一个实例化的logger传递给所有要被执行的代码的复杂性形成了反差。
然而,一些复杂的应用程序,比如虚拟网络服务器,必须依据虚拟主机的上下文语言环境,以及发布请求的软体组件来作不同的log。最近的log4j发行版支持多阶层树。这一功能的加强允许每个虚拟主机拥有它自己的logger阶层版本。
性能
一个经常提出的争议就是logging的运算开销。这种关注是有道理的,因为即便是一个中等大小的应用程序至少也会产生几千个log输出。许多工作都花费在测量和改进logging性能上。Log4j声明它是快速和灵活的:速度第一,灵活性第二。
用户需要清楚地了解下面这些与性能相关的问题:
-
Logging performance when logging is turned off.
当logging被完全关闭或只是set of levels被关闭,日志请求的开销是方法的调用和整数的比较。在一个233 MHz Pentium II机器上,这种开销通常在5 to 50 毫微秒范围内。 set of levels
不过,方法的调用包含有参数的建造上的“隐闭”开销。
例如下面的logger cat
程序段中:
logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
不管message被日志记录与否,构造message参数的开销还是有的,比如说,把整数i 和数组entry[i]
转化为String,连接中间字串。参数构造的这种开销可能很高,它依赖于所介入的参数数量有多少。
为了避免这种参数构造开销,把以上的代码段改写为:
if(logger.isDebugEnabled() {
logger.debug("Entry number: " + i + " is " + String.valueOf(entry[i]));
}
如果排错功能不被使用,就不会有参数构造上的开销。但是,另一方面,如果 logger的排错功能被起用,就会有俩倍的开销用于评估logger是否被起用:一次是判断debug
Enabled
,一次是判断debug是否被启用。但这不是极重的负担,因为评估logger的时间只有整个log语句执行时间的1%
在log4j中,把日志请求作为Logger类的实例。Logger是类而不是接口,这主要是为了减少程序调用的开销,但牺牲了接口所能带来的灵活性。
有些用户使用预处理或compile-time技术来编译所有log语句。这样logging方面的性能是很好。但是,因为resulting application binary没有包含任何log语句,你不能对这个二进制程序起用logging。在我看来,这是为了小的性能增加而付出大的代价。
-
The performance of deciding whether to log or not to log when logging is turned on.
本质上影响性能的因素是logger的层次关系。当logging功能被打开时,log4j仍然需要把log请求的级别去与request logger的级别作比较。不过,有些loggers 并没有指派的优先级别,但它可以从它的上一层logger那里继承优先级别。因此在继承优先级之前,logger可能需要搜索它的ancestors。
Log4j在这方面做了很大的努力,以便使这种阶层的优先级别搜寻(hierarchy walk )尽可能的快速。例如,子代loggers仅仅只和它们现有的ancestors链接。在前面的BasicConfigurator
示例中,叫做com
.foo.Bar
的logger 直接与 root logger链接,绕过了不存在的com或com.foo
loggers。这极大地提高了优先级别搜寻的速度。
阶层的优先级搜寻(walking the hierarchy )的开销在于它比logging完全关闭时要慢三倍。
-
Actually outputting log messages
这里讲的是log输出的格式化和把log信息发送到目标所在地的开销。Log4j在这方面也下了大力气让格式化能尽快执行。对appenders也是一样。通常情况下,格式化语句的开销可能是100到300微秒的处理时间。确切数字请参看 org.apache.log4.performance.Logging 。
尽管log4j具有许多功能特性,但速度是第一设计目标。为了提高性能,一些 log4j的部件曾经被重写过许多次。即使这样,log4j的贡献者们不断提出新的优化办法。你应该很惊喜地发现当以SimpleLayout 来配置时,性能测试显示使用 log4j日志和使用System.out.println
日志同样快。
结论
Log4j是用Java编写的一个非常流行的logging开发包。它的一个显著特性之一是在loggers里运用了继承的概念。使用这种logger的层次关系,就可能准确地控制每一个log语句的输出。这样减少了log信息的输出量并降低了logging的开销。
Log4j API的优点之一是它的可管理性。一旦log语句被插入到代码中,他们就能被配置文件控制而无需重新编译源代码。Log信息的输出能够有选择地被起用或关闭,用户能够按照自己选择的格式将这些log信息输出到许多不同的输出设备中。Log4j软件包的设计是在代码中保留log语句的同时不造成很大的性能损失。
相关推荐
"Log4j简明手册"提供了关于这个强大日志框架的详细指南,适合初学者和经验丰富的开发者。通过学习手册,你可以了解如何配置和使用Log4j,提升你的日志管理能力,从而更好地调试和监控你的Java应用。阅读"log4j简明...
Log4j简明手册 转载的资料 希望对大家有用
### Log4j简明手册深度解析 #### 一、Log4j概览 Log4j是一款功能强大且灵活的开源日志框架,由Apache Software Foundation维护。它支持开发者以自定义的时间间隔控制日志的输出,同时具备平滑的学习曲线,易于上手...
Log4j简明手册 几乎所有的大型应用程序都包括它的自己的日志和跟踪API。顺应这个规则,E.U. SEMPER 项目决定写它自己的跟踪PAI。这是1996年初。在无数次加强,几次变形和许多工作后,那个API变成了如今的Log4j,一个...
Log4j是一个广泛使用的Java日志框架,它允许开发者灵活地控制日志的输出,并通过外部配置文件实现运行时的动态调整。Log4j的设计旨在提供一个平滑的学习曲线,使其易于理解和使用,而且它已经对多种编程语言提供了...
Log4j的相关资料 其中包括个人积累收集的: Log4j简明手册 log4j使用大全 深入学习log4j 关于Log4j比较全面的配置 Java logging API如何与log4j较量 在Java应用软件中加入logging 等许多...
### MATLAB简明手册知识点概述 MATLAB是一种广泛应用于科学计算、算法开发以及数据分析的强大工具。这份简明手册针对MATLAB的常用命令进行了整理与分类,旨在帮助用户快速查阅和掌握核心功能。 ### 编辑与特殊...
R5 I* ~: k6 g1 B$ @4 Z- j' B ( y: ] o$ r9 C( \/ x5 b @: a站点(Site)是由一个或多个IP子网中的一组计算机,确保目录信息的有效交换,站点中的计算机需要很好地连接,尤其是子网内的计算机。站点和域名称空间...
8. "log4j简明使用文档.doc":Log4j是Java日志框架,这个文档提供了关于如何配置和使用Log4j的日志记录功能。 9. "appfuse.txt"和"5.txt":这两个可能是额外的文本文件,可能包含了开发者笔记、命令行脚本或其他...
8. **Log4j1.2**:Log4j是Java日志记录的开源工具,它的API文档解释了如何配置和使用日志系统,便于进行调试和问题追踪。 9. **Struts2_zh**:Struts2是一个基于MVC模式的Java Web框架,其API文档涵盖了Action、...
* I, j: 虚数单位。 * Inf: 无穷大。 * Nan: 非数值。 * Flops: 浮点运算次数。 十、函数和变量 * Nargin: 函数输入变量数。 * Nargout: 函数输出变量数。 * Computer: 计算机类型。 * Isieee: 当计算机采用 IEEE...