본문 바로가기
개발/java,spring,springboot

springboot logback - mongodb appender정의하기

by 개발자종혁 2022. 4. 5.
728x90

1. 설정

1. build.gradle

plugins {
    id 'org.springframework.boot' version '2.5.7'
    id 'io.spring.dependency-management' version '1.0.9.RELEASE'
    id 'java'
}

group = 'kr.co.finotek.demo'
version = '1.0'
sourceCompatibility = '8'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }

    compile.exclude group: "org.slf4j", module: "slf4j-log4j12"
}

repositories {
    mavenCentral()
}

dependencies {
    // web
    implementation ('org.springframework.boot:spring-boot-starter-web'){
        exclude module: 'log4j-slf4j-impl'
        exclude module: 'logback-classic'
        exclude module: 'slf4j-log4j12'
    }
    // log4j 취약점 조치
    implementation group: 'ch.qos.logback', name: 'logback-core', version: '1.2.9'
    implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.9'
    implementation group: 'org.slf4j', name: 'slf4j-api', version: '1.7.32'
    implementation group: 'org.slf4j', name: 'jul-to-slf4j', version: '1.7.32'
    implementation group: 'org.apache.logging.log4j', name: 'log4j-to-slf4j', version: '2.17.1'
    implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.17.1'

    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
    annotationProcessor 'org.projectlombok:lombok'

    // mongodb
    implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'

    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
}

test {
    useJUnitPlatform()
}

1.1 application.yaml

server:
  port: 9090
  servlet:
    timeout: 3600
    encoding:
      charset: UTF-8
      enabled: true
      force: true
      force-request: true
      force-response: true

spring:
  config:
      use-legacy-processing: true
  mvc:
    throw-exception-if-no-handler-found: true
  data:
    mongodb:
        host: ${MONGODB_HOST}
        port: ${MONGODB_PORT}
        username: ${MONGODB_USERNAME}
        password: ${MONGODB_PASSWORD}
        database: ${MONGODB_DATABASE}

2. /main/resources/logback-spring.xml

  • com.path, com.path.log - 개발하는 사람이 정의한 경로
<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%t] %.-5level %logger{30}.%M:%L - %msg %n</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    <appender name="MONGODB" class="com.path.log.MongoDBAppender"></appender>

    <root level="INFO">
        <appender-ref ref="MONGODB" />
        <appender-ref ref="STDOUT" />
    </root>
    <logger name="org.springframework.*" level="INFO" />
    <logger name="com.path.*" level="INFO" />

</configuration>

3. MongoDBAppender.java

package com.path.log;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.TimeZone;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.UnsynchronizedAppenderBase;
import kr.co.finotek.lottecard.common.repository.mongo.logging.LogApiRepository;
import kr.co.finotek.lottecard.log.dao.LogApiDao;

@Component
public class MongoDBAppender extends UnsynchronizedAppenderBase<ILoggingEvent> implements ApplicationContextAware {
    private static LogApiRepository logRepository;

    final static String FORMAT_MESSAGE = "[%s] %s %s.%s:%d - %s";

    // @formatter:off
    protected void append(ILoggingEvent e) {

        LocalDateTime time =  LocalDateTime.ofInstant(Instant.ofEpochMilli(e.getTimeStamp()), TimeZone.getDefault().toZoneId());

        LogApiDao logDao = LogApiDao.builder()
                                    .log(formatLog(e))
                                    .time(time)
                                    .build();
        logRepository.save(logDao);
    }

    private String formatLog(ILoggingEvent event){
        StackTraceElement[] callerData = event.getCallerData();
        StackTraceElement stackTraceElement = callerData[0];
        String threadName = event.getThreadName();
        String level = event.getLevel().toString();
        String logger = event.getLoggerName();
        String msg = event.getFormattedMessage();
        // String className = stackTraceElement.getClassName();
        String method = stackTraceElement.getMethodName();
        int lineNumber = stackTraceElement.getLineNumber();

        return String.format(FORMAT_MESSAGE, threadName, level, logger, method, lineNumber, msg);
    }

    public void setApplicationContext(ApplicationContext applicationContext) {
        if (applicationContext.getAutowireCapableBeanFactory().getBean(LogApiRepository.class) != null) {
            logRepository = (LogApiRepository) applicationContext.getAutowireCapableBeanFactory().getBean(LogApiRepository.class);
        }
    }

}

4. LogApiDao.java - log api document에 저장됨

import java.time.LocalDateTime;

import org.springframework.data.mongodb.core.mapping.Document;
import lombok.Builder;
import lombok.Getter;

@Getter
@Document("log_api")
public class LogApiDao extends CommonLogDao {
    @Id
    private String id;
    private String log;
    private LocalDateTime time;

    @Builder
    public LogApiDao(String id, String log,  LocalDateTime time) {
        this.id = id;
        this.log = log;
        this.time = time;
    }

}

5. LogApiRepository.java


import java.time.LocalDateTime;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.repository.MongoRepository;

import kr.co.finotek.lottecard.log.dao.LogApiDao;

public interface LogApiRepository extends MongoRepository<LogApiDao, String> {
    Page<LogApiDao> findByTimeBetween(LocalDateTime start, LocalDateTime end, Pageable pageable);

    Page<LogApiDao> findByLogContainingAndTimeBetween(String search, LocalDateTime start, LocalDateTime end, Pageable pageable);
}

hibernate 로그 통합

1. application.yaml

spring:
  config:
      use-legacy-processing: true
  mvc:
    throw-exception-if-no-handler-found: true
  jpa:
    properties:
      hibernate:
        '[format_sql]': true
    show-sql: false
  data:
    mongodb:
        host: ${MONGODB_HOST}
        port: ${MONGODB_PORT}
        username: ${MONGODB_USERNAME}
        password: ${MONGODB_PASSWORD}
        database: ${MONGODB_DATABASE}

2. logback-spring.xml

  • <logger name="org.hibernate.SQL" level="DEBUG" />등 추가
<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%t] %.-5level %logger{30}.%M:%L - %msg %n</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    <appender name="MONGODB" class="com.path.log.MongoDBAppender"></appender>

    <root level="INFO">
        <appender-ref ref="MONGODB" />
        <appender-ref ref="STDOUT" />
    </root>
    <logger name="org.springframework.*" level="INFO" />
    <logger name="com.path.*" level="INFO" />
    <logger name="org.hibernate.SQL" level="DEBUG" />
</configuration>
728x90

댓글