使用自定义Log4j2 Appender实现日志入库:详细指南

在现代应用程序开发中,日志记录是监控、调试和审计的重要组成部分。Log4j2 是一个功能强大的日志框架,支持灵活的日志配置和扩展。通过自定义 Appender,我们可以将日志信息存储到数据库、消息队列或其他存储系统中。

本文将详细介绍如何使用自定义 Log4j2 Appender 将日志信息存储到数据库中,并提供完整的配置和代码示例。


目录

  1. 概述

  2. Log4j2 自定义 Appender 的工作原理

  3. 配置 Log4j2

    • 编写 log4j2.xml
    • 配置 Logger 和 Appender
  4. 实现自定义 Appender

    • 实现具体 Appender
  5. 使用自定义 Logger

  6. 总结


1. 概述

Log4j2 提供了强大的扩展能力,允许开发者通过自定义 Appender 将日志输出到任意目标。本文将演示如何创建一个自定义 Appender,将日志信息存储到数据库中。我们将使用 MySQL 作为示例数据库。


2. Log4j2 自定义 Appender 的工作原理

Log4j2 的 Appender 是负责将日志事件输出到目标(如控制台、文件、数据库等)的组件。自定义 Appender 的核心步骤如下:

  1. 继承 AbstractAppender :创建一个类继承自 AbstractAppender,并实现 append 方法。
  2. 处理日志事件 :在 append 方法中,解析日志事件并将其存储到数据库。
  3. 注册 Appender :通过 @Plugin 注解将自定义 Appender 注册到 Log4j2 中。
  4. 配置 Log4j2 :在 log4j2.xml 中配置自定义 Appender 和 Logger。

3. 配置 Log4j2

3.1 编写 log4j2.xml

log4j2.xml 中配置自定义 Appender 和 Logger。

xml 复制代码
<Configuration status="WARN">
    <Appenders>
        <!-- 自定义 Appender -->
        <CustomDatabaseAppender name="CustomDatabaseAppender">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n"/>
        </CustomDatabaseAppender>

        <!-- 控制台 Appender 作为备用 -->
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n"/>
        </Console>
    </Appenders>

    <Loggers>
        <!-- 定义 Logger -->
        <Logger name="savelog" level="INFO" additivity="false">
            <AppenderRef ref="CustomDatabaseAppender"/>
        </Logger>

        <!-- 根 Logger -->
        <Root level="error">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

3.2 配置说明

  • CustomDatabaseAppender :定义了一个自定义 Appender,使用 PatternLayout 指定日志格式。
  • Logger :定义了一个名为 savelog 的 Logger,将日志事件传递给 CustomDatabaseAppender
  • Root Logger :作为备用,将所有 ERROR 级别的日志输出到控制台。

4. 实现自定义 Appender

4.1 实现具体 Appender

创建一个自定义的 Appender 类 CustomDatabaseAppender,继承自 AbstractAppender,并重写 append 方法。

typescript 复制代码
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.layout.PatternLayout;

import java.io.Serializable;
import java.util.Map;

@Plugin(name = "CustomDatabaseAppender", category = "Core", elementType = "appender")
public class CustomDatabaseAppender extends AbstractAppender {

    @Autowired
    private SaveLogMapper saveLogMapper;

    protected CustomDatabaseAppender(String name, Filter filter, Layout<? extends Serializable> layout, boolean ignoreExceptions) {
        super(name, filter, layout, ignoreExceptions);
    }

    @Override
    public void append(LogEvent event) {
        // 获取日志信息
        String loggerName = event.getLoggerName();
        String level = event.getLevel().name();
        Map<String, String> contextMap = event.getContextData().toMap();

        // 保存日志到数据库
        LogEntity logEntity = new LogEntity();
        logEntity.setInfo(contextMap.get("info"));
        logEntity.setServerip(contextMap.get("serverip"));
        // 其他字段设置...

        saveLogMapper.insertToMysql(logEntity);
    }

    @PluginFactory
    public static CustomDatabaseAppender createAppender(
            @PluginAttribute("name") String name,
            @PluginElement("Filter") Filter filter,
            @PluginElement("Layout") Layout<? extends Serializable> layout) {
        if (name == null) {
            throw new IllegalArgumentException("No name provided for CustomDatabaseAppender");
        }
        if (layout == null) {
            layout = PatternLayout.createDefaultLayout();
        }
        return new CustomDatabaseAppender(name, filter, layout, true);
    }
}

4.2 注册 Appender

通过 @Plugin 注解将自定义 Appender 注册到 Log4j2 中。


5. 使用自定义 Logger

在代码中使用自定义 Logger 非常简单:

java 复制代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

public class MyService {
    private static final Logger log = LoggerFactory.getLogger("savelog");

    public void doSomething() {
        // 设置日志上下文信息
        MDC.put("info", "This is a log message");
        MDC.put("serverip", "192.168.1.1");

        // 记录日志信息,日志将被传递给 CustomDatabaseAppender 并保存到数据库
        log.info("This is a log message that will be saved to the database.");
    }
}

5.1 使用说明

  • LoggerFactory.getLogger("savelog") :获取名为 savelog 的 Logger 实例。
  • MDC.put :设置日志上下文信息,这些信息可以在 append 方法中获取并存储到数据库。
  • log.info :记录日志信息,日志将被传递给 CustomDatabaseAppender 并保存到数据库。

6. 总结

通过自定义 Log4j2 Appender,我们可以轻松地将日志信息存储到数据库中。本文详细介绍了如何实现和配置自定义 Appender,并提供了完整的代码示例。希望这篇博客能帮助你更好地理解和使用 Log4j2 的自定义日志功能。


附录:完整代码示例

CustomDatabaseAppender.java

typescript 复制代码
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.layout.PatternLayout;

import java.io.Serializable;
import java.util.Map;

@Plugin(name = "CustomDatabaseAppender", category = "Core", elementType = "appender")
public class CustomDatabaseAppender extends AbstractAppender {

    @Autowired
    private SaveLogMapper saveLogMapper;

    protected CustomDatabaseAppender(String name, Filter filter, Layout<? extends Serializable> layout, boolean ignoreExceptions) {
        super(name, filter, layout, ignoreExceptions);
    }

    @Override
    public void append(LogEvent event) {
        // 获取日志信息
        String loggerName = event.getLoggerName();
        String level = event.getLevel().name();
        Map<String, String> contextMap = event.getContextData().toMap();

        // 保存日志到数据库
        LogEntity logEntity = new LogEntity();
        logEntity.setInfo(contextMap.get("info"));
        logEntity.setServerip(contextMap.get("serverip"));
        // 其他字段设置...

        saveLogMapper.insertToMysql(logEntity);
    }

    @PluginFactory
    public static CustomDatabaseAppender createAppender(
            @PluginAttribute("name") String name,
            @PluginElement("Filter") Filter filter,
            @PluginElement("Layout") Layout<? extends Serializable> layout) {
        if (name == null) {
            throw new IllegalArgumentException("No name provided for CustomDatabaseAppender");
        }
        if (layout == null) {
            layout = PatternLayout.createDefaultLayout();
        }
        return new CustomDatabaseAppender(name, filter, layout, true);
    }
}

log4j2.xml

xml 复制代码
<Configuration status="WARN">
    <Appenders>
        <!-- 自定义 Appender -->
        <CustomDatabaseAppender name="CustomDatabaseAppender">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n"/>
        </CustomDatabaseAppender>

        <!-- 控制台 Appender 作为备用 -->
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n"/>
        </Console>
    </Appenders>

    <Loggers>
        <!-- 定义 Logger -->
        <Logger name="savelog" level="INFO" additivity="false">
            <AppenderRef ref="CustomDatabaseAppender"/>
        </Logger>

        <!-- 根 Logger -->
        <Root level="error">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

MyService.java

java 复制代码
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

public class MyService {
    private static final Logger log = LoggerFactory.getLogger("savelog");

    public void doSomething() {
        // 设置日志上下文信息
        MDC.put("info", "This is a log message");
        MDC.put("serverip", "192.168.1.1");

        // 记录日志信息,日志将被传递给 CustomDatabaseAppender 并保存到数据库
        log.info("This is a log message that will be saved to the database.");
    }
}

通过以上步骤,你可以轻松地将日志信息存储到数据库中,并灵活地扩展 Log4j2 的功能。希望这篇博客对你有所帮助!

相关推荐
日月星辰Ace8 分钟前
jwk-set-uri
java·后端
用户1083863868015 分钟前
95%开发者不知道的调试黑科技:Apipost让WebSocket开发效率翻倍的秘密
前端·后端
疏狂难除31 分钟前
基于Rye的Django项目通过Pyinstaller用Github工作流简单打包
后端·python·django
钢板兽41 分钟前
Java后端高频面经——JVM、Linux、Git、Docker
java·linux·jvm·git·后端·docker·面试
未完结小说1 小时前
声明式远程调用:OpenFeign 基础教程
后端
MickeyCV1 小时前
《苍穹外卖》SpringBoot后端开发项目重点知识整理(DAY1 to DAY3)
java·spring boot·后端·苍穹外卖
uhakadotcom1 小时前
ClickHouse入门:快速掌握高性能数据分析
后端·面试·github
雷渊1 小时前
深入分析mysql中的binlog和redo log
java·后端·面试
uhakadotcom1 小时前
Pydantic Extra Types:扩展数据类型的强大工具
后端·面试·github
uhakadotcom1 小时前
Spring Fu:让Spring Boot启动提速40%的黑科技
后端·面试·github