로그의 중요성
아래는 우리가 스프링부트를 실행하면 흔히 볼 수 있는 것이다.
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.5.2)
2024-01-28 22:19:06.122 INFO 11216 --- [ main] c.s.t.TourApiProjectApplication : Starting TourApiProjectApplication using Java 11.0.19 on DESKTOP-M0JUU87 with PID 11216
2024-01-28 22:19:06.125 INFO 11216 --- [ main] c.s.t.TourApiProjectApplication : The following profiles are active: local,localdb,common,security
2024-01-28 22:19:07.359 INFO 11216 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2024-01-28 22:19:07.683 INFO 11216 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 316 ms. Found 33 JPA repository interfaces.
2024-01-28 22:19:07.868 WARN 11216 --- [ main] o.m.s.mapper.ClassPathMapperScanner : No MyBatis mapper was found in '[com.server.tourApiProject]' package. Please check your configuration.
...
위와 같이 로그는 프로그램이 실행될 때 발생하는 이벤트를 추적할 수 있도록 프로그램 실행 기록을 남기는 것으로, 개발 및 운영에 꼭 필요한 요소이다.
기존의 별 헤는 밤을 개발하면서 로그를 보기만 했지 커스텀하거나 저장하지 않았는데, 점점 어플이 커지고 운영의 효율을 위해 로그 시스템을 개선해 보기로 하였다.
SLF4J
로그 라이브러리에는 java.util.logging, Apache Commons logging, Log4j, Logback 등 다양한 종류가 있다.
SLF4J는 Simple Logging Facade for Java의 약자로 라이브러리 인터페이스 역할을 하며, 여러 라이브러리들을 하나의 통일된 방식으로 사용할 수 있는 방법을 제공한다.
SLF4J 을 사용하기 위해서는 아래 dependency를 추가하고,
dependencies {
implementation 'ch.qos.logback:logback-classic:1.4.1'
implementation 'org.slf4j:slf4j-api:2.0.3'
}
build.gradle
아래와 같이 사용하면 된다.
private static final Logger LOG = LoggerFactory.getLogger(TestService.class);
logger.debug("Hello world!");
하지만 lombok 라이브러리를 사용한다면 @Slf4j 어노테이션으로 간단하게 사용할 수 있으니 lombok을 사용하도록 하자
dependencies {
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
}
build.gradle
@Slf4j
public class TestService {
log.info("Hello world!");
}
이 글에서는 slf4j 인터페이스 중 Logback을 사용할 것이기 때문에 Logback 사용 방법에 대해 알아보자.
사전 지식
- 로그 레벨 Level 설명
error 예상하지 못한 심각한 문제가 발생하는 경우, 즉시 조치를 취해야 할 수준의 레벨 warn 로직 상 유효성 확인, 예상 가능한 문제로 인한 예외 처리, 당장 서비스 운영에는 영향이 없지만 주의해야 할 부분 info 운영에 참고할만한 사항, 중요한 비즈니스 프로세스가 완료됨 debug 개발 단계에서 사용하며, SQL 로깅을 할 수 있음 trace 모든 레벨에 대한 로깅이 추적되므로 개발 단계에서 사용함 - 로그 패턴
- %logger : 패키지 포함 클래스 정보
- %logger{0} : 패키지를 제외한 클래스 이름만 출력
- %logger{length} : Logger name을 축약할 수 있음. {length}는 최대 자리 수, ex)logger{35}
- %-5level : 로그 레벨, -5는 출력의 고정폭 값(5글자), 로깅레벨이i nfo일 경우 빈칸 하나 추가
- ${PID:-} : 프로세스 아이디
- %d : 로그 기록시간 출력
- %p : 로깅 레벨 출력
- %F : 로깅이 발생한 프로그램 파일명 출력
- %M : 로깅이 발생한 메소드의 이름 출력
- %line : 로깅이 발생한 호출지의 라인
- %L : 로깅이 발생한 호출지의 라인
- %thread : 현재 Thread 명
- %t : 로깅이 발생한 Thread 명
- %c : 로깅이 발생한 카테고리
- %C : 로깅이 발생한 클래스 명 (%C{2}는 somePackage.SomeClass 가 출력됨)
- %msg : 로그 메시지 (=%message)
- %n : 줄바꿈(new line)
- %% : %를 출력
- %r : 애플리케이션 시작 이후부터 로깅이 발생한 시점까지의 시간(ms)
- %d{yyyy-MM-dd-HH:mm:ss:sss} : %d는 date를 의미하며 중괄호에 들어간 문자열은 dateformat을 의미. 따라서 [2021-07-12 12:42:78]과 같은 날짜가 로그에 출력됨.
- %-4relative : %relative는 초 아래 단위 시간(밀리초)을 나타냄. 4를하면 4칸의 출력폼을 고정으로 가지고 출력. 따라서 숫자에 따라 [2021-07-12 12:42:78:232] 혹은 [2021-07-12 12:42:78:2332]와 같이 표현됨
- %magenta() : 괄호 안에 포함된 출력의 색상을 마젠타색으로 설정합니다.
- highlight() : 로깅 레벨에 따라 괄호 안에 포함된 출력의 색상을 설정합니다(예: ERROR = 빨간색).
logback 적용
위 로그 포맷을 사용해서 원하는 포맷으로 콘솔에 로그를 출력해 보자.
설정 파일 이름은 logback-spring.xml, 위치는 src/main/resources 에 위치하도록 한다.
다음은 logback의 3가지 주요 설정이다.
- Appender : 어디에 출력할지에 대해 기술
- ConsoleAppender : 콘솔에 로그를 어떤 포맷으로 남길지 설정할 수 있다
- FileAppender : 파일에 로그를 어떤 포맷으로 남길지 설정할 수 있다
- RollingFileAppender : 로그의 양이 많아지면 하나의 파일로 관리하기 어렵기 때문에 하루 단위로 로그 파일을 관리할 때 설정한다.
- Logger : 로그의 주체. 로그의 메시지 전달, 특정 패키지 안의 특정 레벨 이상인 것에 대해 출력
- Layout(Encoder) : 어떻게 출력할지에 대해 기술
아래는 콘솔에 원하는 패턴으로 로그를 출력하게 하는 설정 파일이다.
참고로 root level = INFO는 Info 레벨 이상의 로그만 출력한다는 의미이다.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level [%logger{0}:%line] - %msg%n
</Pattern>
</layout>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
logback-spring.xml
실행 시, 맨 위의 콘솔 로그와 달리 원하는 포맷으로 로그가 출력되었음을 확인할 수 있다.
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.5.2)
2024-01-28 23:12:06 [background-preinit] INFO [Version:21] - HV000001: Hibernate Validator 6.2.0.Final
2024-01-28 23:12:06 [main] INFO [TourApiProjectApplication:55] - Starting TourApiProjectApplication using Java 11.0.19 on DESKTOP-M0JUU87 with PID 27800
2024-01-28 23:12:06 [main] INFO [TourApiProjectApplication:663] - The following profiles are active: local,localdb,common,security
2024-01-28 23:12:07 [main] INFO [RepositoryConfigurationDelegate:132] - Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2024-01-28 23:12:08 [main] INFO [RepositoryConfigurationDelegate:201] - Finished Spring Data repository scanning in 349 ms. Found 33 JPA repository interfaces.
...
특히 패턴 중 %line 은 로깅이 발생한 호출지의 라인을 표시해 주는데, 에러 발생 시 에러가 발생한 부분의 코드라인을 바로 확인할 수 있기에 개인적으로 매우 편한 옵션이라고 생각한다. 추천한다!
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.FileAppender">
<file>testFile.log</file>
<append>true</append>
<immediateFlush>true</immediateFlush>
<encoder>
<pattern>
%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level [%logger{0}:%line] - %msg%n
</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
logback-spring.xml
그럼 testFile.log 란 파일이 생성되고, 해당 파일에 로그가 찍힘을 확인할 수 있다.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 운영계 -->
<springProfile name="prod">
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>testFile.log</file>
<append>true</append>
<immediateFlush>true</immediateFlush>
<encoder>
<pattern>
%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level [%logger{0}:%line] - %msg%n
</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="FILE"/>
</root>
</springProfile>
<!-- 개발계 -->
<springProfile name="local">
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level [%logger{0}:%line] - %msg%n
</Pattern>
</layout>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
</springProfile>
</configuration>
마무리
이번 시간에는 로그 라이브러리 Logback을 사용하여 원하는 포맷으로 로그를 출력하고, 로그 파일을 추출하며 로깅 시스템을 개선해 보았다. 생각보다 간단한 설정만으로 가능하여 하루 정도 투자하면 편하게 로그를 볼 수 있을 것이다.
'별밤 일지 > 개발' 카테고리의 다른 글
[Springboot] Test With Mockito, JUnit (4) | 2024.03.05 |
---|---|
[Android.hardware.Sensor] 안드로이드 Sensor를 활용하여 방위각, 고도 구하기 (0) | 2024.02.20 |
[QueryDSL] queryDSL 도입기 (0) | 2024.01.28 |
[Firebase Cloud Messaging]Android FCM 적용 (2) | 2024.01.21 |
[Android] CustomView 를 활용한 효율적인 나만의 View 만들기 (0) | 2023.12.13 |