`
mwhgJava
  • 浏览: 98122 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Log4j笔记 第十章 Log4j日志现场的秘密

阅读更多
log4j日志现场背后的秘密

1、什么是日志现场
调用Logger打印日志的地方,称为日志现场。日志现场的属性有:类名、方法名、java文件名、和行数。
下面是一个例子。
LoggerTest.java
import org.apache.log4j.Logger;

public class LoggerTest {
	private static final Logger logger = Logger.getLogger(LoggerTest.class);

	public static void main(String[] args) {
		new LoggerTest().test();
	}

	private void test() {
		// 下面一行就是日志现场 LoggerTest类,test方法,LoggerTest.java文件,第12行。
		logger.debug("Hello, log4j!");
	}
}



2、让log4j在打印日志消息时,也打印出日志现场

在classpath下,添加一个log4j.xml的文件。内容如下:
log4j.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" >
	<appender name="SYSTEM_OUT" class="org.apache.log4j.ConsoleAppender">
		<layout class="org.apache.log4j.PatternLayout">
			<!-- %l表示日志现场,%m表示日志消息,%n表示换行。-->
			<param name="ConversionPattern" value="%l: %m%n"/>
		</layout>
	</appender>
	<root>
		<!-- root 引用SYSTEM_OUT appender-->
		<appender-ref ref="SYSTEM_OUT"/>
	</root>
</log4j:configuration>

再运行上面的文件,
在控制台中,可以看到如下信息:日志现场(类名、方法名、java文件名、和行数)和消息。
consoleView
LoggerTest.test(LoggerTest.java:12): Hello, log4j!


3、封装log4j
在打印需要格式化的字符串时,使用Message.format()会出现如下代码。
logger.debug(MessageFormat.format(“Hello, {0}!”, “log4j”));

当日志级别大于debug时,不需要打印该消息。但是format方法还是会被调用。这造成了浪费。早期log4j官网推荐如下使用方式。
if(logger.isDebugEnabled()){
	logger.debug(MessageFormat.format(“Hello, {0}!”, “log4j”));
}

这样就有了早期对log4j的封装版本。
CLogger.java
public class CLogger {
	public static void debug(Logger logger, String pattern, Object[] arguments) {
		if (logger.isDebugEnabled()) {
			logger.debug(MessageFormat.format(pattern, arguments));
		}
	}
}

DLogger
import java.text.MessageFormat;

import org.apache.log4j.Logger;

public class DLogger {

	public static DLogger getLogger(Class<?> clazz) {
		return new DLogger(clazz);
	}

	private final Logger logger;

	private DLogger(Class<?> clazz) {
		logger = Logger.getLogger(clazz);
	}

	public void debug(String pattern, Object... arguments) {
		if (logger.isDebugEnabled()) {
			logger.debug(MessageFormat.format(pattern, arguments));
		}
	}
}

4、使用封装的Logger出现的问题
一切安好,使用之。
LoggerTestThree.java
public class LoggerTestThree {

	private static final DLogger logger = DLogger
			.getLogger(LoggerTestThree.class);

	public static void main(String[] args) {
		LoggerTestThree loggerTestTwo = new LoggerTestThree();
		loggerTestTwo.test();
	}

	private void test() {
		logger.debug("Hello,{0}!", "log4j"); //我们想将日志现场定在这里。
	}

}

使用上例的log4j.xml
在控制台看到如下信息:
console view
DLogger.debug(DLogger.java:19): Hello,log4j!

打印的日志现场是,调用Logger的debug的地方。经过我们的封装,我们希望日志现场为,调用DLogger的debug方法的地方。于是问题出来了,我们封装了日志类,也转移了日志现场。怎样找到日志现场呢?

5、如果是你,会如何定位日志现场的
首先得理解,java函数调用堆栈。从应用的入口函数(main函数)出发,对其他函数的调用,形成了函数调用堆栈。在java方法中,新建一个Throwable对象,该对象的StackTraceElement[]属性,就包括函数调用堆栈。
看如下代码:
LoggerTestTwo.java
public class LoggerTestTwo {
	private static final MyLogger logger = new MyLogger();

	public static void main(String[] args) {
		LoggerTestTwo loggerTestTwo = new LoggerTestTwo();
		loggerTestTwo.test();
	}

	private void test() {
		logger.debug();
	}

}

MyLogger.java
public class MyLogger {
	public void debug() {
		Throwable throwable = new Throwable();
		StackTraceElement[] stackTraceElements = throwable.getStackTrace();
		for (StackTraceElement element : stackTraceElements) {
			System.out.println(element);
		}
	}
}

运行上面代码,在控制台中可以看到如下信息:创建Throwable时的函数调用堆栈。
consoleView
MyLogger.debug(MyLogger.java:3)
LoggerTestTwo.test(LoggerTestTwo.java:10)
LoggerTestTwo.main(LoggerTestTwo.java:6)

设定我们的MyLogger.debug()方法对应,log4j中的Logger.debug()方法。那么日志现场LoggerTestTwo.test(LoggerTestTwo.java:10)就在其中。我们发现,在被MyLogger.debug() 调用的所有 (包括直接和间接调用) 方法中,新建一个Throwable,其函数调用堆栈都包括这些信息。

6、log4j是如何定位日志现场的

在被Logger的debug方法调用的方法中,创建一个Throwable对象,解析其函数调用堆栈,确认日志现场。
秘密1: fqcn( fqnOfCallingClass,fqnOfCategoryClass) class name of first class considered part of the logging framework.  Location will be site that calls a method on this class.
fqcn是Logger的全类名。在与函数调用堆栈比对中,离开Logger类的下一个地址,就是日志现场。
在logger的debug方法,创建LoggingEvent时,传入一个名为fqcn值为Logger的全类名的字符串。这样在LoggingEven的 getLocationInformation()方法中,创建LocationInfo时,传入一个新建的Throwable和fqcn。
new LocationInfo(new Throwable(), fqnOfCategoryClass);

从LocationInfo中,既可得到日志现场。


7、改进封装log4j的技术
在log4j_1.2.16中,logMF和logSF提供了参考意见。
于是就有了上一章的封装log4j的实现。
分享到:
评论

相关推荐

    老生常谈Log4j和Log4j2的区别(推荐)

    下面我们将从配置文件类型、核心JAR包、文件渲染和Log调用四个方面来比较Log4j和Log4j2的区别。 配置文件类型 Log4j通过一个.properties文件作为主配置文件,而Log4j2则弃用了这种方式,采用的是.xml、.json或者....

    Log4j笔记 第九章 封装Log4j

    《Log4j笔记 第九章 封装Log4j》 在Java开发中,日志记录是一项非常重要的任务,它帮助我们追踪程序运行时的状态,定位和解决错误。Log4j是Apache组织提供的一款强大的日志框架,因其高效、灵活和可配置性而广受...

    SSM整合中的Log4j日志的配置详情

    Log4j 是一个功能强大且广泛使用的日志记录工具,特别是在 SSM(Spring、Spring MVC、Mybatis)整合项目中,合理地配置 Log4j 对项目的日志记录和输出至关重要。本文将详细介绍 SSM 整合中的 Log4j 配置详情,帮助...

    若依框架使用的log4j2.16.0,修复log4j漏洞log4j2下载最新log4j2.16.0下载

    Log4j是一个广泛使用的Java日志记录框架,它允许开发者在应用程序中轻松地记录各种级别的日志信息,如DEBUG、INFO、WARN、ERROR等。在2021年底,一个重大的安全漏洞(CVE-2021-44228)被发现在Log4j2的早期版本中,...

    log4j按功能保存日志

    Log4j是一款广泛使用的Java日志记录框架,它允许开发者按照功能模块或特定需求记录应用程序运行过程中的事件信息。在“log4j按功能保存日志”的场景中,我们通常会利用Log4j的配置灵活性,将不同功能的日志分别写入...

    tomcat下的log4j日志配置

    ### Tomcat 下的 Log4j 日志配置详解 在日常的 Web 开发中,日志记录对于调试问题、监控系统状态以及后期维护来说至关重要。在使用 Apache Tomcat 作为服务器时,合理配置日志框架(如 Log4j)能够极大地提高开发...

    log4j日志配置以及配置文件详解

    Log4j作为Java领域广泛应用的日志框架,提供了强大的日志记录功能和灵活的配置。本文将深入探讨log4j的配置以及配置文件的详解。** 首先,我们要理解什么是`log4j.properties`文件。这是log4j框架的配置文件,使用...

    log4j日志报错解决办法

    Log4j 是一款广泛使用的Java日志记录框架,它提供了灵活的日志配置和丰富的日志级别,便于开发者调试和监控应用程序。在Java开发过程中,如果遇到"log4j:WARN Please initialize the log4j system properly"这样的...

    使用log4j2实现日志数据脱敏

    Log4j2是Apache软件基金会开发的日志框架Log4j的升级版,它具有更高的性能、灵活性和可配置性。Log4j2支持多种日志记录级别(如DEBUG、INFO、WARN、ERROR),并允许通过XML、JSON、YAML或纯Java配置文件进行灵活配置...

    Log4j学习笔记和一套完整定义实例

    **Log4j学习笔记** Log4j是一款广泛应用于Java编程中的日志记录框架,由Apache软件基金会开发。它提供了一套灵活的日志记录系统,帮助开发者在开发过程中追踪应用程序的行为,便于调试、性能分析和问题排查。Log4j...

    tomcat8更换log4j记录日志

    压缩包中的"**lib**"目录可能包含Log4j的必要依赖库,比如`log4j.jar`,这是运行Log4j的日志记录功能所必需的。确保这些库文件被添加到Tomcat的`lib`目录,使得所有部署的应用都能访问Log4j。 综上所述,通过正确...

    log4j+slf4j实现 log4j测试代码,log4j+slf4j实现 log4j测试代码

    Log4j和SLF4J(Simple Logging Facade for Java)是两个广泛使用的日志框架,它们各有优势并常被一起使用以提供更灵活的日志解决方案。本文将详细探讨如何通过SLF4J接口来使用Log4j进行日志记录,并展示一个测试代码...

    Log4j2简介及与Log4j效率对比

    Log4j2是Apache软件基金会推出的日志框架,它是Log4j 1.x的重构版本,旨在提供更为高效且灵活的日志解决方案。与Log4j 1.x相比,Log4j2在设计上进行了重大改进,并解决了Logback等其他日志框架中存在的某些体系结构...

    tomcat9 slf4j+log4j2 写日志.zip

    3. **配置Tomcat**:在`$CATALINA_HOME/lib`目录下添加`log4j-api.jar`和`log4j-slf4j-impl.jar`,这将使Tomcat使用Log4j2作为其内部的日志系统。 4. **排除其他日志实现**:确保你的应用中没有引入其他的日志实现...

    log4j使用与java中log4j记录日志如何写入数据库

    1. **配置文件**:Log4j的配置文件通常是`log4j.properties`或`log4j.xml`,它定义了日志的级别(如DEBUG、INFO、WARN、ERROR、FATAL)、输出目的地(控制台、文件、数据库等)以及布局格式。 2. **日志类**:在...

    log4j(二):动态配置日志输出路径

    Log4j是Apache提供的一款广泛使用的日志框架,它提供了丰富的功能和灵活的配置,使得我们可以根据需要动态地改变日志的输出路径。本文将深入探讨如何在Log4j中实现日志输出路径的动态配置。 首先,我们要理解Log4j...

    log4j2.xml记录日志到到数据库

    Log4j2是一款广泛使用的日志框架,它提供了灵活且高效的日志记录功能。本示例将详细介绍如何配置并使用Log4j2将日志信息记录到MySQL数据库中。 首先,我们要理解Log4j2的核心概念。Log4j2主要包括以下几个组件: 1...

    log4j自定义日志文件名及日志输出格式

    Log4j是Apache提供的一款广泛使用的日志框架,它提供了丰富的配置选项,允许开发者灵活地控制日志输出。当我们面对特定项目需求,比如需要自定义日志文件名和日志输出格式时,Log4j同样提供了相应的解决方案。 首先...

    Log4j2学习用到的jar包及apache-log4j-2.19.0-bin.zip

    分别有disruptor-3.3.4.jar(Log4j2异步日志的底层实现)、log4j-api-2.19.0.jar(log4j门面)、log4j-core-2.19.0.jar(log4j实现)、log4j-slf4j-impl-2.19.0.jar(SLF4J与Log4j绑定)、slf4j-api-1.7.30.jar(SLF...

    log4j-控制指定类,包的日志级别:log4j-demo.zip

    Log4j是Apache提供的一款广泛使用的日志框架,它提供了丰富的功能,包括控制日志级别、定制日志格式、支持多种输出方式等。本示例将详细介绍如何使用Log4j来控制指定类或包的日志级别。 首先,我们来理解日志级别的...

Global site tag (gtag.js) - Google Analytics