Skip to content
This repository was archived by the owner on Jan 2, 2026. It is now read-only.

Commit 6894f6e

Browse files
authored
Feature/#16 로그 기능
* ✨ Feat: 로그 기능 개발 * ♻️ Refactor: 로그 유틸 및 Enum 클래스 리팩토링 * ♻️ Refactor: 로그 유틸 클래스 도메인 객체 내부 리팩토링 * ♻️ Refactor: 로그 기능 전체 리팩토링 - 캡슐화 및 상수 활용 * 🐛 Fix: LoggerWithTraceId 객체 내부 StackTraceElement배열 수정 * 💄 Style: 로그 기능의 모든 클래스에 주석을 추가하였습니다. * ♻️ Refactor: 상수로 선언된 부분을 env 파일과 enum클래스로 분리하였습니다.
1 parent bb2ea09 commit 6894f6e

File tree

10 files changed

+736
-1
lines changed

10 files changed

+736
-1
lines changed
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package com.likelion.backendplus4.yakplus;
22

3+
import com.likelion.backendplus4.yakplus.common.configuration.LogbackConfig;
34
import org.springframework.boot.SpringApplication;
45
import org.springframework.boot.autoconfigure.SpringBootApplication;
56

67
@SpringBootApplication
78
public class YakplusApplication {
89
public static void main(String[] args) {
10+
LogbackConfig logbackConfig = new LogbackConfig();
11+
logbackConfig.configure();
912
SpringApplication.run(YakplusApplication.class, args);
10-
1113
}
1214
}
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
package com.likelion.backendplus4.yakplus.common.configuration;
2+
3+
import ch.qos.logback.classic.Level;
4+
import ch.qos.logback.classic.LoggerContext;
5+
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
6+
import ch.qos.logback.classic.spi.ILoggingEvent;
7+
import ch.qos.logback.core.ConsoleAppender;
8+
import ch.qos.logback.core.FileAppender;
9+
import ch.qos.logback.core.rolling.TimeBasedRollingPolicy;
10+
import ch.qos.logback.core.util.FileSize;
11+
import jakarta.annotation.PostConstruct;
12+
import org.slf4j.Logger;
13+
import org.slf4j.LoggerFactory;
14+
import org.springframework.context.annotation.Configuration;
15+
16+
import java.nio.file.Files;
17+
import java.nio.file.Path;
18+
import java.nio.file.Paths;
19+
20+
/**
21+
* 로깅 설정을 위한 설정 클래스
22+
*
23+
* @modified 2025-04-18
24+
* @since 2025-04-16
25+
*/
26+
@Configuration
27+
public class LogbackConfig {
28+
private static final String LOG_DIRECTORY = "logs";
29+
private static final String LOG_FILE_NAME = "like-lion.log";
30+
private static final String LOG_PATTERN = "%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n";
31+
private static final int MAX_HISTORY = 30;
32+
private static final String TOTAL_SIZE_CAP = "1GB";
33+
34+
/**
35+
* 로깅 설정을 초기화하는 메서드
36+
*
37+
* @author 정안식
38+
* @modified 2025-04-18
39+
* @since 2025-04-16
40+
*/
41+
@PostConstruct
42+
public void configure() {
43+
LoggerContext context = initializeLoggerContext();
44+
createLogDirectory();
45+
46+
ConsoleAppender<ILoggingEvent> consoleAppender = createConsoleAppender(context);
47+
FileAppender<ILoggingEvent> fileAppender = createFileAppender(context);
48+
49+
configureRootLogger(context, consoleAppender, fileAppender);
50+
}
51+
52+
/**
53+
* LoggerContext를 초기화하는 메서드
54+
*
55+
* @return LoggerContext 초기화된 로거 컨텍스트
56+
* @author 정안식
57+
* @modified 2025-04-18
58+
* @since 2025-04-16
59+
*/
60+
private LoggerContext initializeLoggerContext() {
61+
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
62+
context.reset();
63+
return context;
64+
}
65+
66+
/**
67+
* 로그 디렉토리를 생성하는 메서드
68+
*
69+
* @author 정안식
70+
* @modified 2025-04-18
71+
* @since 2025-04-16
72+
*/
73+
private void createLogDirectory() {
74+
Path logPath = Paths.get(LOG_DIRECTORY);
75+
try {
76+
if (!Files.exists(logPath)) {
77+
Files.createDirectories(logPath);
78+
}
79+
} catch (Exception e) {
80+
throw new RuntimeException("로그 디렉토리 생성 실패", e);
81+
}
82+
}
83+
84+
/**
85+
* 콘솔 어펜더를 생성하는 메서드
86+
*
87+
* @param context LoggerContext 로거 컨텍스트
88+
* @return ConsoleAppender 생성된 콘솔 어펜더
89+
* @author 정안식
90+
* @modified 2025-04-18
91+
* @since 2025-04-16
92+
*/
93+
private ConsoleAppender<ILoggingEvent> createConsoleAppender(LoggerContext context) {
94+
ConsoleAppender<ILoggingEvent> appender = new ConsoleAppender<>();
95+
appender.setContext(context);
96+
appender.setEncoder(createEncoder(context));
97+
appender.start();
98+
return appender;
99+
}
100+
101+
/**
102+
* 파일 어펜더를 생성하는 메서드
103+
*
104+
* @param context LoggerContext 로거 컨텍스트
105+
* @return FileAppender 생성된 파일 어펜더
106+
* @author 정안식
107+
* @modified 2025-04-18
108+
* @since 2025-04-16
109+
*/
110+
private FileAppender<ILoggingEvent> createFileAppender(LoggerContext context) {
111+
FileAppender<ILoggingEvent> appender = new FileAppender<>();
112+
appender.setContext(context);
113+
appender.setFile(LOG_DIRECTORY + "/" + LOG_FILE_NAME);
114+
appender.setAppend(true);
115+
appender.setEncoder(createEncoder(context));
116+
117+
TimeBasedRollingPolicy<ILoggingEvent> rollingPolicy = createRollingPolicy(context, appender);
118+
rollingPolicy.start();
119+
120+
appender.start();
121+
return appender;
122+
}
123+
124+
/**
125+
* 패턴 레이아웃 인코더를 생성하는 메서드
126+
*
127+
* @param context LoggerContext 로거 컨텍스트
128+
* @return PatternLayoutEncoder 생성된 패턴 레이아웃 인코더
129+
* @author 정안식
130+
* @modified 2025-04-18
131+
* @since 2025-04-16
132+
*/
133+
private PatternLayoutEncoder createEncoder(LoggerContext context) {
134+
PatternLayoutEncoder encoder = new PatternLayoutEncoder();
135+
encoder.setContext(context);
136+
encoder.setPattern(LOG_PATTERN);
137+
encoder.start();
138+
return encoder;
139+
}
140+
141+
/**
142+
* 롤링 정책을 생성하는 메서드
143+
*
144+
* @param context LoggerContext 로거 컨텍스트
145+
* @param parent FileAppender 부모 파일 어펜더
146+
* @return TimeBasedRollingPolicy 생성된 롤링 정책
147+
* @author 정안식
148+
* @modified 2025-04-18
149+
* @since 2025-04-16
150+
*/
151+
private TimeBasedRollingPolicy<ILoggingEvent> createRollingPolicy(LoggerContext context, FileAppender<ILoggingEvent> parent) {
152+
TimeBasedRollingPolicy<ILoggingEvent> policy = new TimeBasedRollingPolicy<>();
153+
policy.setContext(context);
154+
policy.setParent(parent);
155+
policy.setFileNamePattern(LOG_DIRECTORY + "/" + LOG_FILE_NAME.replace(".log", ".%d{yyyy-MM-dd}.log"));
156+
policy.setMaxHistory(MAX_HISTORY);
157+
policy.setTotalSizeCap(FileSize.valueOf(TOTAL_SIZE_CAP));
158+
return policy;
159+
}
160+
161+
/**
162+
* 루트 로거를 설정하는 메서드
163+
*
164+
* @param context LoggerContext 로거 컨텍스트
165+
* @param consoleAppender ConsoleAppender 콘솔 어펜더
166+
* @param fileAppender FileAppender 파일 어펜더
167+
* @author 정안식
168+
* @since 2025-04-16
169+
*/
170+
private void configureRootLogger(LoggerContext context, ConsoleAppender<ILoggingEvent> consoleAppender, FileAppender<ILoggingEvent> fileAppender) {
171+
Logger logger = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
172+
if (logger instanceof ch.qos.logback.classic.Logger) {
173+
ch.qos.logback.classic.Logger rootLogger = (ch.qos.logback.classic.Logger) logger;
174+
rootLogger.setLevel(Level.INFO);
175+
rootLogger.addAppender(consoleAppender);
176+
rootLogger.addAppender(fileAppender);
177+
}
178+
}
179+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.likelion.backendplus4.yakplus.common.configuration;
2+
3+
import com.likelion.backendplus4.yakplus.common.interceptor.LogInterceptor;
4+
import lombok.RequiredArgsConstructor;
5+
import org.springframework.beans.factory.annotation.Autowired;
6+
import org.springframework.context.annotation.Configuration;
7+
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
8+
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
9+
10+
/**
11+
* 웹 설정을 위한 설정 클래스
12+
*
13+
* @modified 2025-04-18
14+
* @since 2025-04-16
15+
*/
16+
@Configuration
17+
@RequiredArgsConstructor
18+
public class WebConfig implements WebMvcConfigurer {
19+
20+
private static final String ALL_PATTERN = "/**";
21+
22+
private LogInterceptor logInterceptor;
23+
24+
/**
25+
* 인터셉터를 등록하는 메서드
26+
*
27+
* @param registry InterceptorRegistry 인터셉터 레지스트리
28+
* @author 정안식
29+
* @modified 2025-04-18
30+
* @since 2025-04-16
31+
*/
32+
@Override
33+
public void addInterceptors(InterceptorRegistry registry) {
34+
// 모든 요청에 대해 LogInterceptor를 적용
35+
registry.addInterceptor(logInterceptor)
36+
.addPathPatterns(ALL_PATTERN); // 모든 URL 패턴에 적용
37+
}
38+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package com.likelion.backendplus4.yakplus.common.interceptor;
2+
3+
import com.likelion.backendplus4.yakplus.common.util.log.LogMessage;
4+
import jakarta.servlet.http.HttpServletRequest;
5+
import jakarta.servlet.http.HttpServletResponse;
6+
import org.slf4j.MDC;
7+
import org.springframework.stereotype.Component;
8+
import org.springframework.web.servlet.HandlerInterceptor;
9+
10+
import java.util.UUID;
11+
12+
import static com.likelion.backendplus4.yakplus.common.util.log.LogUtil.log;
13+
14+
/**
15+
* 로깅을 위한 인터셉터 클래스
16+
*
17+
* @modified 2025-04-18
18+
* @since 2025-04-16
19+
*/
20+
@Component
21+
public class LogInterceptor implements HandlerInterceptor {
22+
23+
/**
24+
* 요청 처리 전에 실행되는 메서드
25+
*
26+
* @param request HttpServletRequest 요청 객체
27+
* @param response HttpServletResponse 응답 객체
28+
* @param handler Object 핸들러 객체
29+
* @return boolean 처리 계속 여부
30+
* @author 정안식
31+
* @modified 2025-04-18
32+
* @since 2025-04-16
33+
*/
34+
@Override
35+
public boolean preHandle(HttpServletRequest request,
36+
HttpServletResponse response, Object handler) {
37+
String traceId = generateTraceId();
38+
setTraceId(traceId);
39+
log("TraceId 생성 성공 - " + traceId);
40+
return true;
41+
}
42+
43+
/**
44+
* 요청 처리가 완료된 후 실행되는 메서드
45+
*
46+
* @param request HttpServletRequest 요청 객체
47+
* @param response HttpServletResponse 응답 객체
48+
* @param handler Object 핸들러 객체
49+
* @param ex Exception 예외 객체
50+
* @author 정안식
51+
* @modified 2025-04-18
52+
* @since 2025-04-16
53+
*/
54+
@Override
55+
public void afterCompletion(HttpServletRequest request,
56+
HttpServletResponse response, Object handler, Exception ex) {
57+
clearTraceId();
58+
}
59+
60+
/**
61+
* TraceId를 생성하는 메서드
62+
*
63+
* @return String 생성된 TraceId
64+
* @author 정안식
65+
* @modified 2025-04-18
66+
* @since 2025-04-16
67+
*/
68+
private String generateTraceId() {
69+
return UUID.randomUUID().toString();
70+
}
71+
72+
/**
73+
* TraceId를 설정하는 메서드
74+
*
75+
* @param traceId String 설정할 TraceId
76+
* @author 정안식
77+
* @modified 2025-04-18
78+
* @since 2025-04-16
79+
*/
80+
private void setTraceId(String traceId) {
81+
MDC.put(LogMessage.TRACE_ID.getMessage(), traceId);
82+
}
83+
84+
/**
85+
* TraceId를 제거하는 메서드
86+
*
87+
* @author 정안식
88+
* @modified 2025-04-18
89+
* @since 2025-04-16
90+
*/
91+
private void clearTraceId() {
92+
MDC.clear();
93+
}
94+
}

0 commit comments

Comments
 (0)