Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions uniro_backend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@ dependencies {
// caffeine
implementation 'com.github.ben-manes.caffeine:caffeine:3.1.8'

// log4j2
implementation "org.springframework.boot:spring-boot-starter-log4j2" // Spring Boot Log4j2
implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml" // Jackson Dataforamt yaml
implementation "com.lmax:disruptor:3.4.4"

}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package com.softeer5.uniro_backend.common.logging;

import static com.softeer5.uniro_backend.common.constant.UniroConst.*;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
Expand All @@ -8,21 +12,26 @@
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.log4j.Log4j2;
import lombok.extern.slf4j.Slf4j;

@Aspect
@Component
@Log4j2
@Slf4j
@Profile("!test")
public class ExecutionLoggingAop {
Logger asyncLogger = LoggerFactory.getLogger("async-logger");
Logger synclogger = LoggerFactory.getLogger(ExecutionLoggingAop.class);

private static final ThreadLocal<String> userIdThreadLocal = new ThreadLocal<>();

Expand All @@ -48,44 +57,41 @@ public Object logExecutionTrace(ProceedingJoinPoint pjp) throws Throwable {
}
HttpServletRequest request = null;
if (RequestContextHolder.getRequestAttributes() instanceof ServletRequestAttributes) {
request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
}

if(request==null){
if (request == null) {
return pjp.proceed();
}
log.info("✅ [ userId = {} Start] [Call Method] {}: {}", userId, request.getMethod(), task);
asyncLogger.info("✅ [ userId = {} Start] [Call Method] {}: {}", userId, request.getMethod(), task);

try{
try {
if (isController) {
logParameters(pjp.getArgs());
}
}
catch (Exception e){
} catch (Exception e) {
// 로깅 중에 발생한 에러는 무시하고 로깅을 계속 진행
log.error("🚨🚨🚨 [ userId = {} ] {} 메서드 파라미터 로깅 중 에러 발생 : {} 🚨🚨🚨", userId, task, e.getMessage());
asyncLogger.error("🚨🚨🚨 [ userId = {} ] {} 메서드 파라미터 로깅 중 에러 발생 : {} 🚨🚨🚨", userId, task, e.getMessage());
}
log.info("");

StopWatch sw = new StopWatch();
sw.start();

Object result;
try {
result = pjp.proceed();
sw.stop();
asyncLogger.info("🚨 [ExecutionTime] {} --> {} (ms) [ userId = {} ] {} End\n", task, sw.getTotalTimeMillis(),
userId, className);
} catch (Exception e) {
log.warn("[ERROR] [ userId = {} ] {} 메서드 예외 발생 : {}", userId, task, e.getMessage());
asyncLogger.warn("[ERROR] [ userId = {} ] {} 메서드 예외 발생 : {}", userId, task, e.getMessage());
throw e;
} finally {
if (isController) {
if (isControllerOrService(target)) {
userIdThreadLocal.remove();
}
}

sw.stop();
log.info("[ExecutionTime] {} --> {} (ms)", task, sw.getTotalTimeMillis());
log.info("🚨 [ userId = {} ] {} End\n", userId, className);

return result;
}

Expand All @@ -94,13 +100,23 @@ private boolean isRestController(Object target) {
.anyMatch(RestController.class::isInstance);
}

private boolean isControllerOrService(Object target) {
boolean b = Arrays.stream(target.getClass().getDeclaredAnnotations())
.anyMatch(RestController.class::isInstance);

boolean b1 = Arrays.stream(target.getClass().getDeclaredAnnotations())
.anyMatch(Service.class::isInstance);

return b || b1;
}

private void logParameters(Object[] args) {
StringBuilder parametersLogMessage = new StringBuilder();

Arrays.stream(args)
.forEach(arg -> logDetail(arg, "[Parameter]", parametersLogMessage, 0));

log.info("\n{}", parametersLogMessage.toString());
asyncLogger.info("\n{}", parametersLogMessage);
}

private void logDetail(Object arg, String requestType, StringBuilder logMessage, int depth) {
Expand Down Expand Up @@ -154,13 +170,16 @@ private void logObjectFields(Object object, StringBuilder logMessage, int depth)
Object value = field.get(object);
logDetail(value, "[Field] " + field.getName(), logMessage, depth + 1);
} catch (IllegalAccessException e) {
logMessage.append(indent).append("[Field Access Error] Cannot access field: ").append(field.getName()).append("\n");
logMessage.append(indent)
.append("[Field Access Error] Cannot access field: ")
.append(field.getName())
.append("\n");
}
});
}

private void logHttpRequest(String userId) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()).getRequest();

// HTTP Request 메시지 출력 (RFC 2616 형식)
StringBuilder httpMessage = new StringBuilder();
Expand Down Expand Up @@ -199,7 +218,6 @@ private void logHttpRequest(String userId) {
}

// 요청 메시지 출력
log.info("✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅ New request");
log.info("[ userId = "+ userId + " ] HTTP Request: \n" + httpMessage);
asyncLogger.info("✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅ New request\n [ userId = {} ] HTTP Request: {} \n", userId, httpMessage);
}
}
7 changes: 5 additions & 2 deletions uniro_backend/src/main/resources/application-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ spring:
import: application.properties
datasource:
hikari:
maximum-pool-size: 30
maximum-pool-size: 100
url: ${DB_URL}
username: ${DB_USER}
password: ${DB_PASSWORD}
Expand Down Expand Up @@ -44,4 +44,7 @@ cors:
allowed-origins: ${allowed-origins}

jwt:
secret: ${JWT_SECRET}
secret: ${JWT_SECRET}

logging:
config: classpath:log4j2/log4j2.yml
9 changes: 6 additions & 3 deletions uniro_backend/src/main/resources/application-local.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
spring:
datasource:
hikari:
maximum-pool-size: 30
maximum-pool-size: 100
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/uniro?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
url: jdbc:mysql://localhost:3306/uniro-db?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
username: root
password:
jpa:
Expand Down Expand Up @@ -45,4 +45,7 @@ cors:
allowed-origins: ${allowed-origins}

jwt:
secret: ${JWT_SECRET}
secret: ${JWT_SECRET}

logging:
config: classpath:log4j2/log4j2.yml
67 changes: 67 additions & 0 deletions uniro_backend/src/main/resources/log4j2/log4j2.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
Configutation:
# 구성 이름
name: uniro-api

# [Properties] 설정에 사용되는 속성들을 정의
Properties:
Property:
- name: "charset-UTF-8"
value: "UTF-8"
- name: "layout-pattern"
value: "%style{%d{UTF-8}} %highlight{%-5level} [%style{%t}{bright,blue}] %style{%C}{bright,yellow}: %msg%n%throwable"

# [Appenders] 로그 기록방식 정의
Appenders:
# [Appenders - Console] 콘솔에 로그를 출력하는 방식 정의
Console:
- name: console-appender
target: SYSTEM_OUT
PatternLayout:
pattern: ${layout-pattern}

# [Loggers] 로그 출력 범위를 정의
Loggers:
# [Loggers - Root] 모든 로그를 기록하는 최상위 로그를 정의
Root:
level: OFF
AppenderRef:
- ref: console-appender

# [Loggers - AsyncLogger] 비동기 로깅에 대한 정의
AsyncLogger:
Comment thread
mikekks marked this conversation as resolved.
name: async-logger # logger key
level: DEBUG
additivity: false
AppenderRef:
- ref: console-appender

# [Loggers - Loggers] 특정 패키지나 클래스에 대한 로그를 정의
Logger:
# 1. Spring Framework 로그 레벨 'INFO' 정의
- name: org.springframework
additivity: "false"
level: INFO
AppenderRef:
- ref: console-appender

# 2. Spring Framework 로그 레벨 'DEBUG' 정의
- name: "com.softeer5.uniro_backend"
additivity: "false"
level: DEBUG
AppenderRef:
- ref: console-appender

- name: jdbc
level: OFF
- name: jdbc.sql only
level: OFF
- name: jdbc.sliding
level: INFO
- name: jdbc.result-settable
level: OFF
- name: jdbc.audit
level: OFF
- name: jdbc.result
level: OFF
- name: jdbc.connection
level: OFF