Files
llm-wiki/raw/branch-notes/feature-startup-failure-log-suppression.md

20 KiB

title, source_type, status, branch, parent_branch, related_projects, tags, created, target_merge, status_label, id, kind, project, work_item, inherits, refines, overrides, depends_on, contract_packet, contract_packet_sha256
title source_type status branch parent_branch related_projects tags created target_merge status_label id kind project work_item inherits refines overrides depends_on contract_packet contract_packet_sha256
branch / feature-startup-failure-log-suppression branch-note raw feature-startup-failure-log-suppression
ca-tmpl
branch
ca-tmpl
runtime
spring-boot
error-handling
flyway
log-routing
2026-07-03 in-progress BR-CA-SKELETON-OPERATIONAL-CONTRACT-058 project-work-item ca-skeleton-operational-contract WI-CA-SKELETON-OPERATIONAL-CONTRACT-058
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-BOOTSTRAP-001@1
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-ERROR-ENVELOPE-001@1
WI-CA-SKELETON-OPERATIONAL-CONTRACT-001
WI-CA-SKELETON-OPERATIONAL-CONTRACT-017
1 e7c1afc830ee67bc838ff152355faa14fe6c26669d8914655bda307ea186532b

branch: feature-startup-failure-log-suppression

Layer: raw/branch-notes/ — ca-tmpl startup failure logging 작업 기록. 실제 git branch: develop.

부모 (필수)

브랜치 계약 패킷

  • 생성 시 프로젝트 개정: 1
  • 패킷 스키마: contract_packet: 1
  • 완료 조건: suppressible startup failure 조건과 retained actionable error test가 명시된다

상속한 프로젝트 결정

Decision Ref Project Summary Branch Application Source
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-BOOTSTRAP-001@1 신규 환경의 default 진입 명령은 ./gradlew bootstrap이다 Work Item 완료 조건에 적용 raw/project-notes/ca-skeleton-operational-contract
DEC-CA-SKELETON-OPERATIONAL-CONTRACT-ERROR-ENVELOPE-001@1 foundation이 envelope schema와 error.category enum의 단일 owner다 Work Item 완료 조건에 적용 raw/project-notes/ca-skeleton-operational-contract

브랜치 지역 결정

기존 branch-local 결정은 아래 ## Decision Evidence Map / 결정-근거 매핑의 D-row가 소유하며 이 packet에서 복제하지 않는다.

Decision ID Decision Relation Supporting Claims Status

선언한 예외

Override ID Overrides Reason Approval Status

목표

  • Spring Boot startup failure에서 ca-tmpl의 구조화 MIGRATION_FAILED 로그와 Spring Boot 기본 Application run failed stacktrace가 함께 출력되는 문제를 줄인다.
  • 목표 정책: startup failure는 startup.phase, error.code, error.category, root-cause 요약만 남기고 framework/driver stacktrace는 application log에 출력하지 않는다.

범위

포함 범위

  • app-bootstrap startup failure logging 계약 변경.
  • StartupFailures canonical log에서 SLF4J throwable 인자 제거.
  • SpringBootExceptionReporter로 typed startup failure의 Spring Boot 기본 실패 report 억제.
  • Logback TurboFilter로 startup failure 이후의 SpringApplication 중복 close/report message 억제.
  • settings/validator startup failure를 StartupFailures.envValidation(...)로 통일.
  • Spring Boot context refresh cancellation / failure analysis residual log 억제.
  • focused tests, :app-bootstrap:test, verifyCleanArchitectureDependencies, check 검증.

제외 범위

  • runtime HTTP exception response shape 변경.
  • persistence DB_* SQLState matrix 변경.
  • production 환경 로그 검증.

근거

Source 정당화하는 결정
Local code evidence: src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/runtime/startup/StartupFailures.java 기존 canonical startup failure log가 throwable cause를 SLF4J에 넘겨 stacktrace를 출력하던 사실 확인.
Local dependency evidence: javap org.springframework.boot.SpringApplication SpringBootExceptionReporter#reportExceptiontrue를 반환하면 Spring Boot가 failure를 logged exception으로 등록하고 generic report path를 종료하는 흐름 확인.
Local test evidence: ./gradlew check 전체 Gradle guard 통과로 구현·검증 결과 확인.

TODO

  • Startup failure canonical log에서 throwable proxy 제거 — 등급: actually-implemented
  • root-cause class/message 구조화 필드 추가 — 등급: actually-implemented
  • startup failure 전용 SpringBootExceptionReporter 등록 — 등급: actually-implemented
  • SpringApplication 중복 close/report log filter 추가 — 등급: actually-implemented
  • app-bootstrap settings/validator plain startup exception을 StartupValidationException으로 번역 — 등급: actually-implemented
  • Spring Boot context cancellation / failure analysis residual log filter 확장 — 등급: actually-implemented
  • DB down / invalid tracing sample rate bootRun 재현 검증 — 등급: locally-verified
  • focused tests, :app-bootstrap:test, verifyCleanArchitectureDependencies 실행 — 등급: locally-verified

진행 중 메모

  • TDD RED로 StartupFailuresTest가 기존 throwable proxy 때문에 실패하는 것을 먼저 확인했다.
  • SpringBootExceptionReporter만으로는 Unable to close ApplicationContext WARN을 제어하지 못하므로, canonical startup failure가 이미 기록된 뒤 SpringApplication의 exact duplicate message만 차단하는 Logback filter를 추가했다.
  • ./gradlew check 첫 실행은 Spotless formatting 위반으로 실패했고, :app-bootstrap:spotlessApply 적용 후 재실행에서 통과했다.
  • 2026-07-03 후속 hardening: ConfigurationProperties record와 runtime startup validator가 plain IllegalStateException/IllegalArgumentException을 던지던 사각을 StartupFailures.envValidation(...) 으로 통일했다.
  • invalid tracing sample rate 재현에서 기존 BindException/NumberFormatException/FailureAnalysis 출력은 compact STARTUP_VALIDATION_FAILED 로그 1줄로 축소되었다.
  • DB down migration 재현에서 기존 context refresh cancellation BeanCreationException WARN은 더 이상 grep 결과에 나타나지 않았다. 남은 Spring BeanPostProcessorChecker/Micrometer WARN은 exception report가 아니라 별도 framework lifecycle/noise 축이다.

결정 사항

  • 2026-07-03: startup failure log는 stacktrace 대신 root-cause summary field만 남긴다 / 이유: 운영자가 분류할 수 있는 정보는 유지하면서 driver/framework stacktrace 노출과 중복을 줄이기 위해 / 검토한 대안: 중복 제거만, profile별 stacktrace 분기 / 근거: local code + test evidence.
  • 2026-07-03: Spring Boot generic Application run failedSpringBootExceptionReporter로 typed startup failure에 한해 억제한다 / 이유: unknown startup failure의 Boot 기본 진단은 유지하기 위해 / 검토한 대안: org.springframework.boot.SpringApplication logger 전체 off / 근거: local dependency evidence.
  • 2026-07-03: context close 중복 WARN은 marker 기반 Logback filter로 exact message만 차단한다 / 이유: reporter 이후 context close 단계에서 발생하는 별도 SpringApplication WARN을 좁은 범위로 억제하기 위해 / 검토한 대안: logger 전체 off, 방치 / 근거: attached runtime log + local test evidence.
  • 2026-07-03: startup validation/settings failure는 plain Java exception 대신 StartupFailures.envValidation(...) 으로 번역한다 / 이유: Boot binding/context failure path에 들어가더라도 cause chain에 StartupFailureException이 포함돼 compact reporter/filter 정책이 적용되게 하기 위해 / 검토한 대안: reporter가 모든 IllegalStateException을 잡도록 확장, Spring Boot failure analyzer logger만 억제 / 근거: local bootRun 재현 + focused tests.
  • 2026-07-03: LoggingFailureAnalysisReporter와 Spring context refresh cancellation log는 startup failure marker가 켜진 뒤에만 filter에서 억제한다 / 이유: unknown boot failure 진단은 보존하고, 이미 compact startup failure가 기록된 중복 exception detail만 제거하기 위해 / 검토한 대안: Spring logger level 조정, failure analysis reporter 전체 비활성 / 근거: local bootRun 재현 + filter tests.

결정-근거 매핑

Decision ID Decision Supporting Claims Evidence Strength Open Risk
D1 StartupFailures는 cause를 예외에는 보존하되 SLF4J throwable 인자로 넘기지 않고 root-cause class/message만 로그 구조화 필드로 남긴다. UNSUPPORTED_DECISION — local code inspection and user-approved policy; trade-off: stacktrace triage detail is removed from startup logs. actually-implemented + locally-verified 운영자가 전체 stacktrace를 로그에서 바로 보지 못하므로 재현 환경에서 cause chain 확인이 필요할 수 있다.
D2 StartupFailureExceptionReporter는 cause chain에 StartupFailureException이 있을 때만 true를 반환해 Boot generic failure report를 억제한다. UNSUPPORTED_DECISION — local javap inspection of Spring Boot failure reporting path; trade-off: official doc raw source was not captured in this task. actually-implemented + locally-verified Spring Boot internal flow가 major upgrade에서 바뀌면 reporter 효과를 재검증해야 한다.
D3 StartupFailureSpringBootLogFilter는 canonical startup failure 이후 SpringApplication의 Application run failedUnable to close ApplicationContext exact message만 차단한다. UNSUPPORTED_DECISION — attached log symptom + local filter tests; trade-off: process-local marker assumes startup failure is fatal. actually-implemented + locally-verified 동일 JVM에서 startup failure 후 테스트가 계속되는 특수 상황은 marker reset test helper에 의존한다.
D4 Wiki branch-note slug는 logical work unit feature-startup-failure-log-suppression을 사용하고, 실제 git branch develop은 본문에 기록한다. UNSUPPORTED_DECISION — LLM Wiki naming lint rejects develop.md; trade-off: ca-tmpl branch-name capture와 wiki naming gate 사이의 충돌을 wiki document shape 우선으로 해결. documented-only git branch 기준 검색 시 logical note slug를 한 번 더 확인해야 한다.
D5 app-bootstrap startup settings/validators는 invalid config를 plain Java exception이 아니라 StartupFailures.envValidation(...)으로 던진다. UNSUPPORTED_DECISION — local bug reproduction and user-approved policy; trade-off: direct constructor tests now observe StartupValidationException instead of IllegalArgumentException. actually-implemented + locally-verified LoggingSettings처럼 startup validation owner가 아닌 warn-and-default bootstrap helper는 별도 정책 예외로 남는다.
D6 startup failure marker 이후 LoggingFailureAnalysisReporter와 Spring context refresh cancellation log를 filter에서 억제한다. UNSUPPORTED_DECISION — local bootRun symptom and filter tests; trade-off: fatal startup failure window에서 Spring Boot failure-analysis banner를 숨긴다. actually-implemented + locally-verified Spring Boot logger/message 이름이 major upgrade에서 바뀌면 bootRun 재현 테스트로 재확인 필요.

구현 가이드

1. Canonical startup log

Trace: D1

  • UNSUPPORTED_IMPL_DECISION: structured field 이름은 error.root_cause.classerror.root_cause.message를 사용했다. 기존 error.code/error.category dotted naming과 맞춘 local convention이다.
File 구현
StartupFailures.java cause가 있을 때 rootCause(cause)를 찾아 class/message를 structured argument로 기록하고, throwable 인자는 넘기지 않는다.
StartupFailuresTest.java migration failure log event의 ThrowableProxy가 null이고 root-cause summary field가 있는지 검증한다.

2. Spring Boot duplicate report suppression

Trace: D2, D3

  • UNSUPPORTED_IMPL_DECISION: SpringBootExceptionReporter와 Logback TurboFilter를 함께 사용했다. reporter는 generic report path만 막고, filter는 reporter 이후 context close duplicate WARN만 좁게 막는다.
File 구현
StartupFailureExceptionReporter.java cause chain에 StartupFailureException이 있으면 true, 아니면 false.
META-INF/spring.factories org.springframework.boot.SpringBootExceptionReporter key로 reporter 등록.
StartupFailureLogState.java canonical startup failure가 기록됐는지 process-local marker 제공.
StartupFailureSpringBootLogFilter.java marker가 켜진 뒤 org.springframework.boot.SpringApplication의 exact duplicate messages만 DENY.
logback-spring.xml startup failure duplicate filter를 turbo filter로 등록.

3. Startup validation translation hardening

Trace: D5, D6

  • UNSUPPORTED_IMPL_DECISION: settings record compact constructor도 StartupFailures.envValidation(...) 을 직접 호출한다. app-bootstrap의 운영 설정 검증이며 비즈니스 규칙이 아니므로 composition-root 책임 안에 둔다.
File 구현
AsyncExecutorSettings.java, IdempotencySettings.java, OutboxSettings.java, TracingSettings.java invalid runtime setting을 StartupFailures.envValidation(...)으로 변환한다.
RuntimeNumericBoundsValidator.java, HikariPoolConstraintValidator.java, OpenInViewSafetyValidator.java, SecretSourceValidator.java startup safety guard의 plain exception을 StartupFailures.envValidation(...)으로 변환한다.
StartupFailureSpringBootLogFilter.java marker 이후 LoggingFailureAnalysisReporter 전체와 Spring context refresh cancellation prefix를 DENY한다.
focused settings/validator/filter tests invalid path가 StartupValidationException으로 번역되고 residual Boot logs가 filter에서 차단되는지 검증한다.

엣지·실패·의존

  • 실패·엣지 경로: cause chain self-reference는 reporter와 root cause walker가 무한 루프를 피해야 한다.
  • 실패·엣지 경로: non-startup exception은 Spring Boot 기본 failure report를 유지해야 한다.
  • 다른 계약 의존: app-bootstrap logging bootstrap과 Spring Boot spring.factories loading path에 의존한다.

검증해야 할 주장

Claim Why uncertain How to verify Status
실제 bootRun에서 DB down 시 Application run failed, context refresh cancellation, BeanCreationException stacktrace가 출력되지 않는다. 2026-07-03 후속 hardening에서 실제 재현 수행. APP_DATASOURCE_URL='jdbc:postgresql://127.0.0.1:1/ca_skeleton' timeout 60s ./gradlew :app-bootstrap:bootRun --quiet 2>&1 | rg -n "startup failure|Application run failed|Exception encountered during context initialization|LoggingFailureAnalysisReporter|BeanCreationException|ConnectException|Caused by:" -C 2 locally-verified
실제 bootRun에서 invalid tracing sample rate가 BindException/NumberFormatException stacktrace 대신 compact startup failure로 출력된다. 2026-07-03 후속 hardening에서 실제 재현 수행. APP_MIGRATION_ON_STARTUP=false APP_TRACING_SAMPLE_RATE='not-a-number' timeout 60s ./gradlew :app-bootstrap:bootRun --quiet 2>&1 | rg -n "startup failure|Application run failed|Exception encountered during context initialization|LoggingFailureAnalysisReporter|BindException|NumberFormatException|Caused by:" -C 2 locally-verified
Spring Boot major upgrade 후에도 SpringBootExceptionReporter의 true-return behavior가 동일하다. local dependency bytecode 확인에 기반한 결정이다. Spring Boot upgrade branch에서 reporter focused test와 실제 startup failure 로그 재현. needs-confirmation

관심사 커버리지

관심사 상태 owner 심각도 근거
startup failure canonical log covered-here D1
Spring Boot duplicate failure report covered-here D2, D3, D6
app-bootstrap startup validation/settings plain exception covered-here D5
runtime HTTP exception response delegated existing adapter-web error contract OK Out of scope
runtime background log(..., ex) stacktrace delegated future runtime logging hardening OK Out of scope

마주친 문제

  • Spotless formatting failure
  • 2026-07-03 후속 hardening 중 TDD RED failures
    • 원인: 의도적으로 settings/validator tests를 StartupValidationException 기대치로 먼저 바꿔 기존 plain exception 사각을 재현.
    • 해결: StartupFailures.envValidation(...) 전환 후 focused suite green.
    • 별도 에러 노트: 없음. 의도된 RED 단계로 별도 트러블슈팅 문서화 대상 아님.
  • 2026-07-03 전체 check 실패
    • 원인: :sample-portfolio:test web context startup 중 Tomcat PortInUseException/BindException.
    • 시도: import order Spotless failure 수정 후 ./gradlew check 재실행.
    • 해결: 이번 변경 범위 밖의 sample-portfolio test/runtime port collision으로 분리 기록. focused startup/logging suite, :app-bootstrap:test, verifyCleanArchitectureDependencies, bootRun 재현은 통과/확인.
    • 별도 에러 노트로 분리됨: raw/errors/sample-portfolio-tomcat-port-in-use-check-2026-07-03

묶음 (이 branch에서 파생된 자료)

Sub-branches (세부 작업)

  • 없음.

오류 기록 (이 branch 작업 중 발생)

면접 준비 (이 작업에서 나올 수 있는 면접 질문)

  • 추출할 별도 면접 질문 없음.

강의 (이 작업을 위해 학습한 강의)

  • 없음.

job-posting tie-ins (이 작업에서 파생된 글감)

  • 후보: startup failure compact logging hardening은 블로그 글감으로 확장 가능하나, 이번 캡처에서는 별도 raw/blog-topic으로 분리하지 않음.

관련 일일 노트

  • 없음.

완료 후 정리

  • PR 링크:
  • 리뷰 메모:
  • 머지 결과 / 배포 환경: local verification only.
  • wiki 추출 대상:
    • actually-implemented 항목: startup failure stacktrace suppression implementation; startup settings/validator exception translation hardening; residual Spring Boot failure-analysis/context-cancellation log filter.
    • locally-verified 항목: focused tests, :app-bootstrap:test, verifyCleanArchitectureDependencies, DB down bootRun reproduction, invalid tracing sample rate bootRun reproduction.
    • prod-verified 항목: 없음.
  • 추출하지 않을 항목:
    • 전체 ./gradlew check: :sample-portfolio:testPortInUseException으로 실패. 변경 범위와 분리해 raw error note에 기록.
    • runtime background log(..., ex) stacktrace cleanup은 별도 future work.