一、背景
虽然log4j很强大,能够将日志输出到文件、DB、ES等。可是有时候确不免彻底适合本身,此时咱们就须要自定义Appender,使日志输出到指定的位置上。php
本文,将经过两个例子说明自定义APPender,一个是将日志写入文件中,另外一个是将日志发送到远程Thrift服务中。java
本文代码详见:https://github.com/hawkingfoo/log-demogit
二、自定义文件Appender
2.1 定义文件Appender
先上代码:github
-
@Plugin(name = "FileAppender", category = "Core", elementType = "appender", printObject = true)
-
public class FileAppender extends AbstractAppender {
-
-
-
-
public FileAppender(String name, Filter filter, Layout<? extends Serializable> layout, boolean ignoreExceptions, String fileName) {
-
super(name, filter, layout, ignoreExceptions);
-
this.fileName = fileName;
-
-
-
-
public void append(LogEvent event) {
-
final byte[] bytes = getLayout().toByteArray(event);
-
-
-
-
-
-
-
public static FileAppender createAppender(@PluginAttribute("name") String name,
-
@PluginAttribute("fileName") String fileName,
-
@PluginElement("Filter") final Filter filter,
-
@PluginElement("Layout") Layout<? extends Serializable> layout,
-
@PluginAttribute("ignoreExceptions") boolean ignoreExceptions) {
-
-
LOGGER.error(
"no name defined in conf.");
-
-
-
-
layout = PatternLayout.createDefaultLayout();
-
-
-
if (!createFile(fileName)) {
-
-
-
return new FileAppender(name, filter, layout, ignoreExceptions, fileName);
-
-
-
private static boolean createFile(String fileName) {
-
Path filePath = Paths.
get(fileName);
-
-
-
if (Files.exists(filePath)) {
-
-
-
Files.createFile(filePath);
-
}
catch (IOException e) {
-
LOGGER.error(
"create file exception", e);
-
-
-
-
-
-
private void writerFile(byte[] log) {
-
-
Files.write(Paths.
get(fileName), log, StandardOpenOption.APPEND);
-
}
catch (IOException e) {
-
LOGGER.error(
"write file exception", e);
-
-
-
上面代码有几个须要注意的地方:spring
@Plugin..
注解:这个注解,是为了在以后配置log4j2.xml
时,指定的Appender Tag。
- 构造函数:除了使用父类的之外,也能够增长一些本身的配置。
- 重写
append()
方法:这里面须要实现具体的逻辑,日志的去向。
createAppender()
方法:主要是接收log4j2.xml中的配置项。
2.2 添加log4j2.xml配置
-
<?xml version="1.0" encoding="UTF-8"?>
-
-
<configuration status="INFO" monitorInterval="30">
-
-
-
<console name="Console" target="SYSTEM_OUT">
-
-
<PatternLayout pattern="%highlight{[ %p ] [%-d{yyyy-MM-dd HH:mm:ss}] [%l] %m%n}"/>
-
-
-
-
<FileAppender name="File" fileName="log.log">
-
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] [%-5p] {%F:%L} - %m%n" />
-
-
-
-
-
-
-
<logger name="org.springframework" level="INFO"></logger>
-
<logger name="org.mybatis" level="INFO"></logger>
-
-
<appender-ref ref="Console"/>
-
<appender-ref ref="File"/>
-
-
-
备注:mybatis
- 上面的log配置,一共配了2个输出。一个是终端输出,一个是采用自定义的FileAppender输出到文件中。
<FileAppender>
标签要与自定义Appender中的类注解保持一致。
2.3 测试
-
public class TestLogFile {
-
private static final Logger logger = LogManager.getLogger(TestLogFile.class);
-
-
public static void main(String[] args) {
-
-
-
-
-
日志输出
日志输出
能够看到,日志一共输出了2份,一份到终端中,一份到log.log
中(具体的文件路径可在log4j2.xml中配置)。app
三、自定义Thrift Appender
上一节,主要是日志的文件输出。有时咱们须要将日志发送给日志收集服务,常见的方法能够写一个日志收集Agent,收集日志;或者将日志输出方当成客户端直接发送到远程。ide
下文,经过自定义Appender的方式,将日志输出到远程的RPC服务中。函数
3.1 Thrift RPC服务
假设如今有一个Thrift RPC服务,实时接收日志消息。它的定义是下面的样子:测试
-
-
-
-
string getLogRes(1:string log);
-
服务很简单,入参是log,返回值是String。
Thrift相关知识能够查看,Thrift RPC服务10分钟上手。
3.2 定义ThriftAppender
-
@Plugin(name = "ThriftAppender", category = "Core", elementType = "appender", printObject = true)
-
public class ThriftAppender extends AbstractAppender {
-
-
private LogServer.Client client;
-
private TTransport transport;
-
-
-
public ThriftAppender(String name, Filter filter, Layout<? extends Serializable> layout, boolean ignoreExceptions, String host) {
-
super(name, filter, layout, ignoreExceptions);
-
-
createThriftClient(host);
-
-
-
-
public void append(LogEvent event) {
-
final byte[] bytes = getLayout().toByteArray(event);
-
-
String response = client.getLogRes(
new String(bytes));
-
System.out.println(response);
-
-
-
-
-
-
-
-
public static ThriftAppender createAppender(@PluginAttribute("name") String name,
-
@PluginAttribute("host") String host,
-
@PluginElement("Filter") final Filter filter,
-
@PluginElement("Layout") Layout<? extends Serializable> layout,
-
@PluginAttribute("ignoreExceptions") boolean ignoreExceptions) {
-
-
LOGGER.error(
"no name defined in conf.");
-
-
-
-
layout = PatternLayout.createDefaultLayout();
-
-
return new ThriftAppender(name, filter, layout, ignoreExceptions, host);
-
-
-
-
-
-
-
-
-
-
private void createThriftClient(String host) {
-
-
transport =
new TFramedTransport(new TSocket(host, 9000));
-
-
TProtocol protocol =
new TBinaryProtocol(transport);
-
client =
new LogServer.Client(protocol);
-
LOGGER.info(
"create client success");
-
-
LOGGER.error(
"create file exception", e);
-
-
-
备注:
除了和文件Appender相同的外,这里须要注意两个地方。一个是Thrift Client的建立,另外一个Thrift发送log。
具体的发送逻辑,在append()
方法中实现。
3.3 添加log4j2.xml配置
-
<?xml version="1.0" encoding="UTF-8"?>
-
-
<configuration status="INFO" monitorInterval="30">
-
-
-
<console name="Console" target="SYSTEM_OUT">
-
-
<PatternLayout pattern="%highlight{[ %p ] [%-d{yyyy-MM-dd HH:mm:ss}] [%l] %m%n}"/>
-
-
-
-
<ThriftAppender name="Thrift" host="127.0.0.1">
-
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] [%-5p] {%F:%L} - %m%n" />
-
-
-
-
-
-
<logger name="org.springframework" level="INFO"></logger>
-
<logger name="org.mybatis" level="INFO"></logger>
-
-
<appender-ref ref="Console"/>
-
<appender-ref ref="Thrift"/>
-
-
-
-
这里一样是定义了两个输出路径,一个是终端,一个是Thrift服务。
3.4 测试
-
public class TestThriftFile {
-
private static final Logger logger = LogManager.getLogger(TestThriftFile.class);
-
-
public static void main(String[] args) {
-
-
-
-
-
Server端
Client端
能够看出,Server端成功接收到了log。