[Log] Docker + logback 적용과정

hynnch2·2022년 2월 21일
2
post-thumbnail

project를 실행하던 중, backend에서 로그를 저장 할 필요성이 생겼습니다.

  1. API 호출 시 수행 시간이 얼마나 걸렸는지 확인하기 어려움. -> 현재 병목이 어느 부분에 생기는지 확인 어려움.
  2. 서비스가 갑자기 죽어도 어떤 이유인지 확인이 어려움. -> 자동 배포를 구현하는 과정에서 발생했는데, 왜 죽었는지 확인이 어려움.

어느정도 백엔드 지식이 쌓이면서 log를 저장하는 것은 기본적인 관행이라고 알고 있었지만, 어떻게 저장할지 고민하다가 logback이라는 라이브러리를 사용하게 되었습니다.


초기 구상 (DB 이용)

프로젝트 초창기에는 Docker를 사용하지 않았기 때문에, 로그를 DB에 저장하기로 했습니다.

mysql에 API log를 저장하자.

지금 생각해보면 매우 잘못된 생각이지만, 당시에는 로그에 대한 지식이 없었기 때문에 이런식으로 해결하면 괜찮을 것이라 생각했습니다.

  • API를 호출한다.
  • spring의 AOP를 이용하여 controller 호출 시간을 저장한다.
  • API 서비스를 실행한다.
  • spring AOP에서 return값과 실행시간, 그 외 정보를 저장한다.

다음과 같은 방식으로 로그를 저장하는 방법이었습니다.


문제 발생.

위의 방식은 바로 문제가 발생했습니다.

  1. return 값이 커지면 에러뜸. return 값의 크기가 얼마일지 예측하고 크기를 주기 애매함.
  2. 서버가 죽거나, controller에 문제가 생기면 저장을 할 수 없음.
  3. 매 요청마다 DB에 query가 불필요하게 날라감.

return 값은 없앨 수 있지만, 2번, 3번의 문제가 해결되지 않았습니다. 더욱이 RDMS에 저장하는 것은 메모리 부분에서도 비 효율적이며, 읽기보다 쓰기가 많은 요청에 사용하는 것은 적합하지 않다고 판단하였습니다.


다음 아이디어 (docker log)

다른 방법을 찾아보다 docker로 배포 방식을 바꾸며 docker log라는 기능이 있다는 것을 확인했습니다. docker log를 활용하면 console에 출력되는 값을 확인할 수 있다는 점을 통해 console을 통해 로그를 처리 할 수 있다는 점을 알았습니다.

이후, DB 코드를 지우고, 특정 logic 사이에 logger 라이브러리를 이용하여 로그를 출력하는 방식으로 진행했습니다.

이를 통해 얻을 수 있는 장점은

  1. DB에 불필요한 query를 줄일 수 있다.
  2. server 외적인 에러 까지 docker log에 저장된다.

그러나 여전히 단점이 존재했는데, CI/CD를 구현하며 container의 갯수가 많아지는 것을 방지하느라 컨테이너를 지속적으로 삭제하면서 로그 정보가 날라갔습니다.


현재 방식 (docker volume + logback)

다른 곳에서는 어떻게 로그를 처리하는지 알아보다 logback이라는 라이브러리를 알게 되었습니다.

🤔 Logback ?

공식 홈페이지에서 logback에 대한 설명은 다음과 같습니다.

logback은 log4j의 인기있는 후속 제품이다. logback은 다른 loggin 시스템보다 더 빠르고 더 적은 공간을 차지한다.

java에서 log를 사용할 때 slf4j를 사용하는데, logback은 내부 상태 시스템을 이용하여 log의 내부 정보를 출력할 수 있습니다. 이는 StatusManager을 이용하고, StatusPrinter class를 이용해서 명시적으로 표현 할 수 있습니다. 다음 코드를 보면,

ex)

@SpringBootApplication
public class TestmoduleApplication {

	public static void main(String[] args) {
		Logger logger = LoggerFactory.getLogger(TestmoduleApplication.class);
		logger.debug("hello test");

		LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
		StatusPrinter.print(lc);
	}
}

따로 logback-test.xml, logback.xml을 작성하지 않으면 log system이 default configuration인 "ConsoleAppender" 정책을 따르고 있다고 알려줍니다.

여기서 말하는 Appender는 출력의 destination을 지정하는 것으로, TCP, file, Socket등 다양한 Appender가 있습니다.

👍 logback의 기능!

즉 log를 이용할 때 slf4j를 사용하는데 logback을 통해 log system의 내부 정보를 알려주거나, 추가로 encoder, configuration, filter와 같은 부가적인 기능을 가능하게 하는 것이 logback 입니다.

또한 logback의 기본 기능을 요약하면,

Appender: logback이 log작성을 위임하는 구성요소. (링크)
Encoder: event를 형식에 맞게 변경. (링크)
Layout: 정규식에 맞춰서 값을 출력하는 부분. (링크)
Architecture: logback의 level 규칙. 위계질서가 있음. (링크)

이 정도만 이해해도 쉽게 logback.xml을 작성 할 수 있습니다.


(logback.xml)

appender: encoder와 출력 형태를 정함.
file: RollingFileAppender의 출력을 저장할 파일 위치 (절대 경로 입력)
logger: package단위로 어떤 정도의 log level을 지정할지 선택.

위와 같이 작성하고 배포하여 docker container내에 파일이 저장되는 것을 확인했고, 최종적으로 docker volume을 통해 호스트의 volume과 마운트하여 기록이 지워지지 않도록 구성했습니다.


+ 추가 할 내용이나 부족한 부분이 있다면, 댓글 작성 부탁드립니다! :)

profile
more than yesterday

1개의 댓글

comment-user-thumbnail
2023년 12월 26일

도커 볼륨 설정하는 내용이 없네요..

답글 달기