惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
人人都是产品经理
人人都是产品经理
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
T
The Exploit Database - CXSecurity.com
N
News and Events Feed by Topic
Latest news
Latest news
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
CXSECURITY Database RSS Feed - CXSecurity.com
IT之家
IT之家
V
V2EX
WordPress大学
WordPress大学
Apple Machine Learning Research
Apple Machine Learning Research
Cisco Talos Blog
Cisco Talos Blog
K
Kaspersky official blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
S
SegmentFault 最新的问题
小众软件
小众软件
A
Arctic Wolf
酷 壳 – CoolShell
酷 壳 – CoolShell
腾讯CDC
宝玉的分享
宝玉的分享
Last Week in AI
Last Week in AI
G
GRAHAM CLULEY
罗磊的独立博客
T
Tor Project blog
C
Cisco Blogs
美团技术团队
博客园 - Franky
月光博客
月光博客
博客园 - 三生石上(FineUI控件)
T
Threat Research - Cisco Blogs
Cyberwarzone
Cyberwarzone
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
有赞技术团队
有赞技术团队
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Security Latest
Security Latest
博客园 - 司徒正美
Hugging Face - Blog
Hugging Face - Blog
Spread Privacy
Spread Privacy
J
Java Code Geeks
C
CERT Recently Published Vulnerability Notes
大猫的无限游戏
大猫的无限游戏
S
Securelist
The Cloudflare Blog
博客园 - 叶小钗
D
Darknet – Hacking Tools, Hacker News & Cyber Security
阮一峰的网络日志
阮一峰的网络日志
雷峰网
雷峰网
Project Zero
Project Zero

博客园 - PointNet

log4j2发送消息至Kafka log4j 不同模块输出到不同的文件 shell之磁盘容量检查,配合crontab可以定时清理磁盘 spring注解之@profile How to do conditional auto-wiring in Spring? MyBatis传入参数为集合 list 数组 map写法 Spring Boot @Autowired 没法自动注入的问题 mysql5.5 uuid做主键与int做主键的性能实测 dom4j解析xml字符串实例 spring自动注入是单例还是多例?单例如何注入多例? Spring中Bean的五个作用域 【总结】瞬时高并发(秒杀/活动)Redis方案 浅谈分布式事务 基于Redis实现分布式锁 MySQL事务隔离级别详解 Redis学习手册(Sorted-Sets数据类型) Redis的快照持久化-RDB与AOF Redis - 事务 ArrayList、Vector、HashMap、HashTable、HashSet的默认初始容量、加载因子、扩容增量
log4j2自定义Appender(输出到文件/RPC服务中)
PointNet · 2018-10-12 · via 博客园 - PointNet

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. public FileAppender(String name, Filter filter, Layout<? extends Serializable> layout, boolean ignoreExceptions, String fileName) {

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

  5. this.fileName = fileName;

  6. public void append(LogEvent event) {

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

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

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

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

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

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

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

  14. layout = PatternLayout.createDefaultLayout();

  15. if (!createFile(fileName)) {

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

  17. private static boolean createFile(String fileName) {

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

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

  20. Files.createFile(filePath);

  21. } catch (IOException e) {

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

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

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

  25. } catch (IOException e) {

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

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

  • @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. <console name="Console" target="SYSTEM_OUT">

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

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

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

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

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

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

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

备注:

  • 上面的log配置,一共配了2个输出。一个是终端输出,一个是采用自定义的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) {

日志输出

日志输出

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

3、自定义Thrift Appender

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

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

3.1 Thrift RPC服务

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

  1. string getLogRes(1:string log);

服务很简单,入参是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. public ThriftAppender(String name, Filter filter, Layout<? extends Serializable> layout, boolean ignoreExceptions, String host) {

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

  7. createThriftClient(host);

  8. public void append(LogEvent event) {

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

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

  11. System.out.println(response);

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

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

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

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

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

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

  18. layout = PatternLayout.createDefaultLayout();

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

  20. private void createThriftClient(String host) {

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

  22. TProtocol protocol = new TBinaryProtocol(transport);

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

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

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

备注:
除了和文件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. <console name="Console" target="SYSTEM_OUT">

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

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

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

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

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

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

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

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

3.4 测试

  1. public class TestThriftFile {

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

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

Server端

Client端

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