본문 바로가기

CS 스터디/로그

로깅(Logging)

로깅(Logging)

- 프로그램 동작시 발생하는 모든 일을 기록하는 행위 (서비스 동작 상태, 장애(exception, error))

- 서비스 동작 상태

    - 시스템 로딩

    - HTTP 통신

    - 트랜젝션

    - DB 요청

    - 의도를 가진 Exception 

    - ....

- 장애(exception, error)

    - I/O Exception

    - NullPointException

    - 의도하지 않은 Exception

- 클라이언트는 서버에 수 많은 요청을 보내고, 서버는 그에 대한 응답을 해줌

 

로그를 남기는 이유

- 서버나 프록시의 문제를 찾거나 웹 사이트 접근 및 성능 통계를 내기 위함

- 로깅을 통해 나온 통계는 마케팅 장비 조달 계획 등을 세우는데 유용

- 운영 중인 웹 애플리케이션에서 문제가 발생했을 경우, 문제의 원인을 파악하기 위해 당시의 정보가 필요

- 위 정보를 얻기 위해서는 중요 기능 실행 부분 혹은 Exception 발생 부분에서 로그를 남겨야 함

- 정보를 제공하는 일련의 기록인 로그(Log)를 생성하도록 시스템을 작성해야 함

 

 

로그 출력 방법

1. System.out.println()

2. 로깅(Logging) 라이브러리

 

1. System.out.println()

- Java를 접했을 때, 익숙한 출력 방식

- 하지만 위 방식은 시스템을 운영하는데에 있어서 적절하지 않음

1) 성능상의 문제: 속도가 매우 느림

2) 최소한의 정보가 없음: 날짜/시간/타입(error, ingo, debug,,) 등과 같은 정보가 없음

3) 콘솔창에 출력만 하기 때문에 다시 확인 불가

4) 데이터를 쌓고 남기기 힘듬

 

2. 로깅(Logging) 라이브러리

- 최소한의 정보(날짜/시간/타입) 등을 제공

- 출력 형식 지정 가능

- 로그 레벨에 따라 남기고 싶은 로그를 별도로 지정 가능

- 콘솔 뿐만 아니라 파일이나, 네트워크 등 로그를 별도 위치에 저장 가능

1) Java.util.logging: JDK1.4 부터 포함된 표준 로깅 API -> 기능 부족

2) Apache Commons logging: 아파치 재단의 Commons 라이브러리 중에 로그 출력을 제공하는 라이브러리

3) Log4j: 가장 오래된 로깅 프레임워크, 2015년 기준 개발 중단

4) Logback: log4j 이후 출시된 로깅 프레임워크, logback은 Springboot의 spring-boot-start-web안에 spring-boot-starter-logging의 logback이 포함되어 있음

5) Log4j2: 가장 최근 등장, Logback와 같은 기능

 

SLF4J

- Simple Logging Facade For Java의 약자, logger의 추상체

- logback이나 log4j와 같은 프레임워크의 인터페이스 역할

- 단독으로 사용 불가능 -> 최종 사용자가 배포시 원하는 구현체를 선택

- 최종 사용자가 배포시 원하는 로깅 프레임 워크를 결정하고 사용해도 slf4j가 인터페이스화 되어 있기 때문에, slf4j를 의존하는 클라이언트 코드에서는 실제 구현을 몰라도 상관 없음 -> 의존 관계 역전 법칙

 

SLF4J 동작 과정

- 개발할 때, SLF4J API를 사용하여 로깅 코드 작성

- 배포할 때, 바인딩된 Logging Framework가 실제 로깅 코드를 수행

- slf4j에서 제공하는 3가지 모듈

 

1. SLF4J Bridging Modules

- 다른 로깅 API로의 Logger 호출을 SLF4J 인터페이스로 연결하여 SLF4J API가 대신 처리할 수 있도록 일종의 어댑터 역할

- 아직 변경되지 않은 이전의 레거시 로깅 프레임워크를 위한 라이브러리

- Bridge는 여러 개를 사용해도 상관 없지만, 사용시 주의점은 Bridge와 Binder에 같은 종류의 프레임워크를 사용하면 안됨

 

2. SLF4J API

- 로깅에 대한 추상 레이어(인터페이스) 제공

- 추상 클래스이기 때문에 이 모듈만 단독적으로 쓰일 수 없음

- 하나의 API 모듈에 하나의 Binding 모듈

 

3. Binding

- SLF4J API를 로깅 구현체(Logging Framework)와 연결

- SLF4J API를 구현한 클래스에서 Binding으로 연결될 Logger의 API를 호출

- 하나의 API 모듈에 하나의 Binding 모듈

 

Logback

- SLF4J의 구현체

- Log4J를 토대로 만든 프레임워크

 

Logback 구조

 

1. logback-core

- 다른 두 모듈을 위한 기반 역할을 하는 모듈

- Appender와 Layout 인터페이스가 이 모듈에 속함

 

2. logback-classic

- logback-core를 가지며 SLF4J API를 구현

- logback-classic에 포함된 라이브러리들은 해당 artifact의 올바른 버전 사용이 필요, 모두 명시적으로 선언하는 것이 좋음

-> 이걸 사용할 때는 exclude를 해주는 것이 좋음

- Logger 클래스가 이 모듈에 속함

 

3. logback-access

- Servlet Container와 통합되어 HTTP 액세스에 대한 로깅 기능을 제공

- 웹 애플리케이션 레벨이 아닌 컨테이너 레벨에서 설치되어야 함

 

 

Logback 설정 요소

1. Logger

어떻게 기록할까?

- 실제 로깅을 수행하는 구성요소

- 출력 레벨 조정 (TRACE < DEBUF< INFO< WARN< ERROR)

 

2. Appender

어디에 기록할까?

- 로그 이벤트를 쓰는 작업을 수행

- 로그 메시지가 출력할 대상 결정

ex) ConsoleAppender

ex) FileAppender

ex) RolloingFileAppender

 

3. Layout

어떻게 출력할까?

- 로그 이벤트를 바이트 배열로 변환 후, 해당 바이트 배열을 OutputStream에 쓰는 작업

- Encode(Layout)

- Appender에 포함

- 사용자가 지정한 형식으로 표현될 로그 메시지를 변환하는 역할

- FileAppender와 하위 클래스는  더이상 layout을 필요로 하지 않기 때문에, layout을 사용하지 않음 -> 현재 encoder를 사용

 

SLF4J & Logback 참고링크

https://www.youtube.com/watch?v=1MD5xbwznlI&t=568s

 

Log Level

- 로그 레벨은 6단계 존재

(범위 넓음) TRACE > DEBUG > INFO > WARN > ERROR > FATAL (범위 좁음)

 

FATAL

- 매우 심각한 에러

- 프로그램이 종료되는 경우가 많음 -> 잘 작성하지 않음

 

ERROR

- 의도하지 않은 에러가 발생한 경우

- 프로그램이 종료되지는 않음

- 요청 처리중 문제가 발생한 오류 정보

- 주로 외부 API 요청에 에러가 발생한 경우 -> 예상/의도하지 않은 오류를 핸들링하는 시점에 사용

- 로그 확인 시, ERROR 위주로 확인한다면 의도하지 않은 경우만 존재하기 때문에 빠르게 장애 원인 파악 가능

 

WARN

- 에러가 될 수 있는 잠재적 가능성이 있는 경우

- 경고성 메시지

- 알람을 통해 개발자가 크리티컬한 에러를 맞닥뜨리기 전 해결 가능

- INFO 레벨로 대체 가능

 

INFO

- 명확한 의도가 있는 에러, ERROR와 반대

- 요구사항에 따라 시스템 동작을 보여줄 경우

- 진행상황 같은 일반 정보

- 상태 변경과 같은 정보성 메시지

 

DEBUG

- INFO 레벨보다 더 자세한 정보가 필요한 경우

- 디버깅하는데 유용한 세분화된 정보

- 개발 도중 확인을 위해 필ㅇ료한 모든 로그들이 해당하는 레벨

- Develop 환경

 

TRACE

- DEBUG 레벨보다 더 자세함

- Develop 환경에서 버그를 해결하기 위해 사용

- 개발시 필요하고 DEBUG로 대체 가능

- 최종 프로덕션이나 커밋에 포함되면 안됨

 

EX)

회원가입 시, DB에 동일한 email을 가진 회원이 있을 때

DuplicationException을 던진다면, 이 이벤트의 로그는 어떤 레벨 적용?

-> INFO

-> 개발자가 의도한 에러

 

EX) 요청사항

- 테스트, 개발 환경에서는 INFO 레벨 로그를 Console에 출력

- 프로덕션 환경에서는 INFO, WARN, ERROR 레벨 별 로그를 파일로 남기기

 

로깅 vs 디버깅

- 프로그래밍의 절반은 디버깅

- 디버깅을 할 수 없는 상황에서 로깅이 최선의 선택 ex) 실 서버 구동중

- 디버깅을 쓸 수 있다면 디버깅 최대한 활용

 

 

로그 작성 시, 주의사항

1) 로그파일/DB 생명주기 & 저장소 용량

2) 개인 정보

3) 시스템 주요 정보(시스템 보안, 계정 정보)

- 로그가 저장되는 저장소의 용량, 파일 혹은 DB라도 삭제는 언제할 것인지

-> 이러한 계획을 명확히 수립하고 운영해야 디스크 용량 부족 및 갑작스러운 장애 방지 가능

- 로그에 개인정보, 시스템 계정 정보가 작성되는 경우가 존재하기 때문에 주의 요망

 

 

로깅 필드

- 모든 HTTP 트랜잭션의 헤더를 로그로 남기면, 감당하기 힘든 양의 데이터를 관리해야 함

- 트랜잭션의 기본 항목만 로깅

1) HTTP 메서드

2) 클라이언트와 서버의 HTTP 버전

3) 요청받은 리소스의 URL

4) 응답의 HTTP 상태 코드

5) 요청과 응답 메시지의 크기

6) 트랜잭션이 일어난 시간

7) Referer와 User-Agent 헤더 값

 

- HTTP 메서드 + URL을 통해서 어떤 요청이 어떤 일을 진행하려 했는지 확인 가능

- URL은 특정 페이지가 얼마나 많이 조회되었는지 통계내어 유용한 정보 확인 가능

- 버전 정보는 클라이언트와 서버 간에 문제가 생겼을 떄 디버깅하는데 도움

- HTTP 상태 코드는 요청이 성공적으로 이뤄졌는지, 인증 시도가 실패했는지, 리소스를 찾았는지 등 요청에 대해 어떤 응답이 발생했는지 확인 가능