https://velog.io/@soonch6/AWS-IAM-%ED%8A%B8%EB%9F%AC%EB%B8%94%EC%8A%88%ED%8C%85 (AWS IAM 정책 - 트러블슈팅)
위 링크는 내가 비동기로 구현한 'S3 파일 삭제 기능'이 실패 했을 때의 트러블 슈팅을 작성한 것이다. 이처럼 비동기로 구현 한다면 응답은 빠를 수 있으나 실제로 서비스는 동작 하지 않을 수 있다. 이는 통합성을 해치는 문제로 따로 처리를 해야 한다.
다행이 S3 파일 같은 경우 직접 조회하여 해당 파일을 삭제 할 수 있다. 하지만 언제 어디서 문제가 어떻게 발생하는지 모르는 상황에 넉 놓고 보고 있을 수는 없다.
따라 알람기능으로 구현하고자 하였으나, 아예 로그를 찍어서 슬랙으로 개발자에게 알리도록 하는게 더욱 알맞다는 걸 알게되었고 logback과 slack webhook을 이용하여 문제를 처리하고자 한다.
logback이란?
slf4j의 구현체로써 SpringBoot의 기본 log로 사용되고 있으며 spring-boot-starter-web안에 spring-boot-starter-logging의 logback이 기본적으로 포함되어 있어서 별다른 dependency 추가 없이 사용할 수 있습니다.
log level
- Trace - 가장 상세한 로그 레벨로, 코드의 흐름을 따라가며 디버깅 정보를 기록합니다.
- Debug - 디버깅을 위한 로그 레벨로, 프로그램의 상태 및 실행 중에 발생하는 중요한 이벤트를 기록합니다.
- Info - 일반적인 정보를 기록하는 로그 레벨로, 프로그램의 주요 이벤트 및 상태 변경을 기록합니다. 에러는 아니지만 주시해야할 것
- Warning - 예외적인 상황을 기록하는 로그 레벨로, 잠재적인 문제 또는 예상치 못한 동작을 알립니다.예외상황이긴 했지만 에러는 아닌 것
- Error - 심각한 에러를 기록하는 로그 레벨로, 예외 상황 또는 잘못된 동작을 나타냅니다.에러가 맞고 대응해야할 것
- Fatal - 가장 심각한 로그 레벨로, 치명적인 오류를 기록하고 프로그램의 중단 또는 비정상 종료를 알립니다.치명적인 것
logback 구성 요소 역할
- appender: logging 이벤트 처리 역할을 담당. Appender 인터페이스를 구현해 이벤트를 처리(Logger는 logging 이벤트를 처리)
- logger: 이벤트의 대상, 어떤 내용을 log로 남길 것인지 정의하며 log level을 선택적으로 설정할 수 있음
- Layout:
- Layout은 로그 이벤트의 출력 형식을 정의합니다.
- 로그 이벤트를 어떻게 포맷할 것인지를 결정합니다.
- logback에서는 다양한 레이아웃이 제공되며, 로그 메시지의 날짜, 로그 레벨, 클래스 이름 등을 포함할 수 있습니다.
- Filter:
- Filter는 로그 이벤트를 필터링하는 역할을 합니다.
- 로그 이벤트를 받아들일지 여부를 결정하거나 이벤트를 수정하는 등의 작업을 수행합니다.
- 로그 이벤트를 일부분만 처리하거나 특정 조건에 따라 로그 이벤트를 다르게 처리하는데 사용됩니다.
- Context:
- Context는 logback의 핵심 구성 요소로, 로깅 이벤트를 관리하는 데 사용됩니다.
- 로깅 이벤트를 로거에 전달하고, 로거와 애펜더, 필터 등의 관계를 관리합니다.
- 컨텍스트는 logback의 설정 파일을 로드하고, 런타임에 로그 구성을 변경하는 데 사용됩니다.

Logback Rolling Policies 정책
- TimeBasedRollingPolicy (시간 기반)
- 일/시간 단위로 로그를 분할
- 가장 실무에서 많이 쓰는 방식
- SizeBasedTriggeringPolicy (용량 기반)
- 파일이 일정 크기를 넘으면 분할
- 보통 FixedWindowRollingPolicy와 함께 사용
- FixedWindowRollingPolicy (번호 순서 기반)
- 파일 이름에 숫자를 붙여 순서대로 롤링
- 보통 Size 기반과 함께 쓰임

그외 기타 xml 파일 구성요소
- file : 기록할 파일명과 경로를 설정한다.
- rollingPolicy class :
- ch.qos.logback.core.rolling.TimeBasedRollingPolicy => 일자별 적용
- ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP => 일자별 + 크기별 적용
- fileNamePattern : 파일 쓰기가 종료된 log 파일명의 패턴을 지정. .gz, .zip으로 자동 압축 가능
- maxFileSize :
- 한 파일당 최대 파일 용량을 지정
- log 내용 크기도 IO 성능에 영향을 미치기 때문에 최대 10MB 내외 권장
- 용량 단위는 KB, MB, GB 3가지 지정 가능
- maxHistory : 최대 파일 생성 개수
ex) maxHistory 가 30이고, Rolling 정책을 일 단위로 하면 30일동안만 저장되고, 월 단위로 하면 30개월간 저장- Filter : 해당 패키지에 반드시 로그를 찍지 않고 필터링이 필요한 경우에 사용하는 기능
추가적인 팁 - 외부 라이브러리
implementation 'net.rakugakibox.spring.boot:logback-access-spring-boot-starter:2.12.0'
Servlet Filter에 로깅을 구현하지 않고 위 라이브러리를 사용하여 HttpRequest, HttpResponse 정보를 편하게 로깅 할 수 있다.
파일 위치 : src.main.resources.logback-spring.xml

프러퍼티가 2개인 이유는 팀원이 무슨 테스트를 위해 잠시 -local을 만들었다
1) 콘솔 작성 :

(중요!) logback-spring.xml 작성하게 되면 spring boot에서 기존 콘솔을 보여주는 기능이 정지되고 logback-spring.xml에서 커스텀 콘솔을 받을 준비를 하기 때문에, 만약 콘솔을 만들지 않으면 실행할때 콘솔창에서 아무것도 안나오는 현상이 발생함.
2) 파일 작성 :

SizeBasedTriggeringPolicy(용량 기반)와 FixedWindowRollingPolicy (번호 순서 기반) 사용하여 일정 이상의 데이터가 쌓이면 다음 로그 파일을 생성하도록 구현하였다.
로그 level을 WARN 설정하고 .filter.ThresholdFilter로 필터를 설정하면 warning 와 그 보다 높은 Error, Fatal 등급의 로그를 파일에 기록한다.
공용 패턴을 하나 만들어서 추후 추가 할 slack 패턴에 사용 할 예정이다.
(콘솔에는 공용패턴을 안 쓰는 이유는 콘솔패턴에는 색을 입하는 쿼리가 들어갔는데 이게 다른 곳에서는 숫자로 나오기에 보기가 안 좋다.)
slack webhook이란?
1. 슬랙에서 새로운 채널을 생성한다.

2. 빈 채널을 만들고

3. 채널 이름을 작성

4. 채널 세부정보 보기 클릭

5. 통합 > 앱 추가

6. incoming webhooks 검색

7. slack에 추가 클릭

8. 채널 선택에서 생성한 채널 이름 찾고 '수신 웹후크 통합 앱 추가' 클릭

9. webhook가 정상적으로 작동

1. build.gradle
implementation 'com.github.maricn:logback-slack-appender:1.6.1'
2. properties 설정
slack.webhook.url=${SLACK_WEBHOOK_URL}
- slack webhook url은 인텔리제이 환경변수로 관리
3. xml 내 properties 참조
<springProperty scope="context" name="SLACK_WEBHOOK" source="slack.webhook.url" />
- slack.webhook.url의 값을 SLACK_WEBHOOK로 받아서 xml 환경변수로 사용하겠다는 뜻
4. slack 송신 logback 작성

- 슬랙 로그 등급을 2개로 나눠서 작성
- .filter.LevelFilter와 onMatch, onMismatch를 추가하여
각각 WARN, ERROR에 대해서만 작동하도록 구현
5. 로그 출력문

- root (logger) : 전체 기본 로그 출력
- (개별 ) logger : 중요한 내부 로그 + Slack 알림
- additivity=false : 중복방지, root에 file이 있을 경우 logger가 root에 설정된 Appender까지 중복 출력하지 않도록 막는다. 즉 logger에 설정된 file만 출력됨.
의도적인 에러 발생
private static final Logger slackLogger = LoggerFactory.getLogger(LogTesterRunner.class);
- LoggerFactory.getLogger()
- 로거를 생성하는 정적 팩토리 메소드
- 로깅의 주체가 되는 해당 클래스를 입력
- slackLogger
- 보통은 logger
- slack 전송용 로거를 내포하고 있음
슬랙 채널:
기존에는 로그만 찍어서 인텔리제이 콘솔창에서 확인하는 @slf4j 어노테이션과 달리
logback 기능을 이용하면 로그를 기록하고 관리하여서 개발자가 문제를 빠르게 파악하는
기초적인 모니터링 기술을 구현하게 되었다.
로깅을 커스텀하여 필요한 정보를 원하는 형태로 다듬어서 로그를 남길 수 있어서
세분화된 로그로 프로젝트를 좀 더 수월하게 관리 할 수 있었다.