Spring Boot 集成Log4j2 使用JDBCAppender把日志写入数据库

慕兴平
2023-12-01

 本文主要介绍Log4j2记录日志到MySQL

一、创建数据库和表

1、创建log数据库:logs

2、创建日志表

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------

-- Table structure for log_table

-- ----------------------------

DROP TABLE IF EXISTS `log_table`;

CREATE TABLE `log_table` (

  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',

  `log_date` datetime DEFAULT NULL COMMENT '日志日期时间',

  `log_level` varchar(32) DEFAULT NULL COMMENT '日志级别',

  `log_class` varchar(255) DEFAULT NULL COMMENT '日志所在的类',

  `line_number` int(255) DEFAULT NULL COMMENT '在类中的行数',

  `log_detail` longtext COMMENT '日志详情',

  PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8;

二、项目配置

1、添加依赖

<!--用于日志存储,不引用打包时会找不到JDBCAppender -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
  1. 创建文件log4j2.properties,配置log数据源
#log数据源
log.datasource.url=jdbc:mysql://localhost:3306/logs?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true
log.datasource.username=root
log.datasource.pwd=root
log.datasource.driverClassName=com.mysql.jdbc.Driver

3、创建连接工厂类,继承JDBCAppender,由于Spring通过new的对象无法通过注解加载配置文件中的参数,所有需要用到Properties对象,所以创建一个工具类PropertiesUtil,获取log4j2.properties文件里的值

package com.iyungu.biss.manage.configurer;


import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.alibaba.druid.wall.violation.ErrorCode;
import com.iyungu.biss.manage.common.utils.PropertiesUtil;
import org.apache.log4j.jdbc.JDBCAppender;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

/**
 * @Author: yangzhiwei@iyungu.com
 * @Description:
 * @Date: 2019/4/17
 * @Modified By:
 */
public class LogConnectionFactory extends JDBCAppender {
    private static String resource = "log4j2-log.properties";
    private static String url = PropertiesUtil.getProperty(resource, "log.datasource.url");
    private static String driverClassName = PropertiesUtil.getProperty(resource, "log.datasource.driverClassName");
    private static String username = PropertiesUtil.getProperty(resource, "log.datasource.username");
    private static String psw = PropertiesUtil.getProperty(resource, "log.datasource.pwd");

    //Druid数据源
    private DruidDataSource dataSource;

    private static LogConnectionFactory logConnectionFactory;

    public LogConnectionFactory() {
        super();
    }

    /**
     * 如果数据库连接对象不为空和没有被关闭的话,关闭数据库连接
     * @param con
     */
    @Override
    protected void closeConnection(Connection con) {
        try {
            if (con != null && !con.isClosed()) {
                con.close();
            }
        } catch (SQLException e) {
            errorHandler.error("Error closing MyJDBCAppender.closeConnection() 's connection", e, ErrorCode.HINT_NOT_ALLOW);
        }
    }

    /**
     * 建立数据库连接
     * @return
     * @throws SQLException
     */
    @Override
    protected Connection getConnection() throws SQLException {
        if(dataSource == null) {
            Properties result = new Properties();
            result.put("driverClassName", driverClassName);
            result.put("url", url);
            result.put("username", username);
            result.put("password", psw);
            try {
                dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(result);
            } catch (Exception e) {
                // Druid数据库源对象产生失败后,取消初始化
                try {
                    uninitialize();
                } catch (Exception e2) {
                }
            }
        }
        return dataSource.getConnection();
    }

    /**
     * 取消初始化
     */
    public void uninitialize() {
        try {
            if (dataSource != null) {
                dataSource.close();
            }
        } catch (Exception e) {
        } finally {
            super.close();
        }
    }

    /**
     * 调用数据库连接
     * @return
     * @throws SQLException
     */
    public static Connection getDataSourceConnection() throws SQLException {
        if (logConnectionFactory == null) {
            logConnectionFactory = new LogConnectionFactory();
        }
        return logConnectionFactory.getConnection();
    }
}      

4、创建PropertiesUtil类

package com.iyungu.biss.manage.common.utils;


import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;

public class PropertiesUtil {
   
   /**
    * 读取properties文件
    * @param resource 文件名称
    * @return
    */
   public static Properties getProperties(String resource){
      
      Properties properties = new Properties();
      try {
         InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(resource);
         properties.load(is);
      } catch (IOException ioe) {
         ioe.printStackTrace();
         throw new RuntimeException(ioe);
      }
      return properties;
   }
   
   /**
    * 获取property
    * @param key key
    * @return value
    */
   public static String getProperty(String resource,String key){
      Properties properties = PropertiesUtil.getProperties(resource);
      return properties.getProperty(key);
   }
   
   /**
     * 获取getPropertyNew
     * @param key key
     * @return value
     */
    public static String getPropertyNew(String resource,String key){
        Properties properties = new Properties();
        try {
            InputStreamReader is = new InputStreamReader(Thread.currentThread().getContextClassLoader().getResourceAsStream(resource), "UTF-8");
            properties.load(is);
        } catch (IOException ioe) {
            ioe.printStackTrace();
            throw new RuntimeException(ioe);
        }
        return properties.getProperty(key);
    }
   
   /**
    * 获取匹配的属性列表
    * @param resource 资源文件名称
    * @param prefix 匹配的前缀字符串
    * @return 匹配的结果存入List
    */
   public static List getMatchProperties4List(String resource,String prefix){
      Properties properties = PropertiesUtil.getProperties(resource);
      List list = new ArrayList();
      Iterator it = properties.entrySet().iterator();
      Object key = null;
      Object value = null;
      while (it.hasNext()) {
         Map.Entry entry = (Map.Entry) it.next();
         key = entry.getKey();
         if(key.toString().startsWith(prefix)){
            value = entry.getValue();
            list.add(value);
         }
       }
      return list;
   }
}

5、配置log4j2.xml

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

<!--设置log4j的自身日志级别为warn,配置自动检测时间间隔为30秒-->

<Configuration status="WARN" monitorInterval="30"> 
    <properties>
        <property name="LOG_HOME">logs</property>

<!--配置日志表名-->
        <property name="LOG_TABLE_NAME">log_table</property>
    </properties>

    <Appenders>

<!--配置控制台日志-->
        <Console name="console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %level %logger{36}@%method:%line - %msg%n"/>
        </Console>

<!--配置日志写入文件-->
        <RollingRandomAccessFile name="infoLog" fileName="${LOG_HOME}/log.log"
                                 filePattern="${LOG_HOME}/log.%d{yyyy-MM-dd}-%i.log.gz" append="true">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %level %logger{36}@%method:%line - %msg%n"/>
            <Policies>

<!-- 对应 filePattern维度,此处为天数-->
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>            

</Policies>
            <DefaultRolloverStrategy max="30"/>
        </RollingRandomAccessFile>
        <JDBC name="databaseAppender" tableName="${LOG_TABLE_NAME}">

<!--配置数据库连接com.iyungu.biss.xxx.configurer.LogConnectionFactory-->
            <ConnectionFactory class="com.iyungu.biss.xxx.configurer.LogConnectionFactory" method="getDataSourceConnection" />
            <Column name="log_date" pattern="%d{yyyy-MM-dd HH:mm:ss}"/>
            <Column name="log_level" pattern="%p" />
            <Column name="log_class" pattern="%c" />
            <Column name="line_number" pattern="%L"/>
            <Column name="log_detail" pattern="%m"/>
        </JDBC>
    </Appenders>

    <Loggers>
        <Root level="INFO">
            <AppenderRef ref="console"/>
            <!--<AppenderRef ref="infoLog" />-->
            <AppenderRef ref="databaseAppender"/>
        </Root>
        <logger name="org.springframework" level="INFO"> <!--spring日志-->
            <AppenderRef ref="infoLog" />
        </logger>
        <logger name="org.mybatis" level="info" additivity="false"> <!--myBatis日志-->
            <!--<AppenderRef ref="infoLog" />-->
            <AppenderRef ref="databaseAppender"/>
        </logger>
        <Logger name="com.iyungu.biss" level="info" additivity="false"> <!--业务日志-->
            <!--<AppenderRef ref="infoLog" />-->
            <AppenderRef ref="databaseAppender"/>
        </Logger>
    </Loggers>

</Configuration>

 

 

 类似资料: