-
Notifications
You must be signed in to change notification settings - Fork 1
[SCRUM-355] Feat: 로깅 시스템 구축 #112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Walkthrough인터셉터와 AOP 기반 로깅 클래스를 추가·전역 등록하고, 프로파일별 로깅 설정과 Discord 알림을 도입하며 Gradle에 JitPack 및 AOP/Discord 의존성을 추가했다. 일부 JPA SQL 로그 설정을 프로덕션용 yml로 옮겼다. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant C as Client
participant D as Dispatcher (Spring MVC)
participant I as LoggingInterceptor
participant H as Controller/Handler
participant E as GlobalExceptionHandler
C->>D: HTTP 요청 (/api/**)
D->>I: preHandle (시작시간 저장)
D->>H: 핸들러 실행
alt 예외 발생
H-->>D: 예외 throw
D->>E: 예외 처리 및 로그
else 정상 처리
H-->>D: 응답 반환
end
D->>I: afterCompletion (상태, 소요시간 계산)
I-->>C: 응답 완료 (상태에 따라 INFO/WARN/ERROR 로그)
sequenceDiagram
autonumber
participant A as LoggingAspect
participant S as Service Layer
participant R as Repository Layer
A->>S: Around advice 진입 (메서드 호출)
A->>A: 시작시간 기록
S->>R: Repository 호출
R-->>S: 결과 반환
A->>A: 실행시간 계산 및 INFO/경고 로그
A-->>S: 원래 결과 반환
A->>R: AfterReturning (Repository 메서드 성공 반환)
A-->>A: 반환 타입 로깅
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
Status, Documentation and Community
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
🔭 Outside diff range comments (2)
src/main/java/com/kkinikong/be/global/exception/handler/GlobalExceptionHandler.java (2)
90-95: 메서드명 오타: ReviewException 핸들러 이름을 수정하세요.ReviewException을 처리하는데 메서드명이 handleS3Exception으로 되어 있어 혼란을 줍니다.
- public ResponseEntity<Object> handleS3Exception( - final ReviewException e, HttpServletRequest request) { + public ResponseEntity<Object> handleReviewException( + final ReviewException e, HttpServletRequest request) {
129-135: DTO 검증 실패(400)에 대해서도 로그를 남기세요.현재 MethodArgumentNotValidException 처리에서 로그가 남지 않습니다. 인터셉터 외에도 여기서 일관된 포맷으로 남기면 추적성이 좋아집니다.
@@ @Override public ResponseEntity<Object> handleMethodArgumentNotValid( @NonNull MethodArgumentNotValidException e, @NonNull HttpHeaders headers, @NonNull HttpStatusCode status, @NonNull WebRequest request) { - return handleExceptionInternal(e); + // WebRequest -> HttpServletRequest로 변환 가능 시 400 로그 기록 + if (request instanceof org.springframework.web.context.request.ServletWebRequest swr) { + logInfo(GlobalErrorCode.INVALID_PARAMETER, e, swr.getRequest()); + } + return handleExceptionInternal(e); }추가 import 필요 없음(Java 17 pattern matching 사용 시 완전한 한정명으로 처리).
🧹 Nitpick comments (9)
.coderabbit.yaml (3)
5-5: request_changes_workflow의 동작 의미를 정확히 표기해주세요.주석에 “리뷰 끝나면 알아서 PR 승인”이라고 되어 있으나, 해당 옵션은 “코멘트(요청 변경)들이 해결되면 승인” 워크플로를 활성화하는 설정입니다. 자동 병합/즉시 승인은 아닙니다. 혼동 방지를 위해 주석을 보완해 주세요.
- request_changes_workflow: true # 코드래빗이 리뷰 끝나면 알아서 PR 승인 + request_changes_workflow: true # 요청 변경이 모두 해결되면 CodeRabbit이 승인 처리(즉시 자동 승인/병합 아님)
7-7: 시끄러운 출력 방지: poem 설정은 비활성화를 고려하세요.실서비스/팀 레포지토리에서는 리뷰 코멘트에 시를 포함하는 옵션은 불필요한 노이즈일 수 있습니다. 기본값 유지 또는 false로 두는 것을 권장합니다.
- poem: true + poem: false
14-14: 파일 말미 개행(Newline) 누락을 수정해주세요.YAMLLint가 EOF 개행 누락을 지적하고 있습니다. 말미에 빈 줄을 추가해 주세요.
chat: auto_reply: true +build.gradle (1)
101-104: Discord Appender는 runtimeOnly로 지정하세요.Logback Appender는 런타임에서만 필요하며 컴파일 타임 노출이 불필요합니다. 의존성 스코프를 runtimeOnly로 낮추면 컴파일 클래스패스가 깔끔해집니다.
// AOP implementation 'org.springframework.boot:spring-boot-starter-aop' // Discord -implementation 'com.github.napstr:logback-discord-appender:1.0.0' +runtimeOnly 'com.github.napstr:logback-discord-appender:1.0.0'src/main/java/com/kkinikong/be/global/exception/handler/GlobalExceptionHandler.java (2)
41-42: 로그 포맷 간결화는 좋으나, 클래스명은 simpleName이 가독성에 유리합니다.전체 클래스명 대신 simpleName을 사용하면 로그 가독성이 개선됩니다. 또한 상태는 숫자 코드로 고정하면 파싱이 수월합니다.
- private static final String LOG_FORMAT_INFO = "[🔵INFO] - ({} {}) {} {}: {}"; + private static final String LOG_FORMAT_INFO = "[🔵INFO] - ({} {}) {} {}: {}"; // 상태코드 숫자/클래스 simpleName 사용 권장 @@ - ec.getHttpStatus(), - e.getClass().getName(), + ec.getHttpStatus().value(), + e.getClass().getSimpleName(),
187-195: 예외 메시지(PII) 노출 최소화 권장.e.getMessage()에 사용자 입력/민감정보가 포함될 수 있습니다. 필요 시 마스킹 전략을 도입하거나, 사용자 메시지 대신 사전 정의된 ErrorCode 메시지로 제한하는 것을 고려하세요.
src/main/java/com/kkinikong/be/global/config/WebConfig.java (1)
19-22: 정적 리소스 및 에러 엔드포인트 추가 제외 권장.현재 swagger, api-docs, actuator만 제외되어 있습니다. 불필요한 노이즈를 줄이려면 정적 리소스 및 기본 에러 경로도 제외하세요.
registry .addInterceptor(loggingInterceptor) .addPathPatterns("/**") - .excludePathPatterns("/swagger-ui/**", "/v3/api-docs/**", "/actuator/**"); + .excludePathPatterns( + "/swagger-ui/**", + "/swagger-resources/**", + "/webjars/**", + "/v3/api-docs/**", + "/actuator/**", + "/error", + "/favicon.ico");src/main/java/com/kkinikong/be/global/logging/LoggingInterceptor.java (1)
14-14: 상수 네이밍 컨벤션을 따르세요.상수명은 스네이크 케이스를 사용하는 것이 Java 컨벤션에 맞습니다.
다음 diff를 적용하여 네이밍을 개선하세요:
- private static final String START_TIME = "start_time"; + private static final String START_TIME_ATTRIBUTE = "start_time";src/main/resources/logback-spring.xml (1)
37-37: 로그 메시지에 마크다운 형식 개선이 필요합니다.현재 패턴에서 예외 스택트레이스가 항상 마크다운 코드 블록으로 감싸지는데, 예외가 없는 경우 빈 코드 블록이 전송될 수 있습니다.
다음 diff를 적용하여 조건부 마크다운 포맷을 고려하세요:
- <pattern>[%d{yyyy-MM-dd HH:mm:ss}] %-5level %logger{36} - %msg%n```%ex{10}```</pattern> + <pattern>[%d{yyyy-MM-dd HH:mm:ss}] %-5level %logger{36} - %msg%n%ex{10}</pattern>
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
.coderabbit.yaml(1 hunks)build.gradle(2 hunks)src/main/java/com/kkinikong/be/global/config/WebConfig.java(1 hunks)src/main/java/com/kkinikong/be/global/exception/handler/GlobalExceptionHandler.java(1 hunks)src/main/java/com/kkinikong/be/global/logging/LoggingAspect.java(1 hunks)src/main/java/com/kkinikong/be/global/logging/LoggingInterceptor.java(1 hunks)src/main/resources/application-prod.yml(1 hunks)src/main/resources/application.yml(0 hunks)src/main/resources/logback-spring.xml(1 hunks)
💤 Files with no reviewable changes (1)
- src/main/resources/application.yml
🧰 Additional context used
🪛 YAMLlint (1.37.1)
.coderabbit.yaml
[error] 14-14: no new line character at the end of file
(new-line-at-end-of-file)
🔇 Additional comments (8)
.coderabbit.yaml (1)
10-13: 자동 리뷰 설정 적절합니다.auto_review.enabled/drafts 설정이 목적에 부합합니다. 추가로 필요 시 labels/base_branches로 범위를 좁히는 것도 고려해 볼 수 있습니다.
src/main/resources/application-prod.yml (1)
10-17: 운영 환경에서 SQL 로그 억제 구성 적절합니다.Hibernate/JPA의 show_sql, format_sql, highlight_sql, use_sql_comments를 모두 꺼서 운영 로그 노이즈를 줄였습니다. 운영에서의 성능/보안 측면에 부합합니다.
src/main/java/com/kkinikong/be/global/exception/handler/GlobalExceptionHandler.java (1)
187-199: Throwable 전달 방식 적절합니다.ERROR 로그에서 플레이스홀더 2개(메서드, URI) + 마지막 인자로 Throwable을 전달하여 스택트레이스가 포함되도록 한 접근이 맞습니다.
src/main/java/com/kkinikong/be/global/logging/LoggingInterceptor.java (1)
35-41: 로깅 레벨과 메시지 일관성이 좋습니다.HTTP 상태 코드에 따른 로깅 레벨 분류가 적절하고, 이모지를 사용한 시각적 구분과 일관된 메시지 포맷이 잘 구현되어 있습니다.
src/main/java/com/kkinikong/be/global/logging/LoggingAspect.java (2)
28-35: Repository 로깅 로직이 적절합니다.메서드 실행 후 결과 타입을 로깅하는 방식이 깔끔하고, null 체크도 잘 되어 있습니다.
17-17: Service·Repository 포인트컷 표현식은 이미 일관적입니다.
두 패턴 모두execution(* com.kkinikong.be..*Xxx.*(..))구조를 따르고 있으며,
@Aroundvs@AfterReturning차이는 서비스 실행 시간 측정과 레포지토리 호출 후 반환값 로깅이라는 서로 다른 로직을 위해 의도된 어드바이스 타입 구분이므로 별도 수정이 필요하지 않습니다.Likely an incorrect or invalid review comment.
src/main/resources/logback-spring.xml (2)
34-41: Discord 알림 설정이 잘 구성되어 있습니다.웹훅 URI를 환경변수로 관리하고, 한국어 사용자명과 적절한 메시지 포맷을 사용한 점이 좋습니다.
43-48: 비동기 Discord 앱펜더 설정이 적절합니다.ERROR 레벨 필터링과 비동기 처리 설정이 성능상 좋은 구성입니다.
src/main/java/com/kkinikong/be/global/logging/LoggingInterceptor.java
Outdated
Show resolved
Hide resolved
chaen-ing
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
완전 수고했당!!!~~
넘 늦게 확인해서 미안,,,🥹🥹 진짜 Granfa연결해봐도 좋을듯합니다!!
…or.java Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/main/java/com/kkinikong/be/global/config/WebConfig.java (2)
18-20: 헬스체크/문서/에러 엔드포인트는 기본 제외 권장운영·로컬 모두에서 노이즈를 크게 줄이고 의미 있는 요청만 로깅하려면 actuator/health, Swagger, 에러 엔드포인트 등을 제외하는 것이 좋습니다.
다음 변경으로 제외 패턴을 추가해 주세요:
- registry.addInterceptor(loggingInterceptor).addPathPatterns("/api/**"); + registry.addInterceptor(loggingInterceptor) + .addPathPatterns("/api/**") + .excludePathPatterns( + "/error", "/error/**", + "/actuator/**", + "/health", "/actuator/health", + "/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html", + "/favicon.ico" + );
15-20: 프로파일별 비활성화(예: prod) 시 컨텍스트 실패 방지용 선택적 주입 권장현재는
LoggingInterceptor빈이 존재하지 않으면 애플리케이션이 부팅에 실패합니다. 로컬에서만 활성, 운영에서 비활성 같은 전략을 고려 중이라면 선택적 주입(ObjectProvider)로 전환해 조건부 등록을 추천합니다.아래와 같이 수정하면 해당 빈이 없는 프로파일에서도 안전하게 부팅됩니다.
@@ package com.kkinikong.be.global.config; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import lombok.RequiredArgsConstructor; import com.kkinikong.be.global.logging.LoggingInterceptor; @Configuration @RequiredArgsConstructor public class WebConfig implements WebMvcConfigurer { - private final LoggingInterceptor loggingInterceptor; + private final ObjectProvider<LoggingInterceptor> loggingInterceptorProvider; @Override public void addInterceptors(InterceptorRegistry registry) { - registry.addInterceptor(loggingInterceptor).addPathPatterns("/api/**"); + LoggingInterceptor interceptor = loggingInterceptorProvider.getIfAvailable(); + if (interceptor != null) { + registry.addInterceptor(interceptor).addPathPatterns("/api/**"); + } } }참고: Spring Boot를 사용한다면 대안으로
@ConditionalOnBean(LoggingInterceptor.class)를 WebConfig에 추가하는 방법도 있습니다.
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
src/main/java/com/kkinikong/be/global/config/WebConfig.java(1 hunks)src/main/java/com/kkinikong/be/global/logging/LoggingAspect.java(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/main/java/com/kkinikong/be/global/logging/LoggingAspect.java
🔇 Additional comments (2)
src/main/java/com/kkinikong/be/global/config/WebConfig.java (2)
11-13: 구성 클래스/인터셉터 등록 구조 적절@configuration + WebMvcConfigurer 조합과 생성자 주입(@requiredargsconstructor)은 표준적이며, 인터셉터 등록 책임이 명확합니다. 👍
15-15: 확인 결과LoggingInterceptor는@Component애노테이션으로 등록되어 있어 WebConfig 생성자 주입 시 빈 주입에 문제가 없습니다.
📝 개요
로깅 시스템을 구현해보았습니다.
🛠️ 작업 사항
기존에는
Hibernate...하면서 쿼리가 쭉 나오고 GlobalExceptionHandler에서 400, 500에러만 로깅이 되는 상황이었습니다.이 로깅을 조금 세세하게 나오게끔 Interceptor와 AOP를 활용해보았습니다.
docker logs spring-blue(green)이렇게 해서 들어가게 되면, 아래 사진과 같이 로그가 찍히는 것을 볼 수 있는데, 여기서 AOP 로그 부분과Hibernate...부분은 찍히지 않도록 하고 400,500 에러는 동일하게 나오게끔 설정했습니다.🔗 관련 이슈 / JIRA
✅ 체크리스트
🙏 기타 사항
Summary by CodeRabbit
신기능
스타일
작업