问题
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