Log4j 2 in Spring Boot: JDBC appender doesn't write log messages to the DB's column

陌路散爱 提交于 2020-07-23 08:18:28

问题


Lately I'm trying to create and configure JDBC log appender, with usage of Log4j 2.

The main idea is to send a log every time we hit the particular endpoint (Spring service) and put the Hibernate SQL query from the logs, directly to OPERATION_DESCRIPTION column in GDPR_LOG database table.

Here's what I've done so far to achieve it:

  • I excluded in Gradle both 'logback-classic' and 'spring-boot-starter-logging' dependency.
  • I added 'log4j-api', 'log4j-core' and 'spring-boot-starter-log4j2' dependencies.

My current build.gradle looks like this:


    buildscript {
        repositories {
            mavenCentral()
        }
        dependencies {
            classpath 'org.springframework.boot:spring-boot-gradle-plugin:1.5.7.BUILD-SNAPSHOT'
        }
    }
    
    plugins {
        id "org.springframework.boot" version "1.5.7.RELEASE"
    }
    
    apply plugin: 'java'
    apply plugin: 'idea'
    apply plugin: 'io.spring.dependency-management'
    apply plugin: 'org.springframework.boot'
    apply plugin: 'war'
    
    war {
        baseName = 'CprUI'
        version =  '1.0.0-SNAPSHOT'
    }
    
    repositories {
        mavenLocal()
        mavenCentral()
        jcenter()
        maven { url "http://repo.spring.io/libs-snapshot" }
    }
    
    sourceCompatibility = 1.8
    targetCompatibility = 1.8
    
    dependencies {
        compile("org.springframework.boot:spring-boot-starter-web")
        compile("org.springframework.boot:spring-boot-starter-actuator")
        compile("org.springframework.boot:spring-boot-starter-security")
        compile("org.springframework.ldap:spring-ldap-core")
        compile("org.springframework.security:spring-security-ldap")
        compile("org.springframework:spring-tx")
        compile("com.unboundid:unboundid-ldapsdk")
        compile("org.springframework.boot:spring-boot-starter-log4j2")
        compile group: 'org.springframework.boot', name: 'spring-boot-starter-thymeleaf', version: '1.5.7.RELEASE'
        compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa', version: '1.5.7.RELEASE'
        compile group: 'org.springframework.boot', name: 'spring-boot-starter-parent', version: '1.5.7.RELEASE', ext: 'pom'
        compile("com.oracle:ojdbc6:11.2.0.3")
        compile("org.apache.any23:apache-any23-encoding:2.0")
        compile("org.apache.commons:commons-csv:1.5")
        compile group: 'org.thymeleaf.extras', name: 'thymeleaf-extras-springsecurity4', version: '3.0.2.RELEASE'
        compile("org.springframework.boot:spring-boot-starter-web")
        providedRuntime("org.springframework.boot:spring-boot-starter-tomcat")
        testCompile("org.springframework.boot:spring-boot-starter-test")
        testCompile("org.springframework.security:spring-security-test")
        compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.7'
        compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.7'
        compile group: 'org.springframework.boot', name: 'spring-boot-starter-log4j2', version: '2.3.1.RELEASE'
        compile group: 'org.apache.commons', name: 'commons-dbcp2', version: '2.7.0'
        compile group: 'mysql', name: 'mysql-connector-java', version: '8.0.20'
        compile group: 'org.apache.maven.plugins', name: 'maven-compiler-plugin', version: '3.8.1'
    }
    
    configurations.all {
        exclude module: 'spring-boot-starter-logging'
        exclude module: 'logback-classic'
    }

  • Next I created log4j2.properties file and place it under /resources directory. The file looks following:

    appenders = console, db
    appender.console.type = Console
    appender.console.name = STDOUT
    appender.console.layout.type = PatternLayout
    appender.console.layout.pattern = [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n
    
    appender.db.type = JDBC
    appender.db.name = JDBC
    appender.db.layout.type = PatternLayout
    appender.db.layout.pattern = [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n
    appender.db.connectionSource.type= DriverManager
    appender.db.connectionSource.connectionString = my_connection_string
    appender.db.connectionSource.username = my_username
    appender.db.connectionSource.password = my_password
    appender.db.connectionSource.driverClassName = oracle.jdbc.driver.OracleDriver
    appender.db.tableName = GDPR_LOG
    
    appender.db.columnConfigs[0].type = Column
    appender.db.columnConfigs[0].name = OPERATION_DESCRIPTION
    appender.db.columnConfigs[0].pattern =%msg
    appender.db.columnConfigs[0].isUnicode =false
    
    logger.db.name = eu.unicredit.mtr.cpr.logging
    logger.db.level = debug
    logger.db.additivity = false
    logger.db.appenderRef.db.ref = JDBC
    
    rootLogger.level = debug
    rootLogger.appenderRefs = stdout
    rootLogger.appenderRef.stdout.ref = STDOUT

  • Then I updated my application.properties in Spring Boot:

    # LOGGING
    logging.level.org.hibernate.SQLQuery=debug
    logging.level.org.hibernate.type.descriptor.sql=trace
    logging.level.org.springframework.web=${LOG_LEVEL_SPRING:info}
    logging.level.org.hibernate=${LOG_LEVEL_SPRING:debug}
    logging.level.web=${LOG_LEVEL_SPRING:info}
    logging.config=classpath:log4j2.properties
    
    spring.datasource.url=my_datasource
    spring.datasource.username=my_user
    spring.datasource.password=my_password
    spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
    
    server.context-path=/CprUI

Now, I would like to send only the Hibernate queries to the one particular column in db table. The rest of columns are being set by the Spring service methods. Here is how my Entity class and Service's method look like:


    @Entity
    @Table(name = "GDPR_LOG")
    public class Log {
    
        @Id
        @SequenceGenerator(name="DWH_ID_SEQ_GEN", sequenceName="DIM_CPR_COUNTERPARTY_ID", allocationSize=10)
        @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="DWH_ID_SEQ_GEN")
        @Column(name = "ITEM_ID")
        private Long id;
        @Column(name = "CREATION_TIME")
        private String creation_time;
        @Column(name = "LOG_ID")
        private String log_id;
        @Column(name = "USER_ID")
        private String user_id;
        @Column(name = "WORKSTATION_ID")
        private String workstation_id;
        @Column(name = "SESSION_ID")
        private String session_id;
        @Column(name = "OPERATION_DESCRIPTION")
        private String operation_description;
        @Column(name = "APPLICATION_CODE")
        private String app_code;
        @Column(name = "LEGAL_ENTITY")
        private String entity;
    
    //getters, setters


    @Transactional
        public void saveLogForGetAll(Log log) {
            log.setCreation_time(formatDateTime);
            log.setLog_id("SecLog");
            log.setUser_id(checkUser());
            log.setWorkstation_id(checkIP());
            log.setSession_id(session_string);
            log.setApp_code("QRP");
            log.setEntity("AG");
            logsRepository.save(log);
        }

Could you guys please tell me what am I doing wrong here?

Although I specified the field and the value in log4j2.properties file, still I only get nulls there and no Hibernate query is being saved to the database. I'm rather a beginner in Spring and I've been struggling with this topic for two weeks now, so I would be very grateful for any help on that.

Thanks in advance.

Cheers!


回答1:


You are mixing 2 different concepts. Either you let log4j to write logging events to database, or you implement your own logger not related to log4j.

The 1st part shows you are going to use log4j. Fine. But then you don't need JPA entity that uses the same table. Class Log, method saveLogForGetAll(Log log) are just not needed. Log4j will save logging events to database.

The idea of log4j is that the the code should not know anything about how the logging events will be persisted (in a file system, in a database, on some remote device reachable via message queue, etc.)

The 2nd part, class Log and method saveLogForGetAll(Log log), shows that you want to persist logging events directly, without log4j. Then what is the purpose to define a database appender in log4j?

Neither of them or wrong or right. But having 2 independent logging mechanisms makes makes not much sense. But implementing own logging may be pretty complex task: thinks of performance, asynchronous persistence, configuring logging level per classes and packages, retrieving information about the current thread and the method, etc.

That's why I'd suggest you pick up one log4j (or logback), configure and use it. And only if you see that you cannot realize with log4j something really important, only then throw away log4j and implement your own logging.



来源:https://stackoverflow.com/questions/62717600/log4j-2-in-spring-boot-jdbc-appender-doesnt-write-log-messages-to-the-dbs-col

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!