-
Notifications
You must be signed in to change notification settings - Fork 2
feat: prod 환경 logback error level 디스코드 연동 - #155 #165
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
📝 WalkthroughSummary by CodeRabbit릴리스 노트
Walkthrough헬스체크 요청을 건너뛰고 traceId를 확보한 뒤 MDC에 uri·method·trace_id를 설정하고 체인 실행 후 status를 MDC에 기록하며 finally에서 개별 MDC 키들을 제거하도록 필터가 변경되었고, logback-prod에 INFO/ERROR 필터·MDC 확장·비동기 appenders·Discord HTTP appender가 추가되며 Gradle에 Discord appender 의존성이 추가되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Client
participant Filter as MDCLoggingFilter
participant Chain as FilterChain
participant App as Application
rect rgb(245,255,245)
Client->>Filter: HTTP Request
note right of Filter: 1) health-check 검사\n2) traceId 확인/생성\n3) MDC에 trace_id, uri, method 설정
end
alt health-check URL
Filter-->>Client: short-circuit (skip logging)
else normal request
Filter->>Chain: proceed(request)
Chain->>App: handle request
App-->>Chain: response(status)
Chain-->>Filter: response
note right of Filter: 4) MDC에 status 설정\n5) 로그 이벤트 발생 → 비동기 appenders (INFO/ERROR/Discord)
Filter-->>Client: response
end
rect rgb(255,250,245)
note right of Filter: finally: 개별 MDC 제거(status, method, uri, trace_id)
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
Pre-merge checks and finishing touches✅ Passed checks (4 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
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: 0
🧹 Nitpick comments (1)
src/main/resources/logback/logback-prod-file.xml (1)
133-138: Discord 전송 실패 시 에러 로그 유실 가능성을 고려하세요.
queueSize=500은 Discord webhook이 지연되거나 실패할 때 버퍼 역할을 하기에 작을 수 있습니다. 네트워크 장애나 Discord API 장애 시 많은 에러 로그가 유실될 수 있습니다.권장 사항:
- Discord 알림의 중요도에 따라
queueSize를 1000-2000으로 증가시키는 것을 고려하세요.- 또는 Discord 전송 실패가 허용 가능하다면(ERROR_FILE에 이미 기록되므로) 현재 설정을 유지하세요.
Line 113-114의 timeout 설정(3초)이 적절한지도 검토하세요. Discord 응답이 느린 경우 큐가 빠르게 쌓일 수 있습니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/main/java/com/permitseoul/permitserver/global/filter/MDCLoggingFilter.java(1 hunks)src/main/resources/logback/logback-prod-file.xml(5 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: sjk4618
Repo: PERMIT-SEOUL/permit-server PR: 48
File: src/main/java/com/permitseoul/permitserver/domain/guest/core/domain/entity/GuestEntity.java:31-37
Timestamp: 2025-07-15T09:37:32.765Z
Learning: sjk4618 prefers to implement factory methods or public constructors for entities when they are actually needed, rather than creating them proactively.
🧬 Code graph analysis (1)
src/main/java/com/permitseoul/permitserver/global/filter/MDCLoggingFilter.java (1)
src/main/java/com/permitseoul/permitserver/global/Constants.java (1)
Constants(3-24)
🔇 Additional comments (9)
src/main/java/com/permitseoul/permitserver/global/filter/MDCLoggingFilter.java (4)
24-29: LGTM! MDC 키 상수 선언이 올바릅니다.Java 컨벤션에 맞게
private static final순서로 수정되었고, 새로운 MDC 키들(URI, METHOD, STATUS)이 logback 설정과 일관되게 정의되었습니다.
36-40: 헬스 체크 필터링 로직이 적절합니다.헬스 체크 엔드포인트에 대해 MDC 처리를 건너뛰어 불필요한 로깅 오버헤드를 방지하고 있습니다. null 체크도 올바르게 구현되어 있습니다.
47-52: 예외 발생 시 STATUS MDC 누락 가능성을 확인하세요.현재 구조에서는
filterChain.doFilter()실행 중 예외가 발생하면 Line 52의 STATUS가 MDC에 설정되지 않습니다. 예외가 발생한 요청의 에러 로그에 STATUS 정보가 누락될 수 있습니다. 필요하다면 finally 블록이나 catch 블록에서 response.getStatus()를 호출하여 STATUS를 설정하는 것을 고려해보세요.
54-57: 개별 MDC 제거로의 변경이 더 안전합니다.
MDC.clear()대신 개별 키를 제거하는 방식은 다른 필터가 설정한 MDC 엔트리에 영향을 주지 않아 더 안전합니다. 좋은 개선입니다.src/main/resources/logback/logback-prod-file.xml (5)
7-11: INFO와 ERROR 로그 분리가 올바르게 구현되었습니다.LevelFilter를 통해 INFO_FILE에서 ERROR 레벨을 제외하고, ERROR_FILE에서만 ERROR를 수용하여 로그가 명확하게 분리됩니다.
25-27: MDC 컨텍스트 확장이 MDCLoggingFilter와 일관됩니다.uri, method, status 필드가 추가되어 로그에 요청 컨텍스트 정보가 풍부해졌습니다. MDCLoggingFilter에서 설정하는 키들과 정확히 일치합니다.
Also applies to: 58-60
66-66: 스택 트레이스 깊이 증가가 디버깅에 도움이 됩니다.
maxDepthPerThrowable을 10에서 20으로 증가시켜 복잡한 예외 체인의 근본 원인을 더 잘 파악할 수 있습니다. 로그 크기 증가는 합리적인 수준입니다.
88-115: Discord JSON 페이로드의 특수 문자 처리 문제 재확인제공된 컨트롤러 검색 결과를 바탕으로 URI 패턴을 검증했습니다. 대부분의 경로 변수(eventId, ticketCode, paymentKey 등)는 숫자나 안전한 코드 형식이지만, 로그백 설정의 근본적인 문제는 여전히 존재합니다.
현재 문제:
Line 108의 패턴에서trace_id=%X{trace_id} uri=%X{uri} method=%X{method} status=%X{status}가 JSON 문자열 내에 직접 삽입되고 있습니다.%message와%xEx는%replace로 개행을 처리하지만, MDC 값들에는 이스케이핑이 적용되지 않아 다음과 같은 경우에 JSON이 깨질 수 있습니다:
- URI 쿼리 파라미터에 큰따옴표나 백슬래시 포함 시
- 특수 제어 문자가 포함된 경우
권장 개선 사항:
LoggingEventCompositeJsonEncoder사용하여 구조화된 JSON 생성 (선호)- 또는 MDC 값에 대한 이스케이핑 추가:
%replace(%X{uri}){'\"','\\\"'}
126-131: ASYNC_ERROR의 블로킹 동작은 의도된 설계 입니다 (에러 로그 유실 방지 우선)검증 결과, 파일의 주석에 명시된 대로 ASYNC_ERROR의
neverBlock=false설정은 의도된 것입니다. 에러 로그 유실을 방지하기 위해 큐가 가득 찰 경우 요청 처리 스레드의 블로킹을 허용하는 설계입니다.현재 설정의 트레이드오프:
- 장점: 에러 로그 손실 방지 (discardingThreshold=0)
- 위험: 에러 급증 시 요청 스레드 블로킹 가능성 (queueSize=2000)
권장 검토 항목:
- 프로덕션 환경에서 실제 에러 발생 빈도가 이 트레이드오프를 정당화하는지 확인
- 필요시
queueSize증가 또는neverBlock=true+discardingThreshold조정을 고려
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
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/main/resources/logback/logback-prod-file.xml(4 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: sjk4618
Repo: PERMIT-SEOUL/permit-server PR: 48
File: src/main/java/com/permitseoul/permitserver/domain/guest/core/domain/entity/GuestEntity.java:31-37
Timestamp: 2025-07-15T09:37:32.765Z
Learning: sjk4618 prefers to implement factory methods or public constructors for entities when they are actually needed, rather than creating them proactively.
🔇 Additional comments (4)
src/main/resources/logback/logback-prod-file.xml (4)
34-34: 파일명 패턴 변경(ZIP→LOG)과 cleanHistoryOnStart 활성화의 운영 영향을 확인하세요.
.zip형식에서.log형식으로 변경되어 로그가 자동으로 압축되지 않습니다. 저장 공간 비용이 증가할 수 있습니다.cleanHistoryOnStart=true가 추가되어 애플리케이션 시작 시 이전 로그 기록이 삭제됩니다(maxHistory 초과분). 운영 환경에서 로그 보존 정책과 일치하는지 확인이 필요합니다.이 변경사항이 프로덕션 환경의 로그 보존 정책(maxHistory: 30일)과 일치하는지, 그리고 저장 공간 계획에 포함되었는지 확인해 주세요.
Also applies to: 80-80
117-131: 비동기 Appender 큐 설정 및 드롭/블로킹 전략이 적절하게 구성되었습니다.각 로그 레벨별 우선순위와 앱 성능 보호의 균형이 잘 맞춰져 있습니다:
- INFO: 큐 가득 시 WARN 이하 드롭 + 논블로킹 (지연 방지)
- ERROR: 큐 가득 시 블로킹 (에러 손실 방지)
- DISCORD: 큐 가득 시 드롭 + 논블로킹 (HTTP 타임아웃 시 앱 지연 방지)
단, 실제 운영 환경에서 큐 크기(INFO: 5000, ERROR: 2000, DISCORD: 500)가 예상 처리량에 충분한지 모니터링하시기 바랍니다.
7-11: INFO_FILE에서 ERROR 레벨 로그 필터링이 올바르게 설정되었습니다.LevelFilter 설정(DENY on ERROR, NEUTRAL on mismatch)으로 INFO/WARN 파일과 ERROR 파일이 명확하게 분리됩니다.
25-27: MDC 필드 설정 및 정리가 일관성 있게 구현되어 있습니다.검증 결과, MDCLoggingFilter에서 logback-prod-file.xml에 추가된 모든 MDC 필드(uri, method, status)가 정확하게 설정되고 있습니다:
uri:request.getRequestURI()로 설정method:request.getMethod()로 설정status: 필터 체인 실행 후response.getStatus()로 설정finally 블록에서 모든 MDC 키(trace_id, uri, method, status)가 올바르게 제거되고 있으므로 요청 간 MDC 정보 누수가 없습니다.
| <!-- Discord 웹훅 전송(error level만) --> | ||
| <appender name="DISCORD_ERROR" class="net.logstash.logback.appender.HttpAppender"> | ||
| <url>${DISCORD_WEBHOOK_URL}</url> <!-- 환경변수로 주입 --> | ||
| <method>POST</method> | ||
| <headers> | ||
| <header> | ||
| <name>Content-Type</name> | ||
| <value>application/json</value> | ||
| </header> | ||
| </headers> | ||
|
|
||
| <!-- ERROR 이상만 전송 --> | ||
| <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> | ||
| <level>ERROR</level> | ||
| </filter> | ||
|
|
||
| <!-- Discord 단문 텍스트: 2000자 제한 대비 요약 포맷 --> | ||
| <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> | ||
| <pattern> | ||
| { | ||
| "content": "[PERMIT-PROD] %level at %d{yyyy-MM-dd HH:mm:ss.SSS,Asia/Seoul}\n%logger{36}\n trace_id=%X{trace_id} uri=%X{uri} method=%X{method} status=%X{status}\n%replace(%message){'\r?\n',' \\n '}%n%replace(%xEx{5}){'\r?\n',' \\n '} | ||
| } | ||
| </pattern> | ||
| </encoder> | ||
|
|
||
| <connectTimeout>3000</connectTimeout> | ||
| <readTimeout>3000</readTimeout> | ||
| </appender> |
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.
Discord JSON payload은 PatternLayoutEncoder의 수동 JSON 구성으로 인한 특수문자 이스케이프 위험이 있습니다.
PatternLayoutEncoder로 수동 JSON을 구성할 때, 메시지나 MDC 값에 큰따옴표("), 백슬래시() 등이 포함되면 JSON 구조가 깨질 수 있습니다. 예를 들어 trace_id나 uri에 특수문자가 있으면 Discord 전송이 실패할 수 있습니다.
다음과 같이 JSON 인코더를 명시적으로 사용하거나, 패턴 필터를 개선해 특수문자를 완전히 이스케이프하는 것이 안전합니다:
<!-- Option 1: JsonLayout 사용 (권장) -->
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<includeContext>false</includeContext>
<customFields>{"source":"PERMIT-PROD","environment":"production"}</customFields>
</encoder>또는
<!-- Option 2: 기존 패턴에 더 강한 이스케이프 추가 -->
<pattern>
{
"content": "[PERMIT-PROD] %level at %d{yyyy-MM-dd HH:mm:ss.SSS,Asia/Seoul}\n%logger{36}\n trace_id=%replace(%X{trace_id}){'"'}{''}' uri=%replace(%X{uri}){'"'}{''}' method=%X{method} status=%X{status}\n...
}
</pattern>🧩 Analysis chain
HttpAppender 클래스 가용성과 환경변수 설정 확인 필요합니다.
Discord 웹훅 통합을 위해 logstash-logback-encoder에 포함된 HttpAppender가 필요합니다. 또한 ${DISCORD_WEBHOOK_URL} 환경변수가 프로덕션 환경에 반드시 설정되어야 합니다.
🏁 Script executed:
#!/bin/bash
# 의존성 확인: logstash-logback-encoder에 HttpAppender 포함 확인
grep -r "HttpAppender" --include="pom.xml" --include="build.gradle"
# MDC 필드 설정 확인: MDCLoggingFilter에서 uri, method, status 설정 여부
rg -A 10 "class MDCLoggingFilter" src/main/java
# 환경변수 문서 확인
find . -name "*.md" -o -name "*.yml" -o -name "*.yaml" | xargs grep -l "DISCORD_WEBHOOK_URL" 2>/dev/null || echo "Environment variable documentation not found"Length of output: 1412
추가 검증이 필요합니다. 현재까지의 결과를 바탕으로:
logstash-logback-encoder는 HttpAppender를 제공하지 않으며, HttpAppender는 별도의 logstash-logback-http 라이브러리에서 제공됩니다.
🏁 Script executed:
#!/bin/bash
# 1. pom.xml에서 의존성 확인
cat pom.xml | grep -A 5 "logstash-logback"
# 2. MDCLoggingFilter에서 MDC.put 호출 확인
rg "MDC\.put" src/main/java/com/permitseoul/permitserver/global/filter/MDCLoggingFilter.java -A 2 -B 2
# 3. 배포 설정/환경변수 문서 검색
find . -type f \( -name "*.md" -o -name "*deployment*" -o -name "*environment*" -o -name "*.yml" \) | head -20Length of output: 666
추가 검증을 진행하겠습니다.
🏁 Script executed:
#!/bin/bash
# 1. build.gradle에서 의존성 확인
find . -name "build.gradle*" -type f | head -5 | xargs cat 2>/dev/null | grep -A 5 -B 2 "logstash\|HttpAppender"
# 2. 프로덕션 배포 워크플로우에서 환경변수 설정 확인
cat .github/workflows/DOCKER-PROD-CD.yml 2>/dev/null | grep -i "discord\|webhook\|env" -A 2 -B 2
# 3. README에서 환경변수 설정 가이드 확인
cat README.md 2>/dev/null | grep -i "discord\|webhook\|env" -A 2 -B 2 || echo "No Discord/webhook config in README"
# 4. HttpAppender 클래스 실제 사용 확인
rg "HttpAppender" --type=java --type=xml src/Length of output: 898
최종 검증을 위해 HttpAppender의 정확한 클래스명을 확인하겠습니다.
🏁 Script executed:
#!/bin/bash
# 다른 HttpAppender 구현체 확인
rg "HttpAppender" build.gradle --context 3Length of output: 0
🌐 Web query:
logstash-logback-encoder 7.4 HttpAppender support
💡 Result:
Short answer: No — logstash-logback-encoder 7.4 does not provide a built-in HttpAppender. The project’s docs and release notes list the provided appenders (TCP, UDP, async, file/rolling via encoders, etc.) but no HttpAppender. [1][2]
If you need to send JSON logs over HTTP, common options are:
- Use LogstashTcpSocketAppender (or another provided appender) and feed a Logstash TCP input. [1]
- Use a third‑party Logback HTTP appender (or implement a small custom appender) that uses net.logstash.logback.encoder.LogstashEncoder to format JSON before posting.
- Write logs to a file/rolling appender and have an external agent ship them via HTTP.
Sources: project README (appenders/encoders) and 7.4 release notes. [1][2]
HttpAppender 의존성이 누락되어 있습니다. 필수 라이브러리를 추가해야 합니다.
logstash-logback-encoder 7.4는 HttpAppender를 제공하지 않습니다. 현재 build.gradle에는 logstash-logback-encoder:7.4만 있으며, logback-prod-file.xml의 net.logstash.logback.appender.HttpAppender 클래스는 런타임에 ClassNotFoundException을 발생시킬 것입니다.
필요한 조치:
build.gradle에 HTTP 전송을 지원하는 Logback appender 라이브러리 추가 (예: logstash-logback-http 또는 대체 구현체)DISCORD_WEBHOOK_URL환경변수 설정 가이드를 README 또는 배포 문서에 추가- MDC 필드(trace_id, uri, method, status)는 MDCLoggingFilter에서 올바르게 설정되고 있으므로 변경 불필요
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: 3
🧹 Nitpick comments (2)
src/main/resources/logback/logback-prod-file.xml (2)
100-102: ThresholdFilter 설정이 일관성 없습니다.ERROR_FILE은 LevelFilter(LINE 73-77)로 ERROR만 수락하지만, DISCORD_ERROR는 ThresholdFilter(LINE 100-102)로 ERROR "이상"을 수락합니다. ThresholdFilter는 더 높은 레벨(FATAL 등)도 포함하므로, 의도가 명확하지 않습니다. Discord에 ERROR 레벨만 전송한다면 LevelFilter 사용을 권장합니다.
LevelFilter로 변경하여 일관성을 높이십시오:
<filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter>
132-137: ASYNC_DISCORD_ERROR의neverBlock: true설정 검토가 필요합니다.현재 설정:
discardingThreshold: 0(ERROR 로그 드롭 없음)neverBlock: true(큐 가득 시 블로킹 안 함)이 두 설정이 충돌합니다.
neverBlock: true이면 큐가 가득 찬 경우 로그가 드롭될 수 있으며,discardingThreshold: 0의 의도가 훼손됩니다.권장:
Discord 전송이 실패해도 로그 손실을 방지하려면neverBlock: false로 변경하십시오 (ASYNC_ERROR와 동일):<appender name="ASYNC_DISCORD_ERROR" class="ch.qos.logback.classic.AsyncAppender"> <appender-ref ref="DISCORD_ERROR"/> <queueSize>500</queueSize> <discardingThreshold>0</discardingThreshold> <neverBlock>false</neverBlock> </appender>다만 이 경우 Discord 웹훅 지연 시 요청 스레드가 블로킹될 수 있으므로, 큐 크기와 타임아웃을 모니터링하십시오.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
build.gradle(1 hunks)src/main/resources/logback/logback-prod-file.xml(4 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: sjk4618
Repo: PERMIT-SEOUL/permit-server PR: 48
File: src/main/java/com/permitseoul/permitserver/domain/guest/core/domain/entity/GuestEntity.java:31-37
Timestamp: 2025-07-15T09:37:32.765Z
Learning: sjk4618 prefers to implement factory methods or public constructors for entities when they are actually needed, rather than creating them proactively.
🔇 Additional comments (6)
src/main/resources/logback/logback-prod-file.xml (6)
7-11: INFO_FILE에 LevelFilter 추가는 적절합니다.ERROR 레벨 로그를 제외하는 설정이 올바르게 추가되었습니다. 이로써 INFO_FILE과 ERROR_FILE의 역할이 명확히 분리됩니다.
112-113: 타임아웃 설정이 적절합니다.connectTimeout 3초, readTimeout 3초 설정으로 Discord 웹훅 호출 시 무한 대기를 방지합니다.
34-34: fileNamePattern 변경이 합리적입니다..zip 압축 형식에서 .log 형식으로 변경되어 로그 접근성이 향상됩니다.
Also applies to: 80-80
38-38:cleanHistoryOnStart추가가 적절합니다.서버 재시작 시 오래된 로그 정리가 자동으로 수행되어 디스크 관리가 개선됩니다.
Also applies to: 84-84
66-66:maxDepthPerThrowable증가(10 → 20)는 스택트레이스 추적성 향상에 도움이 됩니다.더 깊은 호출 스택을 기록함으로써 디버깅 정보가 풍부해집니다. 다만 JSON 페이로드 크기 증가에 유의하십시오.
24-27: MDC 필드 구현이 올바르게 완료되었습니다.검증 결과, MDCLoggingFilter에서 모든 MDC 필드가 정확하게 설정되고 있습니다:
MDC.put(URI, request.getRequestURI())(47줄)MDC.put(METHOD, request.getMethod())(48줄)MDC.put(STATUS, String.valueOf(response.getStatus()))(52줄)logback-prod-file.xml의 설정(24-27줄, 57-60줄)과 일치하며, 클린업도 적절히 구현되어 있습니다.
build.gradle
Outdated
| implementation 'net.logstash.logback:logstash-logback-encoder:7.4' | ||
| implementation 'net.logstash.logback:logstash-logback-http:1.0.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
의존성 버전 호환성 검증이 필요합니다.
logstash-logback-http:1.0.0과 logstash-logback-encoder:7.4의 호환성을 확인하십시오. 특히 HttpAppender가 logback의 encoder/provider와 올바르게 협력하는지 검증해야 합니다. 또한 최신 버전을 사용하고 있는지 확인하시기 바랍니다.
🌐 Web query:
What is the latest version of logstash-logback-http?
💡 Result:
The latest released version of de.idealo.whitelabels:logstash-logback-http is 1.1.1 (released Sep 22, 2022). [1][2]
Sources:
[1] MVNRepository — de.idealo.whitelabels:logstash-logback-http 1.1.1.
[2] Maven Central listing for de.idealo.whitelabels:logstash-logback-http.
잘못된 Maven 아티팩트 그룹 ID를 수정하세요.
Line 80의 net.logstash.logback:logstash-logback-http:1.0.0은 존재하지 않습니다. 올바른 의존성은 de.idealo.whitelabels:logstash-logback-http:1.2입니다.
🤖 Prompt for AI Agents
In build.gradle around lines 79 to 80, the dependency on line 80 uses a
non-existent Maven artifact groupId and coordinates; replace the incorrect
dependency `net.logstash.logback:logstash-logback-http:1.0.0` with the correct
artifact `de.idealo.whitelabels:logstash-logback-http:1.2` so the build resolves
the HTTP encoder dependency properly.
| <url>${DISCORD_WEBHOOK_URL}</url> | ||
| <method>POST</method> |
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
${DISCORD_WEBHOOK_URL} 환경변수 설정 가이드가 필요합니다.
프로덕션 배포 시 이 환경변수가 필수입니다. 미설정 시 HttpAppender 초기화 실패 또는 403/404 에러가 발생할 수 있습니다. 다음을 확인하십시오:
- 배포 문서(README 또는 wiki)에 환경변수 설정 방법 추가
- CI/CD 파이프라인(예: GitHub Actions, Docker)에서 환경변수 주입 설정 확인
- 선택: 환경변수 미설정 시의 graceful fallback 처리 (예: 로그 비활성화)
🏁 Script executed:
#!/bin/bash
# 1. 배포 관련 문서 확인
find . -type f \( -name "README*" -o -name "DEPLOY*" -o -name "*.md" \) | xargs grep -l "DISCORD\|webhook\|환경변수" 2>/dev/null || echo "배포 문서에서 환경변수 설정 가이드 미발견"
# 2. GitHub Actions 워크플로우 확인
find .github/workflows -name "*.yml" -o -name "*.yaml" 2>/dev/null | xargs grep -l "DISCORD\|env" 2>/dev/null || echo "GitHub Actions에서 환경변수 설정 미발견"Length of output: 96
추가 검증이 필요합니다. GitHub Actions 워크플로우 파일과 logback 설정의 상세 내용을 확인하겠습니다.
---
🏁 Script executed:
```shell
#!/bin/bash
# 1. GitHub Actions 워크플로우에서 DISCORD_WEBHOOK_URL 설정 확인
echo "=== DOCKER-DEV-CD.yml 내용 ==="
grep -A5 -B5 "DISCORD\|webhook" .github/workflows/DOCKER-DEV-CD.yml 2>/dev/null || echo "DISCORD 관련 설정 없음"
echo ""
echo "=== DOCKER-PROD-CD.yml 내용 ==="
grep -A5 -B5 "DISCORD\|webhook" .github/workflows/DOCKER-PROD-CD.yml 2>/dev/null || echo "DISCORD 관련 설정 없음"
# 2. 전체 워크플로우 파일에서 env 섹션 확인 (env 변수 주입 여부)
echo ""
echo "=== DOCKER-PROD-CD.yml env 섹션 ==="
grep -A30 "^env:" .github/workflows/DOCKER-PROD-CD.yml 2>/dev/null || echo "env 섹션 없음"
# 3. logback-prod-file.xml 전체 내용 확인 (HttpAppender 및 오류 처리)
echo ""
echo "=== logback-prod-file.xml 전체 내용 ==="
cat src/main/resources/logback/logback-prod-file.xml 2>/dev/null || echo "파일 없음"
Length of output: 181
logback-prod-file.xml 파일을 찾을 수 없습니다. 리포지토리 전체에서 logback 설정 파일을 검색하겠습니다.
---
🏁 Script executed:
```shell
#!/bin/bash
# 1. 모든 logback 관련 파일 찾기
echo "=== logback 관련 파일 검색 ==="
find . -type f -name "*logback*" 2>/dev/null
# 2. 모든 XML 파일 검색 (resources/logback 디렉토리)
echo ""
echo "=== resources/logback 디렉토리 확인 ==="
find . -type d -path "*/resources/logback" 2>/dev/null
# 3. 전체 resources 디렉토리 구조
echo ""
echo "=== resources 디렉토리 구조 ==="
find . -type d -path "*/resources" 2>/dev/null | head -20
Length of output: 324
파일을 찾았습니다. 이제 logback-prod-file.xml의 내용을 확인하여 HttpAppender 설정과 오류 처리를 검증하겠습니다.
---
🏁 Script executed:
```shell
#!/bin/bash
# logback-prod-file.xml 파일 내용 확인
cat src/main/resources/logback/logback-prod-file.xml
Length of output: 5824
배포 문서 및 CI/CD 파이프라인에서 DISCORD_WEBHOOK_URL 환경변수 설정이 누락되어 있습니다.
검증 결과:
- 배포 문서: README, DEPLOY 관련 문서에서 DISCORD_WEBHOOK_URL 설정 가이드 없음 ✓
- CI/CD 파이프라인: GitHub Actions (DOCKER-PROD-CD.yml, DOCKER-DEV-CD.yml)에서 DISCORD_WEBHOOK_URL 환경변수 주입 설정 없음 ✓
- Logback 설정: HttpAppender에 오류 처리나 graceful fallback 메커니즘 미구현 ✓
다음을 작업하십시오:
- 배포 문서(README 또는 wiki)에 환경변수 설정 방법 추가
- CI/CD 파이프라인 (GitHub Actions)에서
DISCORD_WEBHOOK_URL환경변수 주입 설정 - 선택: logback 설정에 HttpAppender 오류 처리 추가 (예: conditional appender, fallback 로그레벨 조정)
| <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> | ||
| <pattern> | ||
| { | ||
| "content": "[PERMIT-PROD] %level at %d{yyyy-MM-dd HH:mm:ss.SSS,Asia/Seoul}\n%logger{36}\n trace_id=%replace(%X{trace_id}){"([\"\\])"}{\\\\$1} uri=%replace(%X{uri}){"([\"\\])"}{\\\\$1} method=%X{method} status=%X{status}\n%replace(%message){"([\"\\])"}{\\\\$1}%n%replace(%xEx{5}){'\r?\n',' \\n '} | ||
| } | ||
| </pattern> | ||
| </encoder> |
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.
Discord JSON 페이로드의 특수문자 이스케이프에 주의가 필요합니다.
패턴: %replace(%X{trace_id}){"([\"\\])"}{\\\\$1}
이 정규식은 큰따옴표와 백슬래시만 처리하지만, 로그 메시지에 개행(\n), 탭(\t), 제어문자 등이 포함되면 JSON 구조가 깨질 수 있습니다. 특히 메시지의 개행(%n)이 JSON 문자열 내부에서 실제 개행이 되면 JSON 파싱이 실패합니다(LINE 108의 %message에도 개행 포함 가능).
권장 개선사항:
- PatternLayoutEncoder 대신 LogstashEncoder 사용 (자동 이스케이프)
- 또는 정규식을 강화하여 모든 제어문자 처리
- 또는 사전 검증을 통해 JSON 유효성 테스트
LogstashEncoder 사용을 권장합니다:
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<includeContext>false</includeContext>
<customFields>{"source":"PERMIT-PROD","environment":"production"}</customFields>
</encoder>🤖 Prompt for AI Agents
In src/main/resources/logback/logback-prod-file.xml around lines 104 to 110, the
PatternLayoutEncoder JSON pattern only escapes quotes and backslashes and can
produce invalid JSON when log fields contain newlines, tabs or other control
chars; replace the PatternLayoutEncoder with a LogstashEncoder
(net.logstash.logback.encoder.LogstashEncoder) configured with
includeContext=false and appropriate customFields to ensure proper JSON
encoding, or alternatively enhance the current %replace chains to escape all
control characters (newline, tab, carriage return, etc.) for every injected
field (%X{trace_id}, %X{uri}, %message, %xEx) so that the output is always a
valid single-line JSON payload.
🔥Pull requests
⛳️ 작업한 브랜치
👷 작업한 내용
prod 환경 logback error level 디스코드 웹훅 전송
🚨 참고 사항