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

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 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 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. “1.0” encoding=”UTF-8″?>
  2. console>
  3. FileAppender>
  4. appenders>
  5. logger>
  6. logger>
  7. root>
  8. loggers>
  9. configuration>

备注:

  • 上面的log配置,一共配了2个输出。一个是终端输出,一个是采用自定义的FileAppender输出到文件中。
  • <fileappender></fileappender>标签要与自定义Appender中的类注解保持一致。

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 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 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. “1.0” encoding=”UTF-8″?>
  2. console>
  3. ThriftAppender>
  4. appenders>
  5. logger>
  6. logger>
  7. root>
  8. loggers>
  9. 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。

Original: https://www.cnblogs.com/goody9807/p/9780982.html
Author: PointNet
Title: log4j2自定义Appender(输出到文件/RPC服务中)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/551830/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球