一、Log4j知识了解
在自定义Appende之前,我们先来简单了解下Log4j
1、Log4j是什么
Log4j是由Apache提供的日志操作包,用于帮助用户处理日志信息。
2、log4j的作用
log4j提供了方法使我们能将日志信息分级存储。其次,log4j提供了日志不同的存储方式,我们可以将日志发送到控制台,或者文件,或者数据库中等等。
3、Log4j三大组件
Logger:日志写出器,负责供客户端代码调用,用于输入日志信息。Log4j 允许开发人员定义多个Logger,每个Logger拥有自己的名字,Logger之间通过名字来表明隶属关系。有一个Logger称为Root,它永远存在,且不能通过名字检索或引用,可以通过Logger.getRootLogger()方法获得,其它Logger通过 Logger.getLogger(String name)方法或Logger.getLogger(Class class)方法获得。
appender:配属日志写出目的地,输出日志信息到指定位置。Log4j中支持多种appender,如 console、files、GUI components、NT Event Loggers等,一个Logger可以拥有多个Appender,也就是你既可以将Log信息输出到屏幕,同时存储到一个文件中。
Layout:控制Log信息的输出方式,也就是格式化输出的信息。
4、log4j支持将数据输出到哪里?
org.apache.log4j.ConsoleAppender (控制台)
org.apache.log4j.FileAppender (文件)
org.apache.log4j.DailyRollingFileAppender (每天产生一个日志文件)
org.apache.log4j.RollingFileAppender (文件大小到达指定尺寸的时候产生一个 新的文件)
org.apache.log4j.WriterAppender (将日志信息以流格式发送到任意指定的地方)
如果需要输出日志信息到多个目的地,配置多个appender
5.log4j支持数据输出格式有哪些?
org.apache.log4j.HTMLLayout (以 HTML 表格形式布局)
org.apache.log4j.PatternLayout (可以灵活地指定布局模式)
org.apache.log4j.SimpleLayout (包含日志信息的级别和信息字符串)
org.apache.log4j.TTCCLayout (包含日志产生的时间、线程、类别等等信息)
6. PatternLayout输出格式如何使用
用户自定义日志输出格式类似于printf的输出类型,其中:
%m 输出代码中指定的消息
%p 输出优先级,即 DEBUG , INFO , WARN , ERROR , FATAL
%r 输出自应用启动到输出该 log 信息耗费的毫秒数
%c 输出所属的类目,通常就是所在类的全名
%t 输出产生该日志事件的线程名
%n 输出一个回车换行符, Windows 平台为 “rn” , Unix 平台为 “n”
%d 输出日志时间点的日期或时间,默认格式为 ISO8601 ,也可以在其后指定格式,比如: %d{yyy MMM dd HH:mm:ss,SSS} ,输出类似: 2002 年 10 月 18 日 22 : 10 : 28 , 921
%l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例: Testlog4.main(TestLog4.java:10)
例如:log4j.appender.appenderName.layout.ConversionPattern = [%-5p]%d{ISO8601}, [Class]%-c{1}, %m%n
输出:[WARN ]2015-09-16 17:04:30,908, [Class]PageNotFound, No mapping found for HTTP request with URI [/favicon.ico] in DispatcherServlet with name 'sentry'
7.组件的执行顺序及关系
调用Log4j输出日志时,调用各个组件的顺序:
-
日志信息传入 Logger。
-
将日志信息封装成 LoggingEvent 对象并传入 Appender。
-
在 Appender 中调用 Filter 对日志信息进行过滤,调用 Layout 对日志信息进行格式化,然后输出。
二、为何要自定Appender
有时候log4j官方提供的appender不一定满足自己的需求,例如需要将日志写入es,这时就需要自定义了
三、实现代码
要实现自定义Appender,继承AppenderSkeleton类即可,然后重写几个方法便可
打印日志核心方法:abstract protected void append(LoggingEvent event);
初始化加载资源:public void activateOptions(),默认实现为空
释放资源:public void close()
是否需要按格式输出文本:public boolean requiresLayout()
正常情况下我们只需要覆盖append方法即可。然后就可以在log4j中使用了
自定义输出组件MyAppender
package com.log.appender.log4j;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;
/**
* @author tanpeng
*/
public class MyAppender extends AppenderSkeleton {
private String account ;
@Override
protected void append(LoggingEvent event) {
System.out.println("Hello, " + account + " : "+ event.getMessage());
}
@Override
public void close() {
}
@Override
public boolean requiresLayout() {
return false;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
}
log4j配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration PUBLIC
"-//APACHE//DTD LOG4J 1.2//EN"
"http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/doc-files/log4j.dtd">
<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
<!--控制台输出日志-->
<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %5p %c [userId:%X{userId},tradeId:%X{traceId}] - %m%n"/>
</layout>
</appender>
<appender name="myAppender" class="com.log.appender.log4j.MyAppender">
<param name="account" value="tp"></param>
<layout class="org.apache.log4j.PatternLayout">
<param name='ConversionPattern' value='[%-5p][%d{yyyy/MM/dd HH:mm:ss}][%X{TRACE_ID}][%X{LOGGER_FILTER1}][%X{LOGGER_FILTER2}][%l][%m]%n'/>
</layout>
</appender>
<root>
<priority value="DEBUG"/>
<appender-ref ref="CONSOLE"/>
<appender-ref ref="myAppender"/>
</root>
</log4j:configuration>
测试类
package com.log.alarm.appender.log4j.log4j;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import com.google.common.collect.Lists;
import org.apache.log4j.Logger;
import org.apache.log4j.MDC;
import org.apache.log4j.xml.DOMConfigurator;
import org.junit.Test;
import java.net.URL;
import java.util.concurrent.TimeUnit;
/**
* Unit test for simple App.
*/
public class Log4jTest {
public static final Logger logger = Logger.getLogger(Log4jProTest.class);
@Test
public void testProducerErrorLog() throws Exception {
final URL url = Log4jTest.class.getResource("/test_log4j.xml");
DOMConfigurator.configure(url);
loopLog();
}
public void loopLog() throws InterruptedException {
String now = DateUtil.now();
now = "log4j_test_" + now+","+RandomUtil.randomString(3);
logger.error(now);
logger.info(now);
logger.debug(now);
logger.trace(now);
logger.warn(now);
logger.debug("qqqq");
}
}