[영상후기][10분 테코톡] 아마란스의 로깅

박철현·2025년 6월 17일

영상후기

목록 보기
161/161

movie

목차

  • 로깅이란?
  • Logback 구성요소
  • 로그 출력하기
  • 설정 파일 작성하기

로깅이란?

  • 로그를 기록하도록 시스템을 구성하는 작업

    • 로그 : 시스템이 동작할 때 시간 경과에 따라 기록된 시스템의 상태, 동작 정보
  • 목적

    • 시스템의 오류 추적 : 문제의 원인 파악
    • 정보 수집
      • 시스템의 성능 측정을 위한 통계 자료 수집
      • 실제 서비스 이용률 분석을 위한 로그 수집
  • println : 로깅의 일종

    • 동기적 실행으로 인한 성능 저하 유발, 관리의 번거로움, 정보 제공의 편의성 떨어짐 으로 인해 실무에서 사용되지 않고 있는 방법

    • 추가

      • 동기 로깅 특징

        • 즉시 실행
          • 호출한 코드 라인에서 곧바로 콘솔에 문자열 기록
        • 블로킹
          • 로그를 쓰는 동안 해당 쓰레드는 기다려야 함
            • 콘솔 IO 느려지거나 파일 직접 쓰는 System.out 느려지면 코드 실행 지연
        • 관리 설정 기능 부족
          • 로그 레벨(INFO, WARN, ERROR 등) 설정, 형식(pattern) 지정, 파일 분할(rolling), 필터링 등 거의 불가
      • 비동기 로깅(Logback + AsyncAppender)

        • Logback 자체는 기본적으로 동기방식이지만 AsyncAppender 등 붙이면 비동기 동작 설계 가능

        • 큐에 기록 요청만 넣음

          • 애플리케이션 코드는 로그 메시지를 버퍼에 던짐
          • 블로킹 거의 없음
        • 백그라운드 쓰레드가 실제 출력

          • 로깅 전담 쓰레드가 비동기 기록
        • 성능, 안정성 장점

          • 메인 로직 지연 최소화
          • 유연한 설정(로그레벨, 패턴, 출력 대상 등)
          • 롤링, 압축, 보관 정책 등
  • Java 로깅 라이브러리(logback) 이용

Logback 구성 요소

  • Appender, Encoder, Logger 3가지로 구성됨

Appender

  • 로그 메세지가 출력될 대상 결정
  • Logback에서 제공하고 있는 Appender를 통해 Console, File, Mail 등 원하는 곳 로그 출력 가능
    • ConsoleAppender : 콘솔에 출력
    • FileAppender : 파일에 출력
    • SMTPAppender : 메일로 출력(전송)
    • DBAppender : DB에 출력(저장)

  • 예시 : DBAppender 정의됨
  • Logger가 DBAppender를 참고해서 DB에 로그를 출력하는 모습

Encoder

  • 로그 메세지를 사용자가 정의한 포맷으로 변환시켜주는 요소
    • Encoder에 정의되어있는 패턴에 맞춰 메시지 변환된 뒤 로그로 출력
    • Appender 내부 포함된 요소

"이것은 디버그 로그다" 문구를 형식에 맞게 출력하는 예제 (색깔)

Logger

  • 실제 로깅 수행, 패키지별 로거 설정 가능
    • Appender 설명에서 예제는 하나의 appender를 참조하는 예제
    • 여러개의 appender를 하나의 logger에 참조하게 할 수 있음

패키지별 로거 설정 가능

  • 특정 패키지를 네임으로 설정하면 해당 패키지에서 발생하는 로그를 작성하는 로거를 정의할 수 있음
    • ex) member 패키지용 로거, comment 패키지용 로거

로그 레벨 설정 가능

  • 로그 레벨 : 로그 메세지가 나타내는 중요도

  • Logback 제공하는 Log level 5가지

    Level설명
    TRACEDEBUG 보다 훨씬 상세 정보 표시
    DEBUG프로그램을 디버깅하기 위한 정보 표시
    INFO상태 변경과 같은 정보성 로그 표시
    WARN처리 가능한 문제. 향후 시스템 에러 원인이 될 수 있는 경고성 메시지 표시
    ERROR요청을 처리하는 중 오류가 발생한 경우 표시
  • 중요도 : TRACE < DEBUG < INFO < WARN < ERROR

  • 로그 레벨을 설정할 경우 특정 레벨 이상의 로그만 출력됨

    • ex) level = INFO => INFO, WARN, ERROR만 출력

Filter

  • Appender 내부 포함, 필수 구성요소는 아님
  • Level Filter를 사용하여 해당 레벨 로그만 출력 가능
    • ex) ACCEPT Debug => Debug 요소만 출력


로그 출력하기

  • Spring Boot는 기본적으로 Logback 사용하도록 설계

    • 시스템을 구동시켰을 때 볼 수 있는 로그들 역시 로그백으로 출력이 된 로그들
  • 사용자 생성 로그를 직접 출력 가능

    • Logger 객체 정의
    • logger 객체가 가지고 있는 메서드 호출
@RestController
@RequiredArgsConstructor
public class WebController {
	private final WebService racingService;
    
@GetMapping
public void log() {
	// 1. 로거 객체 정의
	Logger logger = LoggerFactory.getLogger(WebController.class);
    // 2. 메서드 호출
    logger.info("info 로깅이야!!!");
}
  • @Slf4j 어노테이션 사용 시 Logger 정의를 자동으로 해줌
@Slf4j
@RestController
@RequiredArgsConstructor
public class WebController {
	private final WebService racingService;
    
@GetMapping
public void log() {
    // 로거 정의를 자동으로 해주기 때문에 메소드만 호출하면 됨
    log.trace("trace 로깅이야!!!");
    log.debug("debug 로깅이야!!!");
    log.info("info 로깅이야!!!");
    log.warn("warn 로깅이야!!!");
    log.error("error 로깅이야!!!");
}
  • 스프링 부트 기본 로그 레벨 설정 INFO

    • 별도 설정하지 않는 이상 기본적으로 trace, debug 레벨은 출력 안됨
  • 로그레벨 설정, Appender 및 Filter 적용 위해서는 logback-spring.xml 설정 파일 작성 필요

    • /resources/logback-spring.xml

설정 파일 작성하기

Console 출력

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">
    <!-- Appender : ConsoleAppender -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- Encoder : PatternLayoutEncoder -->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 출력하고자 하는 로그의 패턴 지정 -->
            <pattern>[%d{yyyy-MM-dd HH:mm:ss}:%-3relative] %-5level ${PID:-} --- [%15.15thread] %-40.40logger{36} :</pattern>
        </encoder>
    </appender>

    <!-- 로거의 일종으로 로그 중 최상위 계층의 로그(모든 경로에서 발생하는 로드 루트 로거 출력) -->
    <!-- STDOUT 이라는 이름의 Appender를 Root Logger에서 참조하고 있는 형식 -->
    <!-- Root Level을 WARN으로 지정했기에 WARN과 Error 로그만 출력 -->
    <root level="WARN">
        <appender-ref ref="STDOUT" />
    </root>

</configuration>
  • WARN과 Error 로그만 출력

Appender에 Filter 적용

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">
    <!-- Appender : ConsoleAppender -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- filter 추가 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!-- WARN만 허가하고 나머지 거부하는 설정 -->
            <level>WARN</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>

        <!-- Encoder : PatternLayoutEncoder -->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 출력하고자 하는 로그의 패턴 지정 -->
            <pattern>[%d{yyyy-MM-dd HH:mm:ss}:%-3relative] %-5level ${PID:-} --- [%15.15thread] %-40.40logger{36} :</pattern>
        </encoder>
    </appender>

    <!-- 로거의 일종으로 로그 중 최상위 계층의 로그(모든 경로에서 발생하는 로드 루트 로거 출력) -->
    <!-- STDOUT 이라는 이름의 Appender를 Root Logger에서 참조하고 있는 형식 -->
    <!-- Root Level을 WARN으로 지정했기에 WARN과 Error 로그만 출력 -->
    <root level="WARN">
        <appender-ref ref="STDOUT" />
    </root>

</configuration>
  • WARN 로그만 출력됨

파일 출력

파일 출력 부분만

 <!-- RollingFileAppender : 특정 기준으로 로그를 작성하는 타깃 파일을 변경해주는 Appender -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
        <!-- Encoder : PatternLayoutEncoder -->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 출력하고자 하는 로그의 패턴 지정 -->
            <pattern>[%d{yyyy-MM-dd HH:mm:ss}:%-3relative] %-5level ${PID:-} --- [%15.15thread] %-40.40logger{36} :</pattern>
        </encoder>
        <!-- 타깃을 변경하는 기준 rollingPolicy -->
        <!-- TimeBasedRollingPolicy를 사용하여 일정 주기로 새로운 파일 생성 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 생성한 로그 파일의 이름 정의, "%d" 는 로그 파일 주기설정 => 현재 매일 생성 -->
            <fileNamePAttern>${LOGS_ABSOLUTE_PATH}/logFile_%d{yyyy-MM-dd}.log</fileNamePAttern>
            <maxHistory>30</maxHistory>
            <totalSizeCap>3GB</totalSizeCap>
        </rollingPolicy>
    </appender>

    <!-- racingcar 이름의 logger 정의, INFO 레벨 가짐 -->
    <!-- logfile에는 racingcar package 내부에서 발생하는 로그만 출력됨 -->
    <logger name="racingcar" level="INFO">
        <appender-ref ref="FILE" />
    </logger>

전체 부분

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">
    <!-- Appender : ConsoleAppender -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- filter 추가 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!-- WARN만 허가하고 나머지 거부하는 설정 -->
            <level>WARN</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>

        <!-- Encoder : PatternLayoutEncoder -->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 출력하고자 하는 로그의 패턴 지정 -->
            <pattern>[%d{yyyy-MM-dd HH:mm:ss}:%-3relative] %-5level ${PID:-} --- [%15.15thread] %-40.40logger{36} :</pattern>
        </encoder>
    </appender>

    <!-- RollingFileAppender : 특정 기준으로 로그를 작성하는 타깃 파일을 변경해주는 Appender -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
        <!-- Encoder : PatternLayoutEncoder -->
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 출력하고자 하는 로그의 패턴 지정 -->
            <pattern>[%d{yyyy-MM-dd HH:mm:ss}:%-3relative] %-5level ${PID:-} --- [%15.15thread] %-40.40logger{36} :</pattern>
        </encoder>
        <!-- 타깃을 변경하는 기준 rollingPolicy -->
        <!-- TimeBasedRollingPolicy를 사용하여 일정 주기로 새로운 파일 생성 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 생성한 로그 파일의 이름 정의, "%d" 는 로그 파일 주기설정 => 현재 매일 생성 -->
            <fileNamePAttern>${LOGS_ABSOLUTE_PATH}/logFile_%d{yyyy-MM-dd}.log</fileNamePAttern>
            <maxHistory>30</maxHistory>
            <totalSizeCap>3GB</totalSizeCap>
        </rollingPolicy>
    </appender>

    <!-- 로거의 일종으로 로그 중 최상위 계층의 로그(모든 경로에서 발생하는 로드 루트 로거 출력) -->
    <!-- STDOUT 이라는 이름의 Appender를 Root Logger에서 참조하고 있는 형식 -->
    <!-- Root Level을 WARN으로 지정했기에 WARN과 Error 로그만 출력 -->
    <root level="WARN">
        <appender-ref ref="STDOUT" />
    </root>

    <!-- racingcar 이름의 logger 정의, INFO 레벨 가짐 -->
    <!-- logfile에는 racingcar package 내부에서 발생하는 로그만 출력됨 -->
    <logger name="racingcar" level="INFO">
        <appender-ref ref="FILE" />
    </logger>

</configuration>
  • <logger name="racingcar" …> 에서 name 속성은 로그 카테고리를 지정하는 부분

    • 패키지 경로나 클래스명(fully-qualified name)을 넣습니다.
      • name="com.example.myapp.service" 로 설정하면, 그 패키지(및 하위 패키지)에 속한 클래스들이 생성하는 로그만 이 로거에 매핑됩니다.
      • name="racingcar" 처럼 패키지의 최상위 부분만 지정해도, 실제 클래스 로거 이름이 racingcar.TrainService 같은 식으로 racingcar. 로 시작하면 모두 포함됩니다.
  • RollingFileAppender는 기본적으로 append="true"로 동작

    • 현재 설정된 fileNamePattern으로 생성된 파일명이 변하지 않은(같은 날짜, 시간 주기 내) 상태라면 기존 파일 끝에 계속해서 새로은 로그의 row가 추가됨
  • <rollingPolicy> 내부 태그 설명

    • <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      • 분기 기준 : 주로 날짜(%d), 시간(%d{HH}) 단위로 새 파일을 만들때 유용합니다.
  • <<fileNamePattern>…</fileNamePattern>

    • 분리된 로그 파일의 이름 어떤 형식으로 생성할지 패턴
      • ${..} : 환경변수나 시스템 프로퍼티 치환
      • %d{..} : 날짜 포맷
  • <maxHistory>30</maxHistory>

    • 과거 로그 파일의 최대 개수 또는 일수 지정
      • 개수로 지정하려면 FixedWindowRollingPolicy + SizeBasedTriggeringPolicy 정책 클래스를 사용해야 함
    • 최근 30일
  • <totalSizeCap>3GB</totalSizeCap>

    • 모든 로그 파일의 총 용량 상한 설정
    • 합계 3GB 넘으면 가장 오래된 파일부터 삭제

부록

부록 1 : 커스터마이징 Appender, Filter 생성 가능

  • Appender, Filter는 Logback 내부에서 추상화된 객체로 존재
    • 인터페이스 또는 추상클래스로 존재
    • 커스텀 Appender, Filter 구현체를 커스터마이징 할 수 있음
      • (예시1) 특정 단어가 포함된 로그만을 필터링하는 Filter
      • (예시2) 로그 이벤트 발생 시 슬랙 웹 훅으로 메시지를 전송하는 Appender

부록 2 : 로깅 전략

profile 설정

spring
  profiles
    active: dev
  • 지정해준 프로필 대로 Logger 다르게 지정 가능

logback-spring.xml 내 다르게

<springProfile name="dev">
<logger name="racingcar" level="DEBUG">
  <appender-ref ref="ASYNC_SLACK_APPENDER" />
</logger>
</springProfile>
  • Profile마다 로깅 전략을 다르게 설정할 수 있음

  • yml 파일에서 로그레벨 설정 가능
  • 복잡한 세부 설정은 xml 파일 필요
profile
비슷한 어려움을 겪는 누군가에게 도움이 되길

0개의 댓글