-
Notifications
You must be signed in to change notification settings - Fork 8
feat: API 성능 로깅, 쿼리 별 메트릭 전송 추가 #602
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
base: develop
Are you sure you want to change the base?
feat: API 성능 로깅, 쿼리 별 메트릭 전송 추가 #602
Conversation
- traceId 기반 요청 추적 - 요청/응답 로깅 - CustomExceptionHandler와 중복 로깅 방지 - Actuator 엔드포인트 로깅 제외
- info, warn, error, api_perf 로 로그 파일 분리해서 관리
* feat: 데이터소스 프록시 의존성 및 config 파일 추가 * feat: 데이터 소스 프록시가 metric을 찍을 수 있도록 listener 클래스 추가 * feat: 요청 시 method, uri 정보를 listener에서 활용하기 위해 RequestContext 및 관련 interceptor 추가
- Time.builder 를 사용하면 매번 빌더를 생성하여 비효율적인 문제를 meterRegistry.timer 방식으로 해결
Walkthrough이번 변경사항은 애플리케이션에 관찰성(Observability) 기능을 종합적으로 추가한 것입니다. 데이터소스 프록시를 통한 데이터베이스 쿼리 메트릭 수집, HTTP 요청/응답 로깅, API 성능 추적, 그리고 사용자 컨텍스트 기반 상세 로깅이 구현되었습니다. 또한 로깅 설정을 프로필별로 다층화하고 새로운 인터셉터와 필터를 웹 MVC 설정에 통합했습니다. 모든 변경은 기존 기능을 수정하지 않으면서 메트릭과 로그 추적 기능을 강화합니다. Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Suggested reviewers
주요 변경사항 상세 분석이번 PR의 변경사항을 정리하면 다음과 같습니다:
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 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.
Actionable comments posted: 2
🧹 Nitpick comments (7)
src/main/java/com/example/solidconnection/security/filter/TokenAuthenticationFilter.java (1)
51-55: Principal 타입 체크 추가를 고려해주세요.변경 내용:
- Authentication 객체에서 Principal을 SiteUserDetails로 캐스팅
- userId를 추출하여 request attribute에 저장
잠재적 이슈:
- Line 52에서
auth.getPrincipal()을SiteUserDetails로 무조건 캐스팅하면 다른 타입의 principal인 경우ClassCastException발생 가능일반적인 흐름에서는
TokenAuthentication이 항상SiteUserDetails를 반환하겠지만, 방어적 프로그래밍 관점에서 타입 체크를 추가하는 것을 권장합니다.🔎 방어적 타입 체크 추가 제안
private void extractIdFromAuthentication(HttpServletRequest request, Authentication auth) { + Object principal = auth.getPrincipal(); + if (!(principal instanceof SiteUserDetails)) { + return; + } - SiteUserDetails principal = (SiteUserDetails) auth.getPrincipal(); + SiteUserDetails userDetails = (SiteUserDetails) principal; - Long id = principal.getSiteUser().getId(); + Long id = userDetails.getSiteUser().getId(); request.setAttribute("userId", id); }src/main/java/com/example/solidconnection/common/interceptor/ApiPerformanceInterceptor.java (2)
17-19: 사용되지 않는 ROUTE_PATTERN_ATTRIBUTE 정리가 필요합니다.변경 내용:
- Line 17에서
ROUTE_PATTERN_ATTRIBUTE상수 정의- Line 38에서 해당 attribute를 request에 설정
이슈:
ROUTE_PATTERN_ATTRIBUTE가 저장되지만afterCompletion에서 읽혀지지 않습니다- Lines 58-59에서
request.getRequestURI()를 직접 사용- 향후 사용을 위해 준비된 것이거나 리팩터링 과정에서 남은 코드일 수 있습니다
코드 정리를 위해 사용하지 않는 경우 제거하거나, 사용할 계획이라면 주석으로 의도를 명시하는 것을 권장합니다.
Also applies to: 38-39
44-83: API 성능 로깅 로직이 효과적으로 구현되었습니다.변경 내용을 정리하면:
- 요청 시작부터 완료까지의 응답 시간 계산
- 3초(3000ms) 임계값을 기준으로 warn/info 레벨 분리
API_PERF로거와 표준 로거 두 곳에 동시 기록
API_PERF: 구조화된 형식으로 파싱 용이하게 기록- 표준 로거: 사람이 읽기 쉬운 형식으로 기록
구현이 올바르며,
logback-spring.xml의 분리된 로그 파일 전략과 잘 통합되어 있습니다.선택적 개선사항:
- Lines 63-66과 75-78, 그리고 68-70과 80-82에 중복된 로깅 코드가 있습니다
- 로깅 메서드를 별도로 추출하면 코드 중복을 줄이고 유지보수성을 높일 수 있습니다
🔎 로깅 중복 제거 리팩터링 제안
+ private void logPerformance(String method, String uri, long responseTime, int status, boolean isWarning) { + String logLevel = isWarning ? "WARN" : "INFO"; + String apiPerfMessage = "type=API_Performance method_type={} uri={} response_time={} status={}"; + String standardMessage = "[API Performance]: {} {} - {}ms [Status: {}]"; + + if (isWarning) { + API_PERF.warn(apiPerfMessage, method, uri, responseTime, status); + log.warn(standardMessage, method, uri, responseTime, status); + } else { + API_PERF.info(apiPerfMessage, method, uri, responseTime, status); + log.info(standardMessage, method, uri, responseTime, status); + } + } + @Override public void afterCompletion( HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex ) throws Exception { Long startTime = (Long) request.getAttribute(START_TIME_ATTRIBUTE); if(startTime == null) { return; } long responseTime = System.currentTimeMillis() - startTime; String uri = request.getRequestURI(); String method = request.getMethod(); int status = response.getStatus(); - if (responseTime > RESPONSE_TIME_THRESHOLD) { - API_PERF.warn( - "type=API_Performance method_type={} uri={} response_time={} status={}", - method, uri, responseTime, status - ); - - log.warn("[API Performance] {} {} - {}ms [Status: {}]", - method, uri, responseTime, status - ); - - return; - } - - API_PERF.info( - "type=API_Performance method_type={} uri={} response_time={} status={}", - method, uri, responseTime, status - ); - - log.info("[API Performance]: {} {} - {}ms [Status: {}]", - method, uri, responseTime, status - ); + boolean isWarning = responseTime > RESPONSE_TIME_THRESHOLD; + logPerformance(method, uri, responseTime, status, isWarning); }src/main/resources/logback-spring.xml (1)
14-28: 시간 기반 롤링 정책에 크기 제한 추가를 권장합니다.현재는 일별로만 로그 파일이 분리되는데, 트래픽이 많은 경우 하루 동안 로그 파일이 무제한으로 커질 수 있습니다. 다음과 같이 크기 제한을 추가하는 것을 권장합니다:
🔎 크기 기반 롤링 정책 추가 예시
INFO_FILE 앱더를 예로 들면:
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_PATH}/info/info.log</file> - <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> - <fileNamePattern>${LOG_PATH}/info/info.%d{yyyy-MM-dd}.log</fileNamePattern> + <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> + <fileNamePattern>${LOG_PATH}/info/info.%d{yyyy-MM-dd}.%i.log</fileNamePattern> + <maxFileSize>100MB</maxFileSize> <maxHistory>7</maxHistory> + <totalSizeCap>3GB</totalSizeCap> </rollingPolicy>WARN_FILE, ERROR_FILE 앱더에도 동일하게 적용하시면 됩니다.
Also applies to: 31-45, 48-62
src/main/java/com/example/solidconnection/common/listener/QueryMetricsListener.java (1)
28-30: 배치 쿼리에서 첫 번째 쿼리만 사용됩니다.Line 29에서
queries.get(0)로 첫 번째 쿼리의 SQL만 가져와 타입을 판단합니다. 배치 쿼리의 경우 나머지 쿼리들의 타입 정보가 손실됩니다.대부분의 경우 배치 내 쿼리들이 동일한 타입일 것으로 예상되므로 현재 구현도 합리적이지만, 필요하다면 각 쿼리별로 별도 메트릭을 기록하는 것도 고려해볼 수 있습니다.
src/main/java/com/example/solidconnection/common/exception/CustomExceptionHandler.java (1)
33-34: 사용자 컨텍스트 로깅이 효과적으로 추가되었습니다!모든 예외 핸들러에서
userId를 로깅하여 에러 발생 시 사용자 추적이 가능해졌습니다:
- 일관된 패턴: 6개 모든 핸들러에서 동일한 방식으로 userId 로깅
- 예외 핸들러별 적용:
- 커스텀 예외 (line 33-34)
- JSON 파싱 예외 (line 47-49)
- 입력값 검증 예외 (line 62, 70)
- 데이터 무결성 예외 (line 83-85)
- JWT 예외 (line 98-101)
- 서버 내부 예외 (line 114-117)
참고:
userId가null일 수 있지만 (인증되지 않은 요청), 로그에 "null"로 표시되는 것은 허용 가능하며 원본 예외를 숨기지 않으므로 현재 구현이 적절합니다.🔎 (선택사항) 가독성 개선 제안
로그 가독성을 약간 높이려면 다음과 같이 null 처리를 명시적으로 할 수 있습니다:
-Long userId = (Long) request.getAttribute("userId"); +Long userId = (Long) request.getAttribute("userId"); +String userIdStr = userId != null ? userId.toString() : "anonymous"; -log.error("커스텀 예외 발생 userId : {} msg: {}", userId, ex.getMessage()); +log.error("커스텀 예외 발생 userId : {} msg: {}", userIdStr, ex.getMessage());다만 현재 구현도 충분히 명확하므로 이는 선택적 개선사항입니다.
Also applies to: 47-49, 62-62, 70-70, 83-85, 98-101, 114-117
src/main/java/com/example/solidconnection/common/config/web/WebMvcConfig.java (1)
36-43: 인터셉터 등록 순서 개선 제안현재 등록 순서는 기능상 문제없이 작동하고 있습니다. 다만 다음과 같은 이유로 순서 조정을 검토할 만한 가치가 있습니다:
현재 동작 분석:
ApiPerformanceInterceptor.preHandle()은 단순히 타이밍 정보만 기록하며, RequestContext에 의존하지 않습니다RequestContextInterceptor.preHandle()이 실행되는 시점이 컨트롤러 실행 전이므로, 쿼리 실행 시점에는 이미 RequestContext가 설정되어 있습니다개선 제안 이유:
- 의존성 설정 후 사용하는 논리적 순서로 정렬하면 코드의 의도가 더 명확해집니다
RequestContextInterceptor→ApiPerformanceInterceptor순서가 "컨텍스트 준비 → 성능 측정 시작"의 흐름을 더 직관적으로 나타냅니다등록 순서 변경 권장:
registry.addInterceptor(requestContextInterceptor) .addPathPatterns("/**"); registry.addInterceptor(apiPerformanceInterceptor) .addPathPatterns("/**");기능상 필수는 아니지만, 코드 가독성과 유지보수성 측면에서 순서 조정을 권장합니다.
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
build.gradlesrc/main/java/com/example/solidconnection/common/config/datasource/DataSourceProxyConfig.javasrc/main/java/com/example/solidconnection/common/config/web/WebMvcConfig.javasrc/main/java/com/example/solidconnection/common/exception/CustomExceptionHandler.javasrc/main/java/com/example/solidconnection/common/filter/HttpLoggingFilter.javasrc/main/java/com/example/solidconnection/common/interceptor/ApiPerformanceInterceptor.javasrc/main/java/com/example/solidconnection/common/interceptor/RequestContext.javasrc/main/java/com/example/solidconnection/common/interceptor/RequestContextHolder.javasrc/main/java/com/example/solidconnection/common/interceptor/RequestContextInterceptor.javasrc/main/java/com/example/solidconnection/common/listener/QueryMetricsListener.javasrc/main/java/com/example/solidconnection/security/filter/TokenAuthenticationFilter.javasrc/main/resources/logback-spring.xml
🧰 Additional context used
🧬 Code graph analysis (5)
src/main/java/com/example/solidconnection/common/filter/HttpLoggingFilter.java (1)
src/main/java/com/example/solidconnection/common/exception/CustomExceptionHandler.java (1)
Slf4j(23-123)
src/main/java/com/example/solidconnection/common/config/web/WebMvcConfig.java (2)
src/main/java/com/example/solidconnection/common/listener/QueryMetricsListener.java (1)
RequiredArgsConstructor(15-53)src/main/java/com/example/solidconnection/common/config/datasource/DataSourceProxyConfig.java (1)
RequiredArgsConstructor(12-29)
src/main/java/com/example/solidconnection/common/interceptor/RequestContextInterceptor.java (1)
src/main/java/com/example/solidconnection/common/interceptor/RequestContextHolder.java (1)
RequestContextHolder(3-18)
src/main/java/com/example/solidconnection/common/listener/QueryMetricsListener.java (3)
src/main/java/com/example/solidconnection/common/interceptor/RequestContextHolder.java (1)
RequestContextHolder(3-18)src/main/java/com/example/solidconnection/common/config/datasource/DataSourceProxyConfig.java (1)
RequiredArgsConstructor(12-29)src/main/java/com/example/solidconnection/common/interceptor/RequestContextInterceptor.java (1)
Component(9-35)
src/main/java/com/example/solidconnection/security/filter/TokenAuthenticationFilter.java (1)
src/main/java/com/example/solidconnection/security/userdetails/SiteUserDetails.java (1)
SiteUserDetails(9-56)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (19)
src/main/java/com/example/solidconnection/common/config/datasource/DataSourceProxyConfig.java (2)
12-29: 데이터소스 프록시 설정 잘 구현되었습니다.변경 내용을 정리하면:
@Primary어노테이션을 사용하여 프록시된 DataSource가 애플리케이션 전체에서 사용되도록 보장QueryMetricsListener를 생성자 주입으로 받아 프록시에 연결ProxyDataSourceBuilder를 사용하여 기존 DataSource를 래핑쿼리 메트릭 수집을 위한 구조가 명확하고 올바르게 구현되었습니다.
20-28: 연결 풀 설정이 프록시를 통해 올바르게 전달됩니다.검증 결과, 현재 구현이 완벽하게 올바른 패턴을 따르고 있습니다:
DataSourceProperties에서 설정이 먼저 적용됩니다
props.initializeDataSourceBuilder().build()는 application.yml의 모든 HikariCP 설정을 읽어 DataSource에 적용합니다프록시 래핑은 투명하게 동작합니다
- ProxyDataSourceBuilder(datasource-proxy 1.11.0)는 이미 완전히 구성된 DataSource를 감싼 투명한 데코레이터입니다
- 연결 풀의 설정을 변경하거나 손실하지 않습니다
Spring Boot 3.1.5 + HikariCP 기본 포함
- DataSource는 기본으로 HikariCP를 사용하며, 모든 풀 설정(maxPoolSize, minimumIdle, timeout 등)이 보존됩니다
코드는 Spring Boot 모범 사례를 정확히 따르고 있으므로 추가 조치가 필요하지 않습니다.
src/main/java/com/example/solidconnection/security/filter/TokenAuthenticationFilter.java (1)
38-38: 인증 성공 후 userId 추출 로직 위치가 적절합니다.변경 내용:
- 인증이 성공하고 SecurityContext에 설정된 직후에 userId를 추출하여 request attribute로 설정
- 이를 통해 HttpLoggingFilter, CustomExceptionHandler 등 다운스트림 컴포넌트에서 userId 활용 가능
요청 추적 및 로깅 인프라와 잘 통합되었습니다.
src/main/java/com/example/solidconnection/common/interceptor/RequestContextInterceptor.java (2)
12-25: 요청 컨텍스트 초기화 로직이 잘 구현되었습니다.변경 내용을 정리하면:
preHandle에서 HTTP method와 best matching path를 캡처RequestContext객체를 생성하여RequestContextHolder의 ThreadLocal에 저장- 이를 통해
QueryMetricsListener가 쿼리 메트릭에 HTTP 컨텍스트를 태깅 가능참고사항:
- Line 19의
bestMatchPath는 핸들러 매핑이 없는 경우(정적 리소스, 에러 등) null일 수 있습니다QueryMetricsListener에서 null 체크 후 "-"로 대체하므로 안전하게 처리됩니다
27-34: ThreadLocal 정리가 올바르게 구현되었습니다.변경 내용:
afterCompletion에서RequestContextHolder.clear()호출- 요청 처리 완료 후 ThreadLocal 값을 제거하여 메모리 누수 방지
중요:
afterCompletion은 예외 발생 시에도 호출되므로 ThreadLocal 정리에 적합한 위치입니다- ThreadLocal 사용 시 반드시 필요한 정리 로직이 정확하게 구현되었습니다
src/main/java/com/example/solidconnection/common/interceptor/ApiPerformanceInterceptor.java (1)
23-42: 요청 시작 시점 기록 로직이 적절합니다.변경 내용을 정리하면:
- 요청 시작 시간(
startTime)을 기록하여 나중에 응답 시간 계산- Request URI와 best matching pattern을 attribute에 저장
afterCompletion에서 성능 메트릭 계산에 사용구현이 명확하고 올바르게 작동합니다.
src/main/java/com/example/solidconnection/common/interceptor/RequestContext.java (1)
1-16: LGTM! 잘 설계된 불변 컨텍스트 객체입니다.HTTP 메서드와 경로를 담는 단순한 불변 데이터 홀더로, ThreadLocal 환경에서 안전하게 사용할 수 있도록 잘 설계되었습니다.
src/main/resources/logback-spring.xml (2)
6-7: 구조화된 로그 패턴으로 파싱이 용이합니다.
traceId를 포함한 키-값 형식의 로그 패턴은 로그 수집 시스템(예: Loki, ELK)에서 파싱하기 좋은 형태입니다.
65-79: API 성능 로그 분리가 잘 구성되었습니다.
additivity=false설정으로 중복 로깅을 방지하고, 별도 파일로 분리하여 성능 분석이 용이하도록 잘 구성되었습니다.PR 목표에서 언급한 대로 Alloy 설정 변경이 필요합니다. 다음 항목을 확인해주세요:
/var/log/spring디렉터리 및 하위 폴더(info/,warn/,error/,api-perf/) 생성 및 권한 설정- Alloy 설정 파일에서 새로운 로그 경로 반영
- 디스크 용량 모니터링 설정 (로그 4개 스트림 * 7일 보관)
src/main/java/com/example/solidconnection/common/filter/HttpLoggingFilter.java (3)
85-94: userId 로깅이 개인정보 보호 정책을 준수하는지 확인이 필요합니다.응답 로그에
userId를 기록하고 있습니다. 다음 사항을 검토해주세요:
- 규정 준수: GDPR, CCPA 등 적용 가능한 개인정보 보호 규정에서 userId 로깅을 허용하는지 확인
- 로그 보관 정책: 7일간 보관되는 로그에 userId가 포함되어도 문제없는지 확인
- 접근 통제:
/var/log/spring디렉터리에 대한 접근 권한이 적절히 제한되어 있는지 확인userId가 민감 정보로 분류되지 않는다면 문제없지만, 조직의 정책을 확인하는 것이 좋습니다.
40-54: traceId 관리 및 예외 안전성이 우수합니다.다음 항목들이 잘 구현되어 있습니다:
- traceId 생성: 16자 hex 문자열로 충분한 고유성 보장
- 제외 경로 처리: Actuator 엔드포인트는 로깅을 건너뛰지만 traceId는 유지하여 하위 레이어 로깅 지원
- MDC 정리: finally 블록에서
MDC.clear()호출로 ThreadLocal 누수 방지- 중복 로깅 방지:
exceptionHandlerLogged속성으로 CustomExceptionHandler와의 중복 방지Also applies to: 56-69
102-117: URL 디코딩 오류 처리가 안전하게 구현되었습니다.잘못된 URL 인코딩으로 인한
IllegalArgumentException을 catch하여 원본 쿼리 스트링을 반환하는 방식이 적절합니다.src/main/java/com/example/solidconnection/common/listener/QueryMetricsListener.java (2)
44-52: SQL 타입 분류 로직이 적절합니다.간단한 prefix 매칭으로 주요 SQL 타입을 분류하고 있으며, 메트릭 수집 목적으로는 충분합니다. null 처리도 안전하게 구현되어 있습니다.
27-42: 해당 우려사항들은 코드에서 실제 문제가 아닙니다.원본 리뷰의 주요 지적사항들을 검증한 결과, 다음과 같은 사실을 확인했습니다:
경로 카디널리티 위험은 존재하지 않습니다
bestMatchPath는 Spring Framework의HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE에서 가져온 값으로,/users/{id}같은 패턴입니다- 실제 요청 경로(
/users/123같은 값)가 아니므로 카디널리티가 제한됩니다- 메트릭 저장소에 미치는 영향은 미미합니다
타이머 인스턴스 캐싱 최적화는 불필요합니다
- Micrometer는 메서드 이름과 태그 조합(Meter.Id)으로 타이머를 내부적으로 캐싱합니다
meterRegistry.timer()를 동일한 태그로 여러 번 호출해도 캐시된 인스턴스를 반환합니다- 별도의
Map기반 캐시는 필요하지 않습니다현재 구현은 성능 및 카디널리티 측면에서 안전합니다.
Likely an incorrect or invalid review comment.
src/main/java/com/example/solidconnection/common/interceptor/RequestContextHolder.java (1)
4-17: ThreadLocal 정리는 안전하게 이루어집니다.검증 결과, 현재 구현은 메모리 누수 없이 안전하게 작동합니다:
정리 보장 ✓
RequestContextInterceptor의afterCompletion()메서드는 Spring의HandlerInterceptor계약에 따라 요청 처리 완료 시 항상 호출됩니다- 예외 발생 시에도 보장되므로
clear()가 반드시 실행됩니다비동기 작업 처리 ✓
@Async메서드들(UpdateViewCountScheduler,FileUploadService등)은 별도 스레드에서 실행되지만,RequestContextHolder를 사용하지 않습니다RequestContextHolder.getContext()는QueryMetricsListener에서만 호출되며, 이는 요청 스레드 내에서 작동하는 Hibernate 쿼리 리스너입니다- 따라서 비동기 작업과의 상호작용이 없어 ThreadLocal 누수 위험이 없습니다
인터셉터 등록 ✓
RequestContextInterceptor가WebMvcConfig에서addPathPatterns("/**")로 등록되어 모든 경로를 포괄합니다src/main/java/com/example/solidconnection/common/config/web/WebMvcConfig.java (2)
3-5: 관찰성 컴포넌트 의존성 주입이 적절합니다!새로운 필터와 인터셉터들이 깔끔하게 추가되었습니다:
- HttpLoggingFilter - 요청/응답 로깅
- ApiPerformanceInterceptor - API 성능 측정
- RequestContextInterceptor - 요청 컨텍스트 전파
생성자 주입 방식으로 의존성이 명확하게 관리되고 있어 좋습니다.
Also applies to: 10-11, 13-13, 15-15, 24-26
45-51: 로깅 필터 등록이 적절합니다!
HttpLoggingFilter를HIGHEST_PRECEDENCE로 등록한 것이 좋습니다:
- 우선순위 설정: 가장 높은 우선순위로 설정되어 모든 요청/응답을 빠짐없이 로깅할 수 있습니다
- 명시적 등록:
FilterRegistrationBean을 사용하여 필터 설정을 명확하게 제어하고 있습니다- traceId 기반 추적: PR 목표에 맞게 요청 시작부터 종료까지 추적이 가능하도록 구성되었습니다
src/main/java/com/example/solidconnection/common/exception/CustomExceptionHandler.java (2)
28-31: 예외 핸들러에 HttpServletRequest 추가가 일관되게 적용되었습니다!모든 예외 핸들러에
HttpServletRequest가 추가되어 요청 컨텍스트에 접근할 수 있게 되었습니다:
- handleCustomException (line 28-31)
- handleInvalidFormatException (line 42-45)
- handleValidationExceptions (line 57-60)
- handleDataIntegrityViolationException (line 78-81)
- handleJwtException (line 93-96)
- handleOtherException (line 109-112)
Spring의
@ExceptionHandler가 서블릿 객체 주입을 지원하므로 이 방식은 적절하며, 일관된 패턴으로 구현되어 유지보수가 용이합니다.Also applies to: 42-45, 57-60, 78-81, 93-96, 109-112
32-32: 중복 로깅 방지 플래그가 잘 구현되었습니다!모든 예외 핸들러에서
exceptionHandlerLogged플래그를 설정하여HttpLoggingFilter와의 협력이 잘 이루어지고 있습니다:
- 목적: 예외 발생 시 응답이 이미 로깅되었음을 필터에 알려 중복 로깅을 방지
- 일관성: 6개 모든 핸들러에 동일하게 적용
- 통합: PR의 다른 변경사항(HttpLoggingFilter)과 깔끔하게 연동
이 패턴은 분산된 로깅 로직 간의 조율을 명확하게 하여 좋은 설계입니다.
Also applies to: 46-46, 61-61, 82-82, 97-97, 113-113
| // Database Proxy | ||
| implementation 'net.ttddyy:datasource-proxy:1.11.0' | ||
| implementation 'net.ttddyy.observation:datasource-micrometer:1.2.0' |
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.
🧩 Analysis chain
🌐 Web query:
datasource-proxy net.ttddyy latest version Maven Central 2025
💡 Result:
Latest Maven Central version: 1.11.0 (released July 14, 2025).
Maven dependency:
net.ttddyy
datasource-proxy
1.11.0
Sources: [Maven Repository (1.11.0)] [1], [javadoc.io (1.11.0)] [2], [Maven Central index/metadata] [3].
References
- https://mvnrepository.com/artifact/net.ttddyy/datasource-proxy/1.11.0
- https://javadoc.io/doc/net.ttddyy/datasource-proxy/1.11.0
- https://maven-eu.nuxeo.org/nexus/content/groups/public/net/ttddyy/datasource-proxy/
🌐 Web query:
datasource-micrometer net.ttddyy.observation latest version Maven Central 2025
💡 Result:
The latest Maven Central version is net.ttddyy.observation:datasource-micrometer: 2.0.1. [1][2]
Sources:
- mvnrepository entry for datasource-micrometer 2.0.1. [1]
- Official docs (installation snippet showing version 2.0.1). [2]
🌐 Web query:
datasource-proxy 1.11.0 security vulnerability CVE
💡 Result:
I found no public CVE that specifically affects the net.ttddyy datasource‑proxy 1.11.0 library itself. Maven listings for datasource‑proxy 1.11.0 show reported vulnerabilities coming from its dependencies (examples listed there include CVE-2025-68161, CVE-2024-38819, CVE-2023-6378), not a direct CVE for datasource‑proxy. [1]
Note: There is a separate, unrelated Grafana "datasource proxy" advisory (CVE-2025-3454) that affects Grafana’s server API — not the net.ttddyy datasource‑proxy Java library. Do not confuse the two. [2]
Sources:
- Maven / mvnrepository entry for net.ttddyy:datasource-proxy 1.11.0 (vulnerability list). [1]
- Grafana security advisory (CVE-2025-3454) — unrelated Grafana product issue. [2]
References:
[1] https://mvnrepository.com/artifact/net.ttddyy/datasource-proxy/1.11.0
[2] https://grafana.com/security/security-advisories/cve-2025-3454/
🌐 Web query:
datasource-micrometer 1.2.0 security vulnerability CVE
💡 Result:
I found no public CVE specifically affecting net.ttddyy.observation:datasource-micrometer version 1.2.0. The Maven listing for that artifact/version shows no CVE entry for the artifact itself. [1]
There are unrelated CVEs for other metric libraries (for example CVE-2020-1960 affecting Apache Flink's JMX reporter), but those do not apply to datasource-micrometer. [2][3]
If you want, I can:
- scan OSS advisories (GitHub Security Advisories, NVD) for any recent updates, or
- check your SBOM/dependency tree for transitive vulnerabilities that might affect your build. Which would you prefer?
Sources:
[1] mvnrepository — net.ttddyy.observation:datasource-micrometer 1.2.0.
[2] Micrometer security policy / advisories.
[3] NVD / GitLab advisory — CVE-2020-1960 (example of an unrelated metrics CVE).
데이터소스 프록시 의존성이 추가되었습니다. datasource-micrometer 버전 업그레이드를 권장합니다.
변경 내용:
datasource-proxy:1.11.0- 최신 버전이며, 쿼리 인터셉션을 위한 핵심 프록시 라이브러리입니다.datasource-micrometer:1.2.0- 최신 버전은 2.0.1이므로 업그레이드를 고려하세요. Micrometer와의 통합을 위한 라이브러리입니다.
DataSourceProxyConfig 및 QueryMetricsListener와 연동되어 쿼리별 메트릭 수집을 지원합니다. 현재 datasource-micrometer는 1.2.0 사용 중이지만, 2.0.1이 최신 버전으로 이용 가능합니다. 특정 보안 취약점은 발견되지 않았으나, 최신 버전으로 업그레이드하면 개선 사항과 안정성을 함께 얻을 수 있습니다.
🤖 Prompt for AI Agents
In build.gradle around lines 72 to 74, the datasource-micrometer dependency is
pinned to 1.2.0 but should be upgraded to the current 2.0.1; update the
implementation coordinate from
'net.ttddyy.observation:datasource-micrometer:1.2.0' to
'net.ttddyy.observation:datasource-micrometer:2.0.1' and then run a quick build
and tests to verify compatibility (adjust any import or API usages in
DataSourceProxyConfig/QueryMetricsListener if the newer API changed).
| "/actuator/**" | ||
| ); | ||
|
|
||
| private final ObjectMapper objectMapper = new ObjectMapper(); |
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.
사용되지 않는 ObjectMapper 필드를 제거해주세요.
objectMapper 필드가 선언되어 있지만 코드 내에서 사용되지 않습니다.
🔎 제안하는 수정
- private final ObjectMapper objectMapper = new ObjectMapper();📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| private final ObjectMapper objectMapper = new ObjectMapper(); |
🤖 Prompt for AI Agents
In
src/main/java/com/example/solidconnection/common/filter/HttpLoggingFilter.java
around line 31, the private final ObjectMapper objectMapper = new
ObjectMapper(); field is declared but never used; remove this unused field
declaration and any now-unused imports related to ObjectMapper (e.g.,
com.fasterxml.jackson.databind.ObjectMapper), then rebuild to confirm no
references remain.
관련 이슈
작업 내용
1. 로깅 필터 추가
- traceId 와 request response 로깅을 통해 , api의 시작과 끝에 대한 로그를 추적하기 쉽게 하기 위해 추가하였습니다.
2. Api 수행시간 interceptor
- api 별 수행시간을 로그로 남기기 위해 추가하였습니다.
3. 데이터 소스 프록시 추가 및 쿼리 별 수행시간 메트릭 저장 기능 추가
- 각 api 에서 발생하는 쿼리들의 수행 시간을 메트릭으로 전송합니다.
- 로그로 남기기엔 너무 용량이 커질 듯 하여 메트릭만 전송합니다.
4. 로그 파일 전략 수정
- 로그 폴더를 info, warn, error, api_perf 로 관리하여 로그 파일의 복잡도를 낮추는 방향으로 수정 해 보았습니다.
특이 사항
log 파일 저장 구조가 변경되어 alloy 파일의 수정이 필요합니다.
쿼리 메트릭을 대시 보드에서 찍기 위한 설정이 필요합니다.
리뷰 요구사항 (선택)