`
mwhgJava
  • 浏览: 94695 次
  • 性别: 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使用笔记

    1.该笔记中详细的介绍了log4j的作用和优势、具体地讲解了log4j的使用步骤和详细配置。 2.深入的说明了log4j在项目中的重要地位以及给项目带来的影响,同时说明了log4j的优化。 3.该笔记从log4j的简介/入门开始介绍,到...

    Log4j日志包

    log4j.rootLogger=debug,CONSOLE,testfile,A1,MAIL ################### # Console Appender ################### log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.Target=...

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

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

    logging-log4j2-log4j-2.15.0-rc2.zip maven 资源库

    针对Log4j 2 远程代码执行漏洞,需要用到的升级资源包,适用于maven资源库,包括log4j,log4j-core,log4j-api,log4j-1.2-api,log4j-jpa等全套2.15.0 maven资源库jar包。如果是maven本地仓库使用,需要将zip包解压...

    log4j日志驱动包

    Log4j比较全面的配置 log4j.rootLogger=DEBUG,CONSOLE,A1,im log4j.addivity.org.apache=true # 应用于控制台 log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.Threshold=DEBUG log4j....

    log4j中配置日志文件相对路径方法分析

    log4j中配置日志文件相对路径方法分析 方法一、 解决的办法自然是用相对路径代替绝对路径,其实log4j的FileAppender本身就有这样的机制,如:log4j.appender.logfile.File=${WORKDIR}/logs/app.log 其中“${...

    log4j.CustomLogAppender 限制log4j文件保存天数

    每天生成一个log4j日志文件,如果只需要将最近一段时间内的日志文件保留,以前或更早的文件不用保留。例如只保留最近一周的日志,日志文件保留3天等等这些。。。通过这个jar包就可以实现。 log4j.properties文件在...

    log4j按功能保存日志

    log4j按功能保存日志

    使用log4j2实现日志数据脱敏

    使用log4j2实现日志数据脱敏

    tomcat6.0 配log4j日志的必须文件及配置过程

    tomcat6.0 配log4j日志的必须文件及配置过程 tomcat6-------lib | |--------tomcat-juli-adapters.jar | |--------log4j.jar | |--------log4j.properites | |----bin |--------tomcat-juli.jar 最后把log4...

    log4j.jar各个版本

    apache-log4j-1.2.15.jar, apache-log4j-extras-1.0.jar, apache-log4j-extras-1.1.jar, apache-log4j.jar, log4j-1.2-api-2.0.2-javadoc.jar, log4j-1.2-api-2.0.2-sources.jar, log4j-1.2-api-2.0.2.jar, log4j-...

    Log4j日志配置说明,Log4j日志配置说明

    Log4j日志配置说明,Log4j日志配置说明Log4j日志配置说明,Log4j日志配置说明

    tomcat下的log4j日志配置

    tomcat下的log4j日志配置,给tomcat配置log4j有好几种方法,我知道的有: 一、tomcat级别的统一日志管理 二、每个webapp分别配置log4j

    apache-log4j-2.17.0 核心jar包

    Log4j 是一个日志记录框架,Log4j 2 是对 Log4j 的升级,提供了重大改进,超越其前身 Log4j 1.x,并提供许多其它现代功能 ,例如对标记的支持、使用查找的属性替换、lambda 表达式与日志记录时无垃圾等。 Apache ...

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

    log4j配置文件以及配置文件说明 包里有一个log4j配置文件 和一个配置详解

    log4j 同时按日期和文件大小分割日志

    已经封装好,把log4j.appender.fileout=org.apache.log4j.Log4JDateAndSizeSplit 即可,其余和原api一样: log4j.appender.fileout.MaxFileSize=10240KB log4j.appender.fileout.MaxBackupIndex=20

    log4j-core-2.15.0.jar log4j-2.15.0-rc2

    Apache log4j2零日漏洞,根据 log4j-2.15.0-rc2 版本编译生成log4j-api-2.15.0.jar 1.解压你的jar jar xvf XXX.jar 2. 删除旧版本jar cd ./BOOT-INF/lib rm -rf log4j-api-*.jar 3. 上传新版本log4j-api-2.15.0....

    log4j日志管理

    log4j日志管理log4j日志管理log4j日志管理log4j日志管理log4j日志管理

    log4j-1.2.9

    设置log4j的根目录,值为 日志等级(DEBUG,INFO,WARN,ERROR,FATAL) , 输出目标名称 log4j.rootLogger=DEBUG,A1 设置输出方式,常用的有: ConsoleAppender 在控制器中输出信息 RollingFileApperder 在文件中输出...

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

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

Global site tag (gtag.js) - Google Analytics