spring-boot + slf4j + log4j2 + h2database + HikariCP(文件和代码配置log4j2)

版权声明:本文为博主hecb原创文章,未经博主允许不得转载。 https://blog.csdn.net/blvyoucan/article/details/79081991

目录结构

这里写图片描述

Maven依赖

maven配置文件pom.xml如下↓

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>blvyoucan</groupId>
    <artifactId>springboot-log4j2-h2database-sample</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <!--去掉默认日志框架logback↓-->
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--增加log4j2依赖↓-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>
        <!--增加h2database依赖↓-->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.196</version>
        </dependency>
        <!--增加HikariCP连接池依赖↓-->
        <dependency>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP</artifactId>
            <version>2.7.4</version>
        </dependency>
        <!--spring jdbc↓-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
    </dependencies>

    <properties>
        <start-class>com.Application</start-class>
        <java.version>1.8</java.version>
        <hibernate.version>5.2.1.Final</hibernate.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

H2数据源配置

h2数据源配置类↓

package com.config;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

@Configuration
public class H2DataSrouceConfiguration {

    @Bean(name = "h2Template")
    public JdbcTemplate h2Template(){
        return new JdbcTemplate(h2DataSource());
    }

    @Bean(name = "h2DataSource")
    //用于识别application.yaml中的db.h2前辍↓
    @ConfigurationProperties("db.h2")
    public DataSource h2DataSource(){
        //采用h2的内存(mem)数据库模式,并设置了数据库初始化脚本h2_init.sql↓
        return DataSourceBuilder.create()
                .url("jdbc:h2:mem:test;INIT=RUNSCRIPT FROM 'classpath:/h2_init.sql'")
                .driverClassName("org.h2.Driver")
                .username("testdb")
                .password("testdb").build();
    }
}

application.yaml片断,使用配置文件指定h2数据库使用Hikari连接池,可以灵活更换连接池↓

...
db:
  h2:
    type: com.zaxxer.hikari.HikariDataSource
    maximum-pool-size: 5
...

h2_init.sql,创建MEMO_LOGS表↓

--日志表,主键自增
CREATE TABLE IF NOT EXISTS MEMO_LOGS (
  EVENT_ID INT AUTO_INCREMENT(1,1) PRIMARY KEY,
  EVENT_DATE DATETIME,
  LEVEL VARCHAR(20),
  LOGGER VARCHAR(255),
  MESSAGE VARCHAR(255),
  THROWABLE CLOB,
  EXT_FIELD VARCHAR(255)
);

log4j2配置

log4j2的ConnectionDataSource类↓

package com.config;

import org.apache.logging.log4j.core.appender.db.jdbc.ConnectionSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

@Component
public class LogDBConnectionSource implements ConnectionSource{

    @Autowired
    @Qualifier("h2DataSource")
    private DataSource h2DataSource;

    @Override
    public Connection getConnection() throws SQLException {
        return h2DataSource.getConnection();
    }

    @Override
    public String toString() {
        return h2DataSource.toString();
    }
}

代码实现log4j2的JdbcAppender配置↓

package com.config;

import com.utils.LogMarker;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.db.jdbc.ColumnConfig;
import org.apache.logging.log4j.core.appender.db.jdbc.JdbcAppender;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.filter.MarkerFilter;
import org.slf4j.MarkerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;

@Configuration
public class LogDBConfiguration {

    @Autowired
    private LogDBConnectionSource logDBConnectionSource;

    @PostConstruct
    public void doConfigure(){
        final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
        final org.apache.logging.log4j.core.config.Configuration config = ctx.getConfiguration();

        //定义表MEMO_LOGS各字段写入的内容↓
        ColumnConfig[] columnConfigs = new ColumnConfig[6];
        columnConfigs[0] = ColumnConfig.createColumnConfig(config,"EVENT_DATE",null,null,"true",null,null);
        columnConfigs[1] = ColumnConfig.createColumnConfig(config,"LEVEL","%level",null,"false",null,null);
        columnConfigs[2] = ColumnConfig.createColumnConfig(config,"LOGGER","%logger",null,"false",null,null);
        columnConfigs[3] = ColumnConfig.createColumnConfig(config,"MESSAGE","%message",null,"false",null,null);
        columnConfigs[4] = ColumnConfig.createColumnConfig(config,"THROWABLE","%ex{full}",null,"false",null,"true");
        columnConfigs[5] = ColumnConfig.createColumnConfig(config,"EXT_FIELD","%X{ext_field}",null,"false",null,null);

        //log4j2的Filter过滤"DB_LOG"↓
        MarkerFilter markerFilter = MarkerFilter.createFilter("DB_LOG", Filter.Result.ACCEPT, Filter.Result.DENY);
        //用于sl4j的Marker同样过滤"DB_LOG"↓
        LogMarker.DB_MARKER = MarkerFactory.getMarker("DB_LOG");

        //使用JdbcAppender连接数据库,"MEMO_LOGS"是h2_init.sql中创建的日志表↓
        final Appender jdbcAppender = JdbcAppender.createAppender("jdbcAppender","true",markerFilter,logDBConnectionSource,null,"MEMO_LOGS",columnConfigs);
        jdbcAppender.start();

        //将JdbcAppender附加到RootLogger中,也可新建另外的logger↓
        LoggerConfig loggerConfig = config.getRootLogger();
        loggerConfig.addAppender(jdbcAppender, null, null);

        ctx.updateLoggers();
    }
}

log4j2-spring.xml配置文件↓

<?xml version="1.0" encoding="UTF-8"?>
<!-- status=debug 可以查看log4j2的装配过程↓ -->
<Configuration status="off">
    <Properties>
        <Property name="LOG_PATH">logs</Property>
        <Property name="LOG_NAME">test</Property>
    </Properties>
    <Appenders>
        <!--日志输出到控制台↓-->
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight{[%t] %-5level %logger{36}} - %msg%n"/>
            <!--防止DB_LOG标记的日志输出到控制台-->
            <MarkerFilter marker="DB_LOG" onMatch="DENY" onMismatch="ACCEPT"/>
        </Console>
        <!--日志输出到文件↓-->
        <RollingRandomAccessFile name="ProductionLog"
                                 fileName="${LOG_PATH}/${LOG_NAME}.log" filePattern="${LOG_PATH}/${LOG_NAME}.%d{yyyy-MM-dd}.log">
            <PatternLayout
                    pattern="%date{yyyy-MM-dd HH:mm:ss.SSS} %level [%thread][%file:%line] - %msg%n" />
            <Policies>
                <TimeBasedTriggeringPolicy interval="1"
                                           modulate="true" />
            </Policies>
        </RollingRandomAccessFile>
    </Appenders>
    <Loggers>
        <!--root的日志输出级别↓-->
        <Root level="INFO">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="ProductionLog" />
        </Root>
    </Loggers>
</Configuration>

LogMarker辅助类↓

package com.utils;

import org.slf4j.Marker;

public class LogMarker {
    public static Marker DB_MARKER;
}

使用和验证

controller类

package com.controllers;

import com.utils.LogMarker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/test")
public class TestContollers {

    private static final Logger logger = LoggerFactory.getLogger(TestContollers.class);

    @Autowired
    @Qualifier("h2Template")
    private JdbcTemplate h2Template;

    @RequestMapping(path="/list")
    public List<Map<String,Object>> list(){
        try{
            throw new Exception("异常测试");
        }catch (Exception e){
            //将额外字段写入ThreadContext↓
            MDC.put("ext_field","额外字段");
            //将日志写入数据库↓
            logger.error(LogMarker.DB_MARKER,"测试",e);
//            MDC.clear();
//            logger.error(LogMarker.DB_MARKER,"测试",e);
        }
        //从数据库中读取日志↓
        String sql = "SELECT EVENT_ID,EVENT_DATE,LEVEL,EXT_FIELD,LOGGER,MESSAGE,THROWABLE FROM MEMO_LOGS";
        return h2Template.queryForList(sql);
    }
}

启动类Application

package com;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;

@SpringBootApplication
@EnableAutoConfiguration(exclude = {HibernateJpaAutoConfiguration.class})
public class Application {

    public static void main(String[] args){
        SpringApplication.run(Application.class);
    }
}

完整的application.yaml

---
server:
  port: 8080
db:
  h2:
    type: com.zaxxer.hikari.HikariDataSource
    maximum-pool-size: 5
#默认的spring boot datasource 配置
#spring:
#  datasource:
#    type: com.zaxxer.hikari.HikariDataSource
#    hikari:
#      maximum-pool-size: 5

运行启动类Application
浏览器访问http://localhost:8080/test/list

[{"EVENT_ID":1,"EVENT_DATE":1516178866892,"LEVEL":"ERROR","EXT_FIELD":"额外字段","LOGGER":"com.controllers.TestContollers","MESSAGE":"测试","THROWABLE":"java.lang.Exception: 异常测试\r\n\tat com.controllers.TestContollers.list(TestContollers.java:29)\r\n\tat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n\tat sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\r\n\tat sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\r\n\tat java.lang.reflect.Method.invoke(Method.java:498)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)\r\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)\r\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)\r\n\tat org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)\r\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:635)\r\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)\r\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:742)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n\tat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n\tat org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:108)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n\tat org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\r\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)\r\n\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)\r\n\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:478)\r\n\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)\r\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)\r\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)\r\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)\r\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803)\r\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)\r\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)\r\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459)\r\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\r\n\tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\r\n\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\r\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n\tat java.lang.Thread.run(Thread.java:748)\r\n"}]

能够查出数据,说明配置成功
代码下载

猜你喜欢

转载自blog.csdn.net/blvyoucan/article/details/79081991