본문 바로가기
개발 관련 강의 정리/10분 테코톡

[10분 테코톡] 이스트의 로깅 정리

by 코딩개발 2023. 6. 11.
728x90
반응형

로깅의 역사

System.out.println()

System.err.println()

로깅 프레임워크들이 등장하기 전에는 println()을 사용했다.

그런데 println()을 사용하게 되면 어떤 환경에서든 똑같이 동작하게 된다는 것이 문제였다.


예시를 들어보자면 뱅킹 앱의 서버를 개발하고 운영하고 있는 개발자가 있다고 하자. 개발 환경에서는 계좌번호와 비밀번호 등등의 정보들을 로깅할 필요가 있을 것이다. 하지만 운영 환경에서도 민감한 정보들을 로깅해도 될까? 안될 것이다.

 

이런 문제들을 해결하기 위해 많은 개발팀들이 자체적인 로깅 프레임워크를 만들었고 이런 로깅 프레임워크를 배포한 팀이 있었다. 바로 log4j 이다.


log4j는 println()의 어떤 환경에서는 똑같이 동작하는 성질을 로그레벨을 통해서 해결하였다. 환경마다 다르게 로그레벨을 설정해서 개발환경에서 로깅한 정보와 운영환경에서 로깅한 정보를 구분하였다.


이맘때쯤 자카르타 프로젝트에 사용하던 로깅 프레임워크가 있었는데 jdk 1.4 배포와 함께 java.util.logging 바로 JUL 패키지가 되어 같이 배포가 되었다.

 


이 JUL은 log4j와 경쟁을 했는데 log4j는 이미 많은 사람들이 쓰고 있었고 JUL과 log4j는 로그레벨이 달랐기 때문에 매핑이 되지 않았다. 그렇기 때문에 JUL은 log4j에 비해 뒤처질 수 밖에 없었다. 그런데 이미 일부 라이브러리들은 JUL 패키지로 마이그레이션을 했고 두 프레임워크를 모두 사용한 라이브러리를 이용해서 어플리케이션을 개발하는 개발자는 이 두 프레임워크를 모두 설정해주어야 했다.

 


이런 설정의 번거로움을 줄이기 위해서 Java Commons Logging, JCL이 등장하게 된다. JCL은 동적바인딩을 통해서 런타임에 구현체를 로드하는 방법으로 여러 구현체들을 연결시켜주었다. 그런데 이런 JCL은 결국 스프링의 기본설정이 되었는데 JCL에는 치명적인 문제가 있었다.

 

 

바로 클래스 로더 이슈였다. 다중 클래스 로드 환경에서 예외가 발생하는 문제가 있었고 메모리 누수 문제도 있었다. 그리고 레거시로 남아있는 로깅 프레임워크를 그대로 사용하지 못하고 JCL로 변경해줘야 한다는 단점도 있었다. 결국에 JCL도 JUL과 log4j와 마찬가지로 같은 경쟁선상에서 놓이게 되었다.

 

 

이 무렵 log4j 메인 컨트리뷰터인 개발자가 새로운 로깅 프레임워크를 개발하기 시작했다. 그게 바로 slf4j 이다. slf4j는 정적 바인딩을 통해 동적 바인딩으로 인한 클래스 로더 이슈를 해결했다. JCL과 마찬가지로 여러 로깅 프레임워크들을 연결시켜 주었다.

 

 

그리고 브릿지라는 기능을 제공했다. 레거시로 남아있던 프레임워크들을 호출했을 때 slf4j로 리다이렉션을 시켜주어 slf4j를 이용하는 것처럼 사용할 수 있었다. 위 그림을 보면 JCL, log4j, JUL API를 호출하게 되는데 slf4j로 브릿징되어 그리고 최종적으로는 slf4j 기본 구현체인 logback으로 바인딩된 것을 볼 수 있다.

 

 

로그 레벨은 FATAL, ERROR, WARN, INFO, DEBUG, TRACE 레벨이 있다. FATAL 레벨은 어플리케이션이 꺼질 수 있는 심각한 오류를 기록할 수 있는 레벨이다. 이 상황에서는 프로그램이 정상적으로 동작하지 않기 때문에 로그 레벨이 정상적으로 기록되지 않을 확률이 있어 실제로는 잘 쓰지 않는 것이 좋다. ERROR 레벨은 어플리케이션이 계속 실행은 되지만 기능이 정상적으로 동작하지 않는 오류를 기록하는 레벨이다. 개발자가 의도하지 않는 예외를 기록하고 싶을때 이 레벨을 사용한다. WARN 레벨은 당장 피해는 없지만 잠재적으로 위험이 될 수 있는 상황에 대한 경고를 위한 로그레벨이고 INFO 레벨은 프로그램이 의도적으로 진행되고 있는지 알려주는 정보성 로그레벨이다. DEBUG 레벨은 개발 단계에서 디버깅을 위해서 사용되는데 굉장히 자세한 정보가 나타나기 때문에 운영 환경에서는 사용하지 않는 것이 좋다. TRACE 레벨은 DEBUG 레벨보다 더 자세한데 서드파티 라이브러리에서 발생한 일을 확인하는 경우에 사용할 수 있다.

 

 

TRACE 레벨이 얼마나 자세하냐면 컨트롤러에서 요청을 LISTENING 하고 있는 부분을 계속해서 메세지를 보내주는것인데 이런 메세지가 계속해서 뜨게 된다면 운영환경에서는 과부하가 걸릴수 있다. 그렇기 때문에 이런 TRACE 레벨은 절대로 운영환경에서 쓰면 안된다.


그리고 로그레벨을 설정한다면 설정한 레벨에 하위레벨은 기록되지 않는다. 예를 들어서 INFO 레벨을 설정한다고 했을 때 DEBUG와 TRACE 레벨은 기록되지 않고 INFO, WARN, ERROR, FATAL 로그레벨만 기록된다.

 

 

slf4j의 기본 구현체인 logback의 설정
Appender란 로그를 어디에 쓸 것인지를 정하는 인터페이스이다.

 

 

보통 로그를 출력한다면 콘솔이나 파일에 출력하길 원할 것이다. 그렇다면 OutputStreamAppender를 상속한 설정을 이용하면 되고 이외에도

 

 

로그를 SMTPAppender를 이용해서 로그를 메일로 보낼 수도 있고

 

 

SocketAppender를 이용해서 로그를 원격 서버로 전송할 수도 있다.

 

 

OutputStreamAppender는 ConsoleAppender와 FileAppender 그리고 FileAppender를 상속한 RollingFileAppender로 나눠져있다.

 


ConsoleAppender는 말 그대로 콘솔에 로그를 출력하겠다는 뜻이다.

 

 

target 옵션을 주면서 System.out과 System.err로 나눌 수 있고 default로는 System.out이 설정되어 있다.

 


FileAppender는 로그를 파일에 출력하겠다는 뜻이다. file 태그를 통해 어떤 파일에 기록할 것인지 설정할 수 있다. 그리고 append 옵션이 있는데 true로 주게된다면 기존 파일에 이어서 로그를 기록하겠다는 뜻이고 false 옵션을 준다면 기존 파일에 덮어씌우겠다는 설정이다.

 

 

RollingFileAppender는 어떤 특정 조건에 맞춰 각기 다른 파일에 로그를 기록하겠다는 설정이다. 이런 어떤 조건에 맞춰
새로운 파일에 기록되는 것을 롤오버라고 하는데 이런 rollingPolicy 옵션을 통해 이 롤오버에 필요한 수행동작을 지정할 수 있다.

 


현재는 TimeBaseRollingPolicy라는 옵션이 지정되어있는데 이 옵션은 fileNamePattern을 통해 언제 롤오버가 될지 지정할 수 있다. 현재는 매일매일 롤오버가 된다고 지정되어 있다. maxHistory 옵션은 보관할 로그파일의 최대 개수를 지정할 수 있다. 현재는 30개가 지정되어있는데 매일매일 롤오버가 되면서 최대 파일이 30개이기 때문에 한 달이 지난 로그파일은 삭제된다고 볼 수 있다.


이제 xml로 설정하는거 알겠지만 많이 복잡해 보인다. 그런데 자바로도 설정이 가능하다.

그렇다면 왜 예제로는 항상 xml로 설정하는 예제밖에 없을까?

 

그 이유는 바로 자동 리로딩 기능 때문이다. 설정 xml 파일의 변경을 스캔해서 자동으로 재설정해준다. 이렇게 때문에 서버를 재시작할 필요가 없어서 굉장히 유용하다.


정리

https://www.youtube.com/watch?v=1IMJCg68-lU&ab_channel=%EC%9A%B0%EC%95%84%ED%95%9C%ED%85%8C%ED%81%AC 

728x90
반응형

댓글