Skip to content

[feat/#647] 로깅 인프라 구축#649

Merged
Dimo-2562 merged 18 commits into
developfrom
feat/#647
Jul 5, 2026
Merged

[feat/#647] 로깅 인프라 구축#649
Dimo-2562 merged 18 commits into
developfrom
feat/#647

Conversation

@Dimo-2562

@Dimo-2562 Dimo-2562 commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

❤️ 기능 설명

운영/디버깅 때 요청 흐름을 더 쉽게 추적할 수 있도록 로깅 인프라를 정리했습니다.

이번 PR에서 추가한 핵심은 아래와 같습니다.

  • MDC 기반 요청 추적 정보 추가

    • MDC는 로그 한 줄마다 같이 출력되는 작은 문맥 정보 저장소입니다.
    • HTTP 요청마다 requestId, method, uri, clientIp, 인증된 경우 memberId를 로그에 함께 남깁니다.
    • 같은 요청에서 발생한 여러 로그를 requestId로 묶어 볼 수 있습니다.
  • 비동기 작업에서도 MDC가 유지되도록 처리

    • Spring @Async 같은 비동기 작업은 다른 스레드에서 실행되기 때문에 기본적으로 MDC가 끊길 수 있습니다.
    • TaskDecorator를 추가해서 요청 스레드의 MDC를 비동기 스레드로 복사하고, 작업 후 정리하도록 했습니다.
  • Logback 파일 로그/롤링 설정 추가

    • 콘솔 로그 외에 파일 로그를 남기도록 logback-spring.xml을 구성했습니다.
    • 일반 애플리케이션 로그, 에러 로그, 웹소켓 로그를 파일로 분리했습니다.
    • 로그 파일은 날짜/크기 기준으로 rolling 되도록 했습니다.
      • application.log: 날짜 기준 1일 단위, 하루 안에서 100MB마다 분할, 최대 30일 보관, 전체 최대 3GB
      • websocket.log: 날짜 기준 1일 단위, 하루 안에서 50MB마다 분할, 최대 14일 보관, 전체 최대 1GB
      • error.log: 날짜 기준 1일 단위, 하루 안에서 50MB마다 분할, 최대 30일 보관, 전체 최대 1GB
  • 로그 I/O 비동기화

    • 파일 쓰기 때문에 요청 처리 스레드가 오래 잡히지 않도록 Logback AsyncAppender를 적용했습니다.
    • 일반/웹소켓 파일 로그는 큐가 가득 찼을 때 요청 처리를 막지 않도록 설정했습니다.
    • 에러 로그는 유실 가능성을 낮추기 위해 별도 파일에 중복 저장합니다.
  • 웹소켓 로그 분리

    • 웹소켓 관련 로그는 콘솔에 직접 찍지 않고 별도 파일로만 남기도록 분리했습니다.
    • 웹소켓 연결/메시지 처리 중에도 MDC가 잡히도록 보완했습니다.
  • Docker 배포 환경 로그 보존

    • 컨테이너 재시작 후에도 로그 파일을 확인할 수 있도록 docker-compose.yml에 로그 volume을 추가했습니다.

연결된 issue

연결된 issue를 자동으로 닫기 위해 아래 {이슈넘버}를 입력해주세요.

close #647



🩷 Approve 하기 전 확인해주세요!

  • JWT 필터에서 서버 에러를 인증 에러로 잘못 catch할 수 있는 이슈를 별도 try-catch로 묶어 해결했습니다.
  • error.log를 별도로 분리해서 에러 로그가 일반 로그 파일과 에러 로그 파일에 함께 남는 방식이 괜찮은지 확인해주세요.
  • 파일 롤링 기간을 기본/웹소켓/에러를 각각 30/14/30으로 설정했는데 의견주시면 감사하겠습니다.
  • X-Forwarded-For 기반 clientIp 신뢰 정책은 추후 nginx/Cloudflare 설정과 함께 별도 개선 예정입니다.

✅ 체크리스트

  • PR 제목 규칙 잘 지켰는가?
  • 추가/수정사항을 설명하였는가?
  • 테스트 결과 사진을 넣었는가?
  • 이슈넘버를 적었는가?

@Dimo-2562 Dimo-2562 requested review from dbalsk and kanghana1 July 3, 2026 08:37

@kanghana1 kanghana1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

파일 롤링기간 좋은 거 같고, 에러로그 분리도 좋은 거 같습니다. 고생하셨습니다!

Comment thread src/main/resources/logback-spring.xml
@Dimo-2562 Dimo-2562 added the 🛠️ FEAT This issue or pull request already exists label Jul 5, 2026
@Dimo-2562 Dimo-2562 merged commit ec7b164 into develop Jul 5, 2026
1 check passed
@Dimo-2562 Dimo-2562 deleted the feat/#647 branch July 5, 2026 18:01
@kanghana1 kanghana1 mentioned this pull request Jul 12, 2026
kanghana1 added a commit that referenced this pull request Jul 12, 2026
* [feat/#589] 안 읽은 메시지 조회 API 구현 (#619)

* refactor: 기존 안 읽은 메시지 조회 로직을 별도 서비스로 분리

* feat: 안 읽은 메시지 조회 API 구현

* refactor: 안 읽은 메시지 조회 로직을 애플리케이션 로직 대신 DB 쿼리로 처리

* test: 안 읽은 메시지 조회 통합 테스트 보강

* chore: 안 읽은 메시지 조회 API는 자주 사용되므로 인덱스 도입하여 조회 성능 개선

* fix: 채팅 배지가 안읽은 메시지 개수가 아닌 단순 boolean 값만 필요하므로 전체 API 수정

* refactor: 채팅방 조회 API에서 안읽은 메시지 조회를 배치 쿼리로 개선

* refactor: 메시지 전송 시 안 읽은 메시지 count를 배치 쿼리로 개선

* fix: 안 읽은 메시지 카운트 업데이트에서 쿼리 실패시 fallback 대신 실패로 변경

* [refactor/#600] ExerciseQueryService 유스케이스별 서비스 분리 (#623)

* refactor: Query 서비스에서 Repository를 직접 참조하지 않도록 변경

* refactor: 맵 쿼리 서비스 분리

* refactor: 추천 쿼리 서비스 분리

* refactor: 내 정보 관련 쿼리 서비스 분리

* refactor: 모임 운동 캘린더 조회 서비스 분리

* refactor: 게스트 조회 서비스 분리

* refactor: 라이프사이클 조회 서비스 분리

* refactor: Reader는 support/reader 패키지로 분리

* fix: 불필요한 Member 검증은 Jwt 필터에서 진행하므로 제거

* debug: 운동 수정용 상세 조회에서 모임장이나 부모임장 권한 로직이 없었떤 버그 제거

* refactor: 사용자 수 계산 쿼리를 운동이 없으면 호출하지 않도록 empty guard 추가

* refactor: contains를 loop를 돌며 호출하는걸 HashSet을 통해 시간복잡도 개선

* refactor: lookup 서비스의 에러는 그 도메인의 에러를 던지도록 변경

* test: Member를 사용하지 않는 서비스에서는 검증 로직을 JWT 필터에 의존하므로 관련 테스트 실패 로직 제거

* test: 시간 의존적인 테스트가 종종 실패하는 문제를 개선

* [refactor/#626] 채팅 REST/WebSocket presentation 계층 정리 (#627)

* refactor: chat 도메인 presentation 계층 정리

* refactor: 웹소켓 메시지 전송 클래스 위치 변경

* refactor: 웹소켓 메시지 전송 클래스 네이밍 명확화

* refactor: Handler는 단순 웹소켓 생명주기 관리로 축소, 메시지 처리는 Dispatcher로 위임

* refactor: request 타입별 메시지 처리를 CommandHandler 책임으로 위임

* refactor: 컨버터에서 웹소켓 전용 로직은 별도 클래스로 분리

* refactor: service 계층에서 presentation 계층에 의존성이 생기므로 일단 converter 패키지 아래로 재이동

* fix: 웹소켓 디스패쳐 로깅 개선 - payload 전체 찍기 X, 에러를 사용자에게 그대로 보내기 X

* docs: 로깅에서 메시지 타입이 아닌 멤버를 찍던 오류를 수정

* [chore/#628] 쿼리 카운트 테스트 인프라 구축 (#634)

* chore: 쿼리 카운트 테스트 인프라 구축

* chore: 스모크 테스트

* chore: 테스트 정합성을 위해 배치사이즈   설정을 테스트 프로파일에 추가

* chore: 캐시로 인한 쿼리 수가 맞지 않는 문제 해결

* [refactor/#630] Bookmark 도메인 N+1 제거 (#636)

* refactor: 관련 엔티티 fetch join

* refactor: 찜한 운동 인원수 count 쿼리화

* refactor: 찜 목록 역방향 fetch join

* test: Bookmark 찜 목록 N+1 쿼리카운트 테스트 추가

* chore: 불필요한 주석 제거

* refactor: set으로 묶기

* [refactor/#638] 운동 참여 인원 수 조회 로직 공통화 (#639)

* feat: 운동 도메인에 운동 참여 멤버수 계산 서비스를 별도 구현

* refactor: 운동 도메인에서 멤버 수 계산 로직을 CountLookupService에 위임하도록 변경
이때 같은 도메인의 서비스가 lookup을 쓰는 건 공통 로직을 묶는 한 어쩔 수 없는 trade-off임

* refactor: Bookmark 도메인에서도 CountLookupService에 운동 참여 멤버 수 로직을 위임하도록 변경

* fix: 사용하지 않게 된 리포지토리 쿼리를 제거하고, N+1 체크 테스트도 반영

* refactor: 운동 북마크 조회를 운동 도메인에 두던 걸 북마크 도메인으로 변경

* [feat/#625] 채팅 unread status WebSocket 이벤트 발행 (#637)

* feat: 채팅 전송 시 발신자를 제외하고 안 읽은 메시지 업데이트 이벤트 발송

* refactor: ChatSendService의 조회 메서드를 별도 Reader로 분리

* refactor: 채팅 전송 서비스에서 파일 첨부 로직을 별도 서비스로 분리

* refactor: 채팅 전송 서비스에서 첫 메시지 판별 로직을 별도로 분리

* refactor: 채팅 전송 서비스에서 이벤트 발행 책임을 별도 서비스로 분리

* refactor: send 관련 클래스들을 별도 패키지로 묶어서 정리

* improve: 시스템 메시지에서도 안 읽은 배지 업데이트 이벤트를 발행하도록 변경

* refactor: 이벤트 리스너는 service 하위로 이동

* refactor: 메시지 읽음 상태 처리 서비스도 send/support 하위로 이동

* refactor: 보낸 메시지 자동 읽음 처리 서비스를 네이밍을 명확하게 하고 메서드 명도 변경

* feat: 채팅방 입장 시 읽음 상태가 변동되므로 이벤트를 발행하도록 구현

* refactor: 구독 시 읽음 처리 서비스의 네이밍과 메서드명을 명확화

* refactor: redis 관련 클래스를 repository 아래로 이동

* refactor: 세션 관리 책임을 별도 서비스로 분리

* refactor: 웹소켓 전송 책임을 구독 서비스 밖으로 분리

* refactor: 브로드캐스트 로직을 별도 서비스로 분리

* refactor: 안 읽음 수 업데이트 브로드캐스트 로직을 별도로 분리

* refactor: 채팅방 목록 업데이트 브로드캐스트 로직도 별도로 분리

* refactor: 구독 서비스에서 redis store를 직접 참조하지 않도록 분리

* refactor: Subscription 서비스가 이름과 맞지 않게 너무 많은 책임을 가지고 있어 각 기능을 분리하고 네이밍을 명확화

* refactor: 이벤트 리스너를 별도로 분리

* improve: 탭을 여러 개 열었을 때, 같은 세션만 웹소켓을 닫도록 세션 정보도 전달

* improve: 안읽음 상태 업데이트를 활성 사용자 대상으로만 필터링 하도록 변경

* improve: 채팅 안읽음 메시지 조회 로직을 배치 쿼리로 변경

* refactor: 직렬화 책임을 별도 Encoder로 분리

* refactor: 메시지 전송은 SessionMessageSender에서만 진행하도록 변경

* docs: 현재 Redis 일관성 수준을 best-effort로 명시, 재시도 및 보상 정책은 추후 별도 이슈로

* test: AFTER-COMMIT 이후 실제 payload가 발행되는지 체크하는 서비스 추가

* chore: 불필요한 중복된 Transactional 어노테이션을 제거

* [debug/#611] 프로필 동시성 처리 문제 해결 (#642)

* fix: ProfileImg에 memberId unique 제약 추가

* feat: 낙관적 락, 아웃박스 로직을 이용한 정합성 로직 추가

* chore: 주석수정

* test: outbox 테스트 정리

* feat: 온보딩에서 프로필 등록하는 로직에도 변경사항 추가할 수 있도록 도메인 로직으로 분리

* fix: 컨트롤러가 Executor를 이용하도록 수정

* fix: 예외 범위 축소

* chore: 중복 이미지를 gcs에서 삭제할 수 있도록 적재하는 쿼리 추가

* [refactor/#624] 채팅 읽음 처리 쿼리 배치화 (#641)

* refactor: 구독 시 unread 배치 update + 배치 read로 변경

* refactor: 구독 후 lastReadMesageId 처리도 배치 쿼리로 변경

* refactor: 메시지 전송 시 자동 읽음 처리에서 활성 사용자의 lastReadMessageId 업데이트도 배치 쿼리로 변경

* refactor: 구독자 자동 읽음 서비스에서 메서드 추출을 통해 로직이 보이도록 변경

* refactor: 다른 클래스에서 참조하는 record를 클래수 내부 record에서 별도로 분리

* refactor: 읽음 상태 처리 repository 의존을 직접하는 대신 support 패키지의 클래스를 이용하도록 변경

* fix: 채팅 배치 읽음 처리에서 IN절이 너무 길어지는 것을 방지하여 500개 기준으로 CHUNK를 분리하도록 개선

* test: 배치 읽음 처리 및 count 로직을 리포지토리 단위 테스트로 검증

* fix: bulk 쿼리에서 제대로 처리되는지를 log로 검증

* fix: 마지막 메시지 Id를 stream.max()로 명확화

* refactor: 조회한 결과가 Id가 중간에 비어있을 수 있음을 메서드로 명시

* docs: 채팅방 멤버 테이블은 메시지 읽음 처리마다 updated_at 칼럼이 바뀔경우 부하가 될 수 있으므로 bulk 처리에서 배제하고 이를 명시

* fix: 채팅 멤버 읽음 상태 업데이트 클래스도 chunk 처리를 하도록 개선

* [refactor/#632] 안 읽은 알림 조회 최적화 (#645)

* [refactor/#631] 메달 개수 쿼리 최적화 (#644)

* refactor: 메달 개수 쿼리를 1개로 최적화

* chore: 주석 수정

* chore: 컨버터 롤백

* [chore/#582] 부하테스트용 FCM 인위적 지연 주입 (#652)

* chore: 부하테스트용 FCM 인위적 지연 주입

* chore: fcm지연 주입 추가

* chore: FCM 지연주입 값을 env(GitHub Variable)로 토글 가능하게 배관

* [feat/#647] 로깅 인프라 구축 (#649)

* feat: MDC 필터 추가 및 JWT 필터에서 MEMBER_ID 추가 및 삭제 로직 추가

* feat: 비동기 스레드의 MDC 전파를 위해 설정 및 TaskDecorator 추가

* chore: Logback 기반 콘솔 및 파일 로그 개선

* chore: 콘솔 로그에는 색상을 추가하여 가시성 개선

* chore: 로그 I/O를 비동기로 하도록 변경

* chore: 에러 로그는 별도로 중복 저장하여 운영 편리성 향상

* feat: 웹소켓에도 MDC를 별도로 적용

* chore: 도커 컴포즈 volume 설정으로 log 추가

* chore: local, staging, prod를 제외하고는 색상을 없애 xml 생성 오류 해결

* docs: 카카오 Authorization code를 로그에서 제거하여 보안 이슈 해결

* chore: 에러 로그에서는 ThresholdFilter를 통해 Error 로그만 받도록 변경

* chore: Error 제외 Appender는 block 되지 않도록 하고, 로그 레벨을 debug로 낮춤

* chore: 누락된 HTTP 메소드, uri, clientIp도 로깅하도록 변경

* test: MDC 로그 테스트 검증을 중복해서 하지 않도록 변경

* chore: 불필요한 줄바꿈 제거

* chore: 토큰 없는 요청의 경우 서버 에러가 인증 에러로 잘못 변환될 수 있으므로 별도 try-catch로 분리

* chore: Ai로 인해 줄바꿈이 잘못 변경된 걸 해결

* [refactor/#633] 회원 프로필 조회 최적화 (#646)

* [refactor/#582] FCM과 채팅 스레드풀 분리 (#653)

* feat: MDC 필터 추가 및 JWT 필터에서 MEMBER_ID 추가 및 삭제 로직 추가

* feat: 비동기 스레드의 MDC 전파를 위해 설정 및 TaskDecorator 추가

* refactor: 채팅과 fcm 스레드풀 분리

* fix: 포화로 거부된 작업은  로그만 찍도록 수정

---------

Co-authored-by: Dimo-2562 <chosehoon2@naver.com>

* [refactor/#650] JWT 토큰 무효화 체계 및 RT 재사용 탐지 도입 (#651)

* feat: tokenVersion 인프라 구축

* refactor: 인증 필터 tokenVersion 검증 전환 및 DB 조회 제거

* feat: 재사용 탐지 로직 추가

* fix: JWT claim에 type 추가

* fix: redis를 캐시로 사용하도록 수정

* fix: AT 무효화 검증 제거

* refactor: lua 스크립트를 이용해 동시성 이슈 방지

* test: 테스트 보강

* [feat/#654] Staging 계층 모니터링(OTLP) 도입  (#655)

* feat: grafana 세팅

* chore: 부하테스트 결과 파일 추적 제외

* [refactor/#656] 도메인 값 SSOT 외부화 (#657)

* refactor: 도메인값 SSOT 외부화

* refactor: terraform 도메인 변수화

* refactor: env 배선

* refactor: WS 포함

---------

Co-authored-by: Dmori <83327857+Dimo-2562@users.noreply.github.com>
Co-authored-by: Dimo-2562 <chosehoon2@naver.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🛠️ FEAT This issue or pull request already exists

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] 로깅 인프라 구축

2 participants