욱'S 노트

마이크로미터 오픈텔레메트리 트레이싱 시작하기 (Micrometer OpenTelemetry Tracing Getting Started) 본문

Programming/Micrometer

마이크로미터 오픈텔레메트리 트레이싱 시작하기 (Micrometer OpenTelemetry Tracing Getting Started)

devsun 2025. 2. 17. 11:07
반응형

마이크로미터에서 트레이싱을 위해서 지원하는 구현체는 크게 두가지가 있다. 하나는 Zipkin이고 다른 하나는 OpenTelemetry다. 둘의 차이점을 챗지피티로 알아보면 다음과 같다.

Zinkin vs OpenTelemetry

개요

 

  • Zipkin: Twitter에서 개발한 오픈소스 분산 트레이싱 시스템. 서비스 간의 요청 흐름을 추적하여 성능 문제를 분석할 수 있음.
  • OpenTelemetry: 클라우드 네이티브 컴퓨팅 재단(CNCF)에서 관리하는 오픈소스 관찰성(observability) 프레임워크로, 트레이싱뿐만 아니라 메트릭(metrics)과 로깅(logging)도 지원함.

차이점

비교 항목 Zipkin OpenTelemetry
개발 주체 Twitter (CNCF 소속) CNCF (Cloud Native Computing Foundation)
지원 범위 트레이싱 전용 트레이싱 + 메트릭 + 로그
데이터 모델 Zipkin 자체 데이터 모델 OpenTelemetry 표준 데이터 모델
수집(Instrumentation) 방식 자체 Zipkin 라이브러리 다양한 언어의 SDK 및 자동 계측 기능 지원
프로토콜 Zipkin 프로토콜 (Thrift, JSON, gRPC) OpenTelemetry Protocol (OTLP) + Zipkin, Jaeger 호환
스토리지 자체 스토리지(Elasticsearch, Cassandra, MySQL 등) 백엔드 선택 가능 (Zipkin, Jaeger, Prometheus, Elastic 등)
확장성 Zipkin 전용 기능 OpenTelemetry Collector를 통한 다양한 백엔드 연동 가능

 

시작하기

예제는 kotlin, gradle(kts) 기반으로 진행 해보겠다. 미래를 고려하면 OpenTelemetry가 더 적합하다는 답변에 따라 OpenTelemetry로 시작해보겠다. 일단 우리의 목표는 마이크로미터의 트레이서를 설정하는 것이다. 마이크로미터의 OtelTracer의 가장 단순한 생성자를 보면 다음과 같다. Baggage라는 개념이 없어서 찾아보니 트레이스 식별자외에 전달되는 다른 프로퍼티들을 의미한다고 한다.

    /**
     * Creates a new instance of {@link OtelTracer} with no baggage support.
     * @param tracer tracer
     * @param otelCurrentTraceContext current trace context
     * @param publisher event publisher
     */
    public OtelTracer(io.opentelemetry.api.trace.Tracer tracer, OtelCurrentTraceContext otelCurrentTraceContext,
            EventPublisher publisher) {
        this(tracer, otelCurrentTraceContext, publisher, NOOP);
    }

 

디펜던시 설정

마이크로미터 공식 문서에는 exporter까지 포함되어 있어서 설정이 헷갈렸다. 최소한의 디펜던시를 추가해보자면 다음과 같다. findbugs는 마이크로미터에서 사용하고 있는 notnull, threadsafe등 어노테이션 지원을 위해서 추가하였다.

dependencies {
    testImplementation(kotlin("test"))

    // 마이크로미터 디펜던시
    implementation("com.google.code.findbugs:jsr305:3.0.2")
    implementation(platform("io.micrometer:micrometer-tracing-bom:1.4.3"))
    implementation("io.micrometer:micrometer-tracing")

    // Otel 트레이서 구현체 브릿지
    implementation("io.micrometer:micrometer-tracing-bridge-otel")
}

 

다음과 같은 디펜던시들이 추가되었다.

 

 

트레이서 설정

마이크로미터 공홈의 코드를 코틀린 기반으로 작성해보았다. 트레이서 설정은 최소화 했다. Otel 트레이서를 하나 생성한 후 기본적인 마이크로미터 트레이서 세팅에 전달하였다.

fun main() {
    // [OTel component] The SDK implementation of OpenTelemetry
    val openTelemetrySdk: OpenTelemetrySdk = OpenTelemetrySdk.builder()
        .build()

    // [OTel component] Tracer is a component that handles the life-cycle of a span
    val otelTracer = openTelemetrySdk.tracerProvider.get("io.micrometer.test")

    // [Micrometer Tracing component] A Micrometer Tracing wrapper for OTel
    val otelCurrentTraceContext = OtelCurrentTraceContext()

    // [Micrometer Tracing component] A Micrometer Tracing listener for setting up MDC
    val slf4JEventListener = Slf4JEventListener()

    // [Micrometer Tracing component] A Micrometer Tracing wrapper for OTel's Tracer.
    val tracer = OtelTracer(otelTracer, otelCurrentTraceContext, { event ->
        slf4JEventListener.onEvent(event)
    })
	
    // ... 후략 ...
}

 

스팬 생성 및 종료

스팬을 하나 생성하고 예외 여부와 상관없이 종료한다. 그리고 그 내용을 출력해보았다.

val newSpan = tracer.nextSpan().name("calculateTax")
 
try {
    tracer.withSpan(newSpan.start())
    newSpan.tag("taxValue", "100")

    // Business logic 

    println(newSpan)
} finally {
    newSpan.end()
}

println(newSpan)

 

Span이 어떠한 데이터들로 구성되어 있는지 알 수 있다. 스팬이 첨 시작하면서 traceId가 생성되고 시작시간이 기록되며, 종료시점에 종료시간이 기록됨을 알 수 있다. 다음에는 Span의 더 다양한 라이프사이클에 대해서 알아보겠다.

SdkSpan{traceId=40cbf3935920f73d0ed036b3f2192ad6, spanId=bb64cd27e2bb94bd, parentSpanContext=ImmutableSpanContext{traceId=00000000000000000000000000000000, spanId=0000000000000000, traceFlags=00, traceState=ArrayBasedTraceState{entries=[]}, remote=false, valid=false}, name=calculateTax, kind=INTERNAL, attributes=AttributesMap{data={taxValue=100}, capacity=128, totalAddedValues=1}, status=ImmutableStatusData{statusCode=UNSET, description=}, totalRecordedEvents=1, totalRecordedLinks=0, startEpochNanos=1739757634924879000, endEpochNanos=0}
SdkSpan{traceId=40cbf3935920f73d0ed036b3f2192ad6, spanId=bb64cd27e2bb94bd, parentSpanContext=ImmutableSpanContext{traceId=00000000000000000000000000000000, spanId=0000000000000000, traceFlags=00, traceState=ArrayBasedTraceState{entries=[]}, remote=false, valid=false}, name=calculateTax, kind=INTERNAL, attributes=AttributesMap{data={taxValue=100}, capacity=128, totalAddedValues=1}, status=ImmutableStatusData{statusCode=UNSET, description=}, totalRecordedEvents=1, totalRecordedLinks=0, startEpochNanos=1739757634924879000, endEpochNanos=1739757634927813375}

 

참고자료 : https://docs.micrometer.io/tracing/reference/api.html

 

Using Micrometer Tracing Directly :: Micrometer Tracing

Micrometer Tracing contains @NewSpan, @ContinueSpan, and @SpanTag annotations that frameworks can use to create or customize spans for either specific types of methods such as those serving web request endpoints or, more generally, to all methods. Micromet

docs.micrometer.io

 

반응형