log4j2自定义Appender(输出到文件/RPC服务中)

栏目: 服务器 · 发布时间: 6年前

内容简介:虽然log4j很强大,可以将日志输出到文件、DB、ES等。但是有时候确难免完全适合自己,此时我们就需要自定义Appender,使日志输出到指定的位置上。本文,将通过两个例子说明自定义APPender,一个是将日志写入文件中,另一个是将日志发送到远程Thrift服务中。本文代码详见:

1、背景

虽然log4j很强大,可以将日志输出到文件、DB、ES等。但是有时候确难免完全适合自己,此时我们就需要自定义Appender,使日志输出到指定的位置上。

本文,将通过两个例子说明自定义APPender,一个是将日志写入文件中,另一个是将日志发送到远程Thrift服务中。

本文代码详见: https://github.com/hawkingfoo/log-demo

2、自定义文件Appender

2.1 定义文件Appender

先上代码:

  1. @Plugin(name = "FileAppender", category = "Core", elementType = "appender", printObject = true)

  2. public class FileAppender extends AbstractAppender {

  3. private String fileName;

  4. /* 构造函数 */

  5. public FileAppender(String name, Filter filter, Layout<? extends Serializable> layout, boolean ignoreExceptions, String fileName) {

  6. super(name, filter, layout, ignoreExceptions);

  7. this.fileName = fileName;

  8. }

  9. @Override

  10. public void append(LogEvent event) {

  11. final byte[] bytes = getLayout().toByteArray(event);

  12. writerFile(bytes);

  13. }

  14. /* 接收配置文件中的参数 */

  15. @PluginFactory

  16. public static FileAppender createAppender( @PluginAttribute( "name") String name,

  17. @PluginAttribute( "fileName") String fileName,

  18. @PluginElement( "Filter") final Filter filter,

  19. @PluginElement( "Layout") Layout<? extends Serializable> layout,

  20. @PluginAttribute( "ignoreExceptions") boolean ignoreExceptions) {

  21. if (name == null) {

  22. LOGGER.error( "no name defined in conf.");

  23. return null;

  24. }

  25. if (layout == null) {

  26. layout = PatternLayout.createDefaultLayout();

  27. }

  28. // 创建文件

  29. if (!createFile(fileName)) {

  30. return null;

  31. }

  32. return new FileAppender(name, filter, layout, ignoreExceptions, fileName);

  33. }

  34. private static boolean createFile(String fileName) {

  35. Path filePath = Paths. get(fileName);

  36. try {

  37. // 每次都重新写文件,不追加

  38. if (Files.exists(filePath)) {

  39. Files.delete(filePath);

  40. }

  41. Files.createFile(filePath);

  42. } catch (IOException e) {

  43. LOGGER.error( "create file exception", e);

  44. return false;

  45. }

  46. return true;

  47. }

  48. private void writerFile(byte[] log) {

  49. try {

  50. Files.write(Paths. get(fileName), log, StandardOpenOption.APPEND);

  51. } catch (IOException e) {

  52. LOGGER.error( "write file exception", e);

  53. }

  54. }

  55. }

上面代码有几个需要注意的地方:

  • @Plugin.. 注解:这个注解,是为了在之后配置 log4j2.xml 时,指定的Appender Tag。
  • 构造函数:除了使用父类的以外,也可以增加一些自己的配置。
  • 重写 append() 方法:这里面需要实现具体的逻辑,日志的去向。
  • createAppender() 方法:主要是接收log4j2.xml中的配置项。

2.2 添加log4j2.xml配置

  1. <?xml version= "1.0" encoding= "UTF-8" ?>

  2. < configuration status= "INFO" monitorInterval= "30">

  3. < appenders>

  4. <!--这个输出控制台的配置-->

  5. < console name= "Console" target= "SYSTEM_OUT">

  6. <!--输出日志的格式-->

  7. < PatternLayout pattern= "%highlight{[ %p ] [%-d{yyyy-MM-dd HH:mm:ss}] [%l] %m%n}"/>

  8. </ console>

  9. <!-- 这个就是自定义的Appender -->

  10. < FileAppender name= "File" fileName= "log.log">

  11. < PatternLayout pattern= "%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] [%-5p] {%F:%L} - %m%n" />

  12. </ FileAppender>

  13. </ appenders>

  14. < loggers>

  15. <!--过滤掉spring和mybatis的一些无用的DEBUG信息-->

  16. < logger name= "org.springframework" level= "INFO"> </ logger>

  17. < logger name= "org.mybatis" level= "INFO"> </ logger>

  18. < root level= "all">

  19. < appender-ref ref= "Console"/>

  20. < appender-ref ref= "File"/>

  21. </ root>

  22. </ loggers>

  23. </ configuration>

备注:

<FileAppender>

2.3 测试

  1. public class TestLogFile {

  2. private static final Logger logger = LogManager.getLogger(TestLogFile.class);

  3. public static void main (String[] args) {

  4. logger.info( "1");

  5. logger.info( "2");

  6. logger.info( "3");

  7. }

  8. }

log4j2自定义Appender(输出到文件/RPC服务中)

日志输出

log4j2自定义Appender(输出到文件/RPC服务中)

日志输出

可以看到,日志一共输出了2份,一份到终端中,一份到 log.log 中(具体的文件路径可在log4j2.xml中配置)。

3、自定义Thrift Appender

上一节,主要是日志的文件输出。有时我们需要将日志发送给日志收集服务,常见的方法可以写一个日志收集Agent,收集日志;或者将日志输出方当成客户端直接发送到远程。

下文,通过自定义Appender的方式,将日志输出到远程的RPC服务中。

3.1 Thrift RPC服务

假设现在有一个Thrift RPC服务,实时接收日志消息。它的定义是下面的样子:

  1. namespace java thrift

  2. service LogServer {

  3. string getLogRes( 1: string log);

  4. }

服务很简单,入参是log,返回值是String。

Thrift相关知识可以查看, Thrift RPC服务10分钟上手

3.2 定义ThriftAppender

  1. @Plugin(name = "ThriftAppender", category = "Core", elementType = "appender", printObject = true)

  2. public class ThriftAppender extends AbstractAppender {

  3. private LogServer.Client client;

  4. private TTransport transport;

  5. /* 构造函数 */

  6. public ThriftAppender (String name, Filter filter, Layout<? extends Serializable> layout, boolean ignoreExceptions, String host) {

  7. super(name, filter, layout, ignoreExceptions);

  8. // 创建客户端

  9. createThriftClient(host);

  10. }

  11. @Override

  12. public void append (LogEvent event) {

  13. final byte[] bytes = getLayout().toByteArray(event);

  14. try {

  15. String response = client.getLogRes( new String(bytes));

  16. System.out.println(response);

  17. } catch (TException e) {

  18. e.printStackTrace();

  19. }

  20. }

  21. /* 接收配置文件中的参数 */

  22. @PluginFactory

  23. public static ThriftAppender createAppender (@PluginAttribute( "name") String name,

  24. @ PluginAttribute ( "host") String host,

  25. @ PluginElement ( "Filter") final Filter filter,

  26. @ PluginElement ( "Layout") Layout<? extends Serializable> layout,

  27. @ PluginAttribute ( "ignoreExceptions") boolean ignoreExceptions) {

  28. if (name == null) {

  29. LOGGER.error( "no name defined in conf.");

  30. return null;

  31. }

  32. if (layout == null) {

  33. layout = PatternLayout.createDefaultLayout();

  34. }

  35. return new ThriftAppender(name, filter, layout, ignoreExceptions, host);

  36. }

  37. @Override

  38. public void stop () {

  39. if (transport != null) {

  40. transport.close();

  41. }

  42. }

  43. private void createThriftClient (String host) {

  44. try {

  45. transport = new TFramedTransport( new TSocket(host, 9000));

  46. transport.open();

  47. TProtocol protocol = new TBinaryProtocol(transport);

  48. client = new LogServer.Client(protocol);

  49. LOGGER.info( "create client success");

  50. } catch (Exception e) {

  51. LOGGER.error( "create file exception", e);

  52. }

  53. }

  54. }

备注:

除了和文件Appender相同的外,这里需要注意两个地方。一个是Thrift Client的创建,另一个Thrift发送log。

具体的发送逻辑,在 append() 方法中实现。

3.3 添加log4j2.xml配置

  1. <?xml version= "1.0" encoding= "UTF-8" ?>

  2. < configuration status= "INFO" monitorInterval= "30">

  3. < appenders>

  4. <!--这个输出控制台的配置-->

  5. < console name= "Console" target= "SYSTEM_OUT">

  6. <!--输出日志的格式-->

  7. < PatternLayout pattern= "%highlight{[ %p ] [%-d{yyyy-MM-dd HH:mm:ss}] [%l] %m%n}"/>

  8. </ console>

  9. <!-- 这个就是自定义的Appender -->

  10. < ThriftAppender name= "Thrift" host= "127.0.0.1">

  11. < PatternLayout pattern= "%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] [%-5p] {%F:%L} - %m%n" />

  12. </ ThriftAppender>

  13. </ appenders>

  14. < loggers>

  15. <!--过滤掉spring和mybatis的一些无用的DEBUG信息-->

  16. < logger name= "org.springframework" level= "INFO"> </ logger>

  17. < logger name= "org.mybatis" level= "INFO"> </ logger>

  18. < root level= "all">

  19. < appender-ref ref= "Console"/>

  20. < appender-ref ref= "Thrift"/>

  21. </ root>

  22. </ loggers>

  23. </ configuration>

这里同样是定义了两个输出路径,一个是终端,一个是Thrift服务。

3.4 测试

  1. public class TestThriftFile {

  2. private static final Logger logger = LogManager.getLogger(TestThriftFile.class);

  3. public static void main (String[] args) {

  4. logger.info( "a");

  5. logger.info( "b");

  6. logger.info( "c");

  7. }

  8. }

log4j2自定义Appender(输出到文件/RPC服务中)

Server端

log4j2自定义Appender(输出到文件/RPC服务中)

Client端

可以看出,Server端成功接收到了log。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Database Design and Implementation

Database Design and Implementation

Edward Sciore / Wiley / 2008-10-24 / 1261.00 元

* Covering the traditional database system concepts from a systems perspective, this book addresses the functionality that database systems provide as well as what algorithms and design decisions will......一起来看看 《Database Design and Implementation》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具