로깅 사용 방법
로깅 사용 방법 (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
- key:
이것은 구조적 로깅 환경에서 가장 유용하며 관련 로그를 빠르게 필터링할 수 있게 합니다.
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-apijar를 제거하고,lib디렉터리에log4j,slf4j-log4j12,log4j-to-slf4jjar를 추가하고,conf디렉터리의 모든 log4j 프로퍼티 파일을 Log4j1 호환 버전으로 교체해야 합니다.
logback 구성 (Configuring logback)
logback과 함께 Flink를 사용하려면 다음을 확인해야 합니다:
org.apache.logging.log4j:log4j-slf4j-impl이 클래스패스에 없어야 하고,ch.qos.logback:logback-core와ch.qos.logback:logback-classic이 클래스패스에 있어야 합니다.
IDE에서는 pom에 정의된 그러한 의존성을 교체하고, 전이적으로 의존하는 의존성에 제외를 추가해야 할 수도 있습니다.
Flink 배포판의 경우,
lib디렉터리에서log4j-slf4j-impljar를 제거하고,lib디렉터리에logback-core,logback-classicjar를 추가해야 합니다.
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);
}