로깅 사용 방법

로깅 사용 방법 (How to use logging)

모든 Flink 프로세스는 해당 프로세스에서 발생하는 다양한 이벤트에 대한 메시지를 담는 로그 텍스트 파일을 생성합니다. 이러한 로그는 Flink 내부 동작에 대한 깊은 통찰을 제공하며, 문제(WARN/ERROR 메시지 형태)를 감지하고 디버깅에 도움을 줄 수 있습니다.

출처: 문서

본문

모든 Flink 프로세스는 해당 프로세스에서 발생하는 다양한 이벤트에 대한 메시지를 담는 로그 텍스트 파일을 생성합니다. 이러한 로그는 Flink 내부 동작에 대한 깊은 통찰을 제공하며, 문제(WARN/ERROR 메시지 형태)를 감지하고 디버깅에 도움을 줄 수 있습니다.

로그 파일은 WebUI의 Job-/TaskManager 페이지를 통해 접근할 수 있습니다. 사용되는 Resource Provider(예: YARN)가 접근을 위한 추가 수단을 제공할 수 있습니다.

Flink의 로깅은 SLF4J 로깅 인터페이스를 사용합니다. 이를 통해 Flink 소스 코드를 수정하지 않고도 SLF4J를 지원하는 어떤 로깅 프레임워크든 사용할 수 있습니다.

기본적으로 Log4j 2가 기본 로깅 프레임워크로 사용됩니다.

구조적 로깅 (Structured logging)

Flink는 대부분의 관련 로그 메시지의 MDC에 다음 필드를 추가합니다(실험 기능):

  • Job ID
    • key: flink-job-id
    • format: string
    • length 32

이것은 구조적 로깅 환경에서 가장 유용하며 관련 로그를 빠르게 필터링할 수 있게 합니다.

MDC는 slf4j가 로깅 백엔드로 전파하며, 로깅 백엔드는 보통 이를 로그 레코드에 자동으로 추가합니다(예: log4j2 json layout).

Log4j 2 JsonTemplateLayout

JsonTemplateLayout은 커스터마이즈 가능하고 효율적이며 가비지 없는(garbage-free) JSON 생성 레이아웃입니다. 제공된 JSON 템플릿이 설명하는 구조에 따라 LogEvents를 인코딩합니다.

필요한 jar log4j-layout-template-json은 편의를 위해 flink-dist에 번들되어 있습니다.

예시 템플릿은 Event Templates를 참고하세요.

Log4j 2 PatternLayout

또는 명시적으로 구성할 수도 있습니다 - log4j pattern layout은 다음과 같이 보일 수 있습니다:

[%-32X{flink-job-id}] %c{0} %m%n.

Log4j 2 구성 (Configuring Log4j 2)

Log4j 2는 프로퍼티 파일과 설정의 혼합으로 제어됩니다.

Log4j 2 프로퍼티 파일 (Log4j 2 property files)

Flink 배포판은 conf 디렉터리에 다음 log4j 프로퍼티 파일을 포함하며, Log4j 2가 활성화되어 있으면 자동으로 사용됩니다:

  • log4j-cli.properties: 커맨드라인 인터페이스(예: flink run, sql-client)에서 사용
  • log4j-session.properties: Kubernetes/Yarn 세션 클러스터 시작 시 커맨드라인 인터페이스에서 사용 (즉, kubernetes-session.sh/yarn-session.sh)
  • log4j-console.properties: Job-/TaskManager가 포그라운드로 실행될 때 사용 (예: Kubernetes)
  • log4j.properties: 기본적으로 Job-/TaskManager에서 사용

Log4j는 주기적으로 이 파일을 스캔하여 변경 사항을 감지하고 필요 시 로깅 동작을 조정합니다. 기본적으로 이 검사는 30초마다 발생하며, Log4j 프로퍼티 파일의 monitorInterval 설정으로 제어됩니다.

Log4j 2 구성 (Log4j 2 configuration)

다음 로깅 관련 구성 옵션을 사용할 수 있습니다:

Configuration Description Default
env.log.dir Flink 로그가 저장되는 디렉터리. 절대 경로여야 합니다. Flink 홈 아래의 log 폴더
env.log.level Root logger 레벨. INFO
env.log.max 유지할 이전 로그 파일의 최대 수. 10

Log4j 1과의 호환성 (Compatibility with Log4j 1)

Flink는 Log4j API bridge를 제공하여 Log4j1 클래스를 대상으로 동작하는 기존 애플리케이션이 계속 동작할 수 있게 합니다.

커스텀 Log4j 1 프로퍼티 파일 또는 Log4j 1에 의존하는 코드가 있다면, 공식 Log4j 호환성마이그레이션 가이드를 참고하세요.

Log4j1 구성 (Configuring Log4j1)

Log4j 1과 함께 Flink를 사용하려면 다음을 확인해야 합니다:

  • org.apache.logging.log4j:log4j-core, org.apache.logging.log4j:log4j-slf4j-impl, org.apache.logging.log4j:log4j-1.2-api가 클래스패스에 없어야 하고,
  • log4j:log4j, org.slf4j:slf4j-log4j12, org.apache.logging.log4j:log4j-to-slf4j, org.apache.logging.log4j:log4j-api가 클래스패스에 있어야 합니다.

IDE에서는 pom에 정의된 그러한 의존성을 교체하고, 전이적으로 의존하는 의존성에 제외(exclusion)를 추가해야 할 수도 있습니다.

Flink 배포판의 경우,

  • lib 디렉터리에서 log4j-core, log4j-slf4j-impl, log4j-1.2-api jar를 제거하고,
  • lib 디렉터리에 log4j, slf4j-log4j12, log4j-to-slf4j jar를 추가하고,
  • conf 디렉터리의 모든 log4j 프로퍼티 파일을 Log4j1 호환 버전으로 교체해야 합니다.

logback 구성 (Configuring logback)

logback과 함께 Flink를 사용하려면 다음을 확인해야 합니다:

  • org.apache.logging.log4j:log4j-slf4j-impl이 클래스패스에 없어야 하고,
  • ch.qos.logback:logback-corech.qos.logback:logback-classic이 클래스패스에 있어야 합니다.

IDE에서는 pom에 정의된 그러한 의존성을 교체하고, 전이적으로 의존하는 의존성에 제외를 추가해야 할 수도 있습니다.

Flink 배포판의 경우,

  • lib 디렉터리에서 log4j-slf4j-impl jar를 제거하고,
  • lib 디렉터리에 logback-core, logback-classic jar를 추가해야 합니다.

Flink 배포판은 conf 디렉터리에 다음 logback 구성 파일을 포함하며, logback이 활성화되어 있으면 자동으로 사용됩니다:

  • logback-session.properties: Kubernetes/Yarn 세션 클러스터 시작 시 커맨드라인 인터페이스에서 사용 (즉, kubernetes-session.sh/yarn-session.sh)
  • logback-console.properties: Job-/TaskManager가 포그라운드로 실행될 때 사용 (예: Kubernetes)
  • logback.xml: 기본적으로 커맨드라인 인터페이스와 Job-/TaskManager에서 사용

Logback 1.3+는 SLF4J 2를 요구하며, 현재 지원되지 않습니다.

개발자를 위한 모범 사례 (Best practices for developers)

클래스의 Class를 인자로 org.slf4j.LoggerFactory#LoggerFactory.getLogger를 호출하여 SLF4J 로거를 만들 수 있습니다.

이 로거를 private static final 필드에 저장하는 것을 강력히 권장합니다.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Foobar {
	private static final Logger LOG = LoggerFactory.getLogger(Foobar.class);

	public static void main(String[] args) {
		LOG.info("Hello world!");
	}
}

SLF4J를 가장 잘 활용하려면 플레이스홀더(placeholder) 메커니즘을 사용하는 것이 좋습니다. 플레이스홀더를 사용하면 로깅 레벨이 너무 높게 설정되어 메시지가 로깅되지 않는 경우 불필요한 문자열 구성을 피할 수 있습니다.

플레이스홀더의 문법은 다음과 같습니다:

LOG.info("This message contains {} placeholders. {}", 2, "Yippie");

플레이스홀더는 로깅될 예외와 함께 사용할 수도 있습니다.

catch(Exception exception){
	LOG.error("An {} occurred.", "error", exception);
}

더 알아보기 (Learn more)