2026'da Spring Boot Gözlemlenebilirlik: OpenTelemetry, Dağıtık İzleme ve Mülakat Soruları

OpenTelemetry ve Micrometer Tracing ile Spring Boot gözlemlenebilirliği hakkında kapsamlı rehber. Dağıtık izleme kurulumu, Observation API, OTLP export yapılandırması ve teknik mülakat hazırlığı.

OpenTelemetry dağıtık izleme ile Spring Boot gözlemlenebilirliği

Spring Boot gözlemlenebilirliği, loglama, metrikler ve dağıtık izlemeyi birleştirerek isteklerin mikro servisler arasındaki akışını gösteren birleşik bir sistem oluşturur. Spring Boot 3 ile birlikte framework, Micrometer Tracing'i benimsedi (Spring Cloud Sleuth'un yerini aldı) ve hem metrikler hem de trace'ler üreten tek bir enstrümantasyon noktası sağlayan Observation API'yi tanıttı.

Observation API Deseni

Spring Boot, OpenTelemetry'yi doğrudan çağırmak yerine Observation.observe() kullanılmasını önerir. Tek bir enstrümantasyon çağrısı, Micrometer aracılığıyla metrikler ve OpenTelemetry köprüsü aracılığıyla trace'ler üretir; bu sayede kod tekrarı azalır ve sinyaller arasında tutarlı etiket adlandırması sağlanır.

Observation API Micrometer ve OpenTelemetry'yi Nasıl Birleştirir

Observation API, hem metrikler hem de izleme üzerinde bir facade görevi görür. Kod Observation.createNotStarted() çağırdığında, Spring Boot gözlemi kayıtlı handler'lara yönlendirir: Micrometer metrikleri için MeterObservationHandler ve dağıtık trace'ler için TracingObservationHandler. Bu mimari, bir kez yapılan enstrümantasyonun her yere export edilmesi anlamına gelir.

Köprü bağımlılığı micrometer-tracing-bridge-otel, Micrometer Tracing'i OpenTelemetry'nin SDK'sına bağlar. Trace'ler OpenTelemetry'nin SdkTracerProvider'ı üzerinden akar ve OTLP aracılığıyla Jaeger, Tempo veya herhangi bir OpenTelemetry uyumlu toplayıcıya export edilir.

ObservabilityConfig.javajava
@Configuration
public class ObservabilityConfig {

    @Bean
    public ObservationRegistryCustomizer<ObservationRegistry> addLowCardinalityTags() {
        return registry -> registry.observationConfig()
            .observationHandler(new ObservationTextPublisher()); // Gözlemleri konsola loglar
    }
}

Yukarıdaki yapılandırma, her gözlemi loglayan bir ObservationHandler kaydeder. Üretim ortamında, otomatik yapılandırılmış handler'lar ek kod olmadan verileri Micrometer kayıtlarına ve OpenTelemetry exporter'larına gönderir.

Spring Boot 3.4 Tracing için Gerekli Bağımlılıklar

Spring Boot 3.4, dağıtık izleme için açık bağımlılıklar gerektirir. spring-boot-starter-actuator Observation API'yi sağlar, ancak izleme OpenTelemetry köprüsü ve bir exporter gerektirir.

xml
<!-- pom.xml -->
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-tracing-bridge-otel</artifactId>
    </dependency>
    <dependency>
        <groupId>io.opentelemetry</groupId>
        <artifactId>opentelemetry-exporter-otlp</artifactId>
    </dependency>
</dependencies>

micrometer-tracing-bridge-otel artifakt'ı, Micrometer Tracing'i OpenTelemetry'nin API'sine köprüler. opentelemetry-exporter-otlp, span'leri HTTP veya gRPC üzerinden OTLP protokolü kullanarak toplayıcılara gönderir. Spring Boot, bağımlılık yönetimi aracılığıyla sürüm hizalamasını yönetir.

Jaeger veya Tempo'ya OTLP Export Yapılandırması

Spring Boot, OTLP bağımlılığı mevcut olduğunda OtlpHttpSpanExporter'ı otomatik yapılandırır. Exporter, application.yml'de belirtilen endpoint'e trace'leri gönderir.

yaml
# application.yml
management:
  tracing:
    sampling:
      probability: 1.0  # Dev için %100 örnekleme, üretimde azaltın
  otlp:
    tracing:
      endpoint: http://localhost:4318/v1/traces
  opentelemetry:
    resource-attributes:
      service.name: order-service
      deployment.environment: staging

resource-attributes, her span'e metadata ekler. Grafana Tempo ve Jaeger gibi backend'ler, trace'leri servis ve ortama göre gruplamak için bu nitelikleri kullanır. sampling.probability'yi 1.0 olarak ayarlamak geliştirme sırasında tüm istekleri yakalar, ancak üretim sistemleri depolama maliyetlerini kontrol etmek için genellikle %1 ile %10 arasında örnekleme yapar.

Düşük ve Yüksek Kardinalite Etiketlerle Özel Gözlemler Oluşturma

Gözlemler iki etiket türünü destekler: metrikler için düşük kardinalite (HTTP metodları veya durum kodları gibi sınırlı değerler) ve trace'ler için yüksek kardinalite (kullanıcı ID'leri veya istek ID'leri gibi sınırsız değerler).

PaymentService.javajava
@Service
public class PaymentService {

    private final ObservationRegistry observationRegistry;

    public PaymentService(ObservationRegistry observationRegistry) {
        this.observationRegistry = observationRegistry;
    }

    public PaymentResult processPayment(PaymentRequest request) {
        return Observation.createNotStarted("payment.process", observationRegistry)
            .lowCardinalityKeyValue("payment.method", request.getMethod().name())  // enum: CARD, BANK_TRANSFER
            .lowCardinalityKeyValue("currency", request.getCurrency())              // sınırlı: USD, EUR, GBP
            .highCardinalityKeyValue("payment.id", request.getPaymentId())          // istek başına benzersiz
            .highCardinalityKeyValue("customer.id", request.getCustomerId())        // yüksek kardinalite
            .observe(() -> executePayment(request));
    }

    private PaymentResult executePayment(PaymentRequest request) {
        // Ödeme gateway çağrısı
        return new PaymentResult(true, "TXN-" + UUID.randomUUID());
    }
}

Düşük kardinalite etiketleri hem metriklerde hem de trace'lerde görünür. Yüksek kardinalite etiketleri yalnızca trace'lerde görünür çünkü sınırsız boyutlara sahip metrikler depolamayı patlatır. Bu ayrım, trace detaylarını zengin tutarken Prometheus kardinalite bombalarını önler.

Mülakat Sorusu: Etiket Kardinalitesi

Mülakatçılar sıklıkla bazı etiketlerin neden metriklerden hariç tutulması gerektiğini sorar. Cevap kardinalite ile ilgilidir: bir metrik üzerindeki kullanıcı ID etiketi, kullanıcı başına bir zaman serisi oluşturur; potansiyel olarak milyonlarca seri. İzleme backend'leri yüksek kardinalite ile zorlanır, bu da bellek tükenmesine ve yavaş sorgulara yol açar. Trace'ler örnekleme yoluyla yüksek kardinality'yi yönetir, bu da onları istek spesifik tanımlayıcılar için doğru yer yapar.

Spring Boot mülakatlarında başarılı olmaya hazır mısın?

İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.

Asenkron Sınırlar Arasında Trace Bağlamını Yayma

Dağıtık izleme bağlam yayılımı gerektirir. HTTP başlıkları servisler arasında trace ID'lerini taşır, ancak @Async metodları veya CompletableFuture zincirleri gibi asenkron işlemler yapılandırılmadığında bağlamı kaybedebilir.

Spring Boot 3.4, yapılandırıldığında reaktif akışlar ve @Async metodları için otomatik yayılım sağlar:

yaml
# application.yml
spring:
  reactor:
    context-propagation: auto
  task:
    execution:
      propagate-context: true

Özel TaskExecutor bean'leri için bunları ContextPropagatingTaskDecorator ile sarın:

AsyncConfig.javajava
@Configuration
@EnableAsync
public class AsyncConfig {

    @Bean
    public TaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(50);
        executor.setTaskDecorator(new ContextPropagatingTaskDecorator());
        executor.initialize();
        return executor;
    }
}

Decorator, mevcut Observation ve trace bağlamını asenkron thread'e kopyalar. Bu olmadan, asenkron görevlerde başlatılan span'ların ebeveyni olmaz ve trace ağacı bozulur.

@Observed ve @NewSpan Anotasyonlarını Kullanma

Spring Boot 3.4, anotasyonlar aracılığıyla deklaratif gözlemlenebilirliği destekler. AspectJ weaver ekleyerek anotasyon işlemeyi etkinleştirin:

xml
<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
yaml
# application.yml
management:
  observations:
    annotations:
      enabled: true
InventoryService.javajava
@Service
public class InventoryService {

    @Observed(name = "inventory.check", contextualName = "checkStock")
    public StockLevel checkStock(String productId) {
        // Veritabanı sorgusu
        return new StockLevel(productId, 42);
    }

    @NewSpan("inventory.reserve")  // Mevcut trace altında çocuk span oluşturur
    public ReservationResult reserveStock(String productId, int quantity) {
        // Envanter güncelleme
        return new ReservationResult(true, "RES-" + System.currentTimeMillis());
    }
}

@Observed hem bir metrik (timer) hem de bir span oluşturur. @NewSpan yalnızca span oluşturur, işlemin zaten başka yerde metrikleri olduğunda kullanışlıdır. Her iki anotasyon da istisna kaydı ve span durumunu otomatik olarak yönetir.

Spring Boot 3.4'te Otomatik Enstrümante Edilen Bileşenler

Spring Boot 3.4, kod değişikliği olmadan birkaç bileşeni otomatik enstrümante eder:

BileşenGözlem AdıNe Yakalar
Spring MVChttp.server.requestsİstek yolu, metod, durum, istisna
WebClienthttp.client.requestsGiden HTTP çağrıları
RestClienthttp.client.requestsGiden HTTP çağrıları (Spring 6.1+)
Spring Kafkaspring.kafka.listenerTüketici grubu, topic, partition
Spring Data JPAspring.data.repositoryRepository metodu, sorgu süresi
Scheduled Tasksspring.schedulingGörev adı, yürütme süresi

Spring Boot Actuator dokümantasyonu tüm otomatik enstrümante edilen bileşenleri listeler. Datasource Micrometer gibi üçüncü parti kütüphaneler JDBC sorgu izleme ekler.

Gürültüyü Azaltmak için Gözlemleri Filtreleme

Sağlık kontrolleri, hazırlık probları ve statik kaynaklar trace'lerde gürültü üretir. Bunları yüklemler kullanarak filtreleyin:

ObservationFilterConfig.javajava
@Configuration
public class ObservationFilterConfig {

    @Bean
    public ObservationPredicate noHealthChecks() {
        return (name, context) -> !name.equals("http.server.requests")
            || !isHealthEndpoint(context);
    }

    private boolean isHealthEndpoint(Observation.Context context) {
        if (context instanceof ServerRequestObservationContext http) {
            String path = http.getCarrier().getRequestURI();
            return path.startsWith("/actuator/health") || path.startsWith("/actuator/ready");
        }
        return false;
    }
}

Alternatif olarak, yapılandırmada ada göre gözlemleri devre dışı bırakın:

yaml
# application.yml
management:
  observations:
    enable:
      spring.security: false  # Spring Security gözlemlerini devre dışı bırak
      http.server.requests.actuator: false  # Özel yüklem adı
Mülakat Bağlamı: İzleme Örnekleme vs. Filtreleme

Örnekleme, tüm endpoint'lerden toplanan trace yüzdesini azaltır. Filtreleme, belirli endpoint'leri tamamen kaldırır. Asla tanısal değer sağlamayan endpoint'ler için filtreleme kullanın (sağlık kontrolleri, metrik kazıma). Temsili verileri korurken maliyetleri kontrol etmek için örnekleme kullanın.

Logları Trace ID'leriyle İlişkilendirme

Spring Boot 3.4, Micrometer Tracing aktif olduğunda trace ve span ID'lerini MDC'ye (Mapped Diagnostic Context) otomatik olarak ekler. Logback ve Log4j2 bu ID'leri log çıktısına dahil edebilir:

xml
<!-- logback-spring.xml -->
<configuration>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - traceId=%X{traceId} spanId=%X{spanId} - %msg%n</pattern>
        </encoder>
    </appender>
    <root level="INFO">
        <appender-ref ref="CONSOLE" />
    </root>
</configuration>

Bu kalıp ile her log satırı trace ID'sini içerir. Trace ID'ye göre log arama, tüm servislerden tek bir isteğin tüm mesajlarını döndürür ve Jaeger veya Tempo'daki span'lerle logları ilişkilendirir.

Spring Boot Gözlemlenebilirliği Hakkında Yaygın Mülakat Soruları

Mülakatçılar hem kavramsal anlayışı hem de gözlemlenebilirlikle pratik deneyimi değerlendirir. Bu sorular senior backend pozisyonlarında sıkça karşılaşılır.

S: Micrometer Tracing ile OpenTelemetry arasındaki fark nedir?

Micrometer Tracing, dağıtık izleme için vendor-neutral bir API'dir, Micrometer'ın metrikleri soyutlamasına benzer. OpenTelemetry belirli bir uygulama ve protokoldür. Spring Boot, Micrometer Tracing'i API olarak kullanır ve micrometer-tracing-bridge-otel aracılığıyla export için OpenTelemetry'ye köprüler. Bu katmanlama, uygulamaların kod değişikliği olmadan backend'leri değiştirmesine olanak tanır.

S: Spring neden doğrudan OpenTelemetry enstrümantasyonu yerine Observation API'yi önerir?

Observation API, hem metrikler hem de trace'ler üreten tek bir enstrümantasyon noktası sağlar. Doğrudan OpenTelemetry çağrıları yalnızca trace'ler üretir. Observation.observe() kullanmak aynı koddan bir timer metriği ve bir span üretir, tekrarı azaltır ve tutarlı adlandırma sağlar.

S: Span'lar arasında boşluk gösteren bir trace'i nasıl debug edersiniz?

Boşluklar eksik enstrümantasyonu veya kopmuş bağlam yayılımını gösterir. Kodun ContextPropagatingTaskDecorator olmadan asenkron işlemler kullanıp kullanmadığını kontrol edin. HTTP istemcilerinin enstrümante edildiğini doğrulayın (WebClient, RestClient veya manuel olarak sarılmış RestTemplate). Mesaj kuyrukları için, trace başlıklarının mesaj özellikleri aracılığıyla yayıldığını onaylayın.

S: Bir metriğe yüksek kardinalite etiket eklerseniz ne olur?

Her benzersiz etiket değeri yeni bir zaman serisi oluşturur. Milyonlarca kullanıcıya sahip bir kullanıcı ID etiketi milyonlarca seri oluşturur ve Prometheus veya diğer TSDB backend'lerinde belleği tüketir. Çözüm, yüksek kardinalitenin beklendiği yalnızca trace'lere etiketi ekleyen highCardinalityKeyValue() yerine lowCardinalityKeyValue() kullanmaktır.

Docker Compose ile Dağıtık İzleme Pipeline'ı Oluşturma

Yerel bir gözlemlenebilirlik stack'i, üretime dağıtımdan önce enstrümantasyonu doğrulamaya yardımcı olur. Bu örnek OpenTelemetry Collector ve Jaeger kullanır:

yaml
# docker-compose.yml
services:
  otel-collector:
    image: otel/opentelemetry-collector-contrib:0.102.0
    command: ["--config", "/etc/otel-collector-config.yml"]
    volumes:
      - ./otel-collector-config.yml:/etc/otel-collector-config.yml
    ports:
      - "4318:4318"   # OTLP HTTP
      - "4317:4317"   # OTLP gRPC

  jaeger:
    image: jaegertracing/jaeger:2.3
    ports:
      - "16686:16686"  # UI
    environment:
      - COLLECTOR_OTLP_ENABLED=true

  app:
    build: .
    environment:
      - MANAGEMENT_OTLP_TRACING_ENDPOINT=http://otel-collector:4318/v1/traces
    depends_on:
      - otel-collector
yaml
# otel-collector-config.yml
receivers:
  otlp:
    protocols:
      http:
        endpoint: 0.0.0.0:4318
      grpc:
        endpoint: 0.0.0.0:4317

processors:
  batch:
    timeout: 1s
    send_batch_size: 1024

exporters:
  otlp/jaeger:
    endpoint: jaeger:4317
    tls:
      insecure: true

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlp/jaeger]

Collector, Spring Boot uygulamasından span'leri alır ve Jaeger'a iletir. Bu mimari, uygulama kodunu değiştirmeden exporter'lar (Tempo, Zipkin, bulut backend'leri) eklemeye olanak tanır.

Pratik yapmaya başla!

Mülakat simülatörleri ve teknik testlerle bilgini test et.

Spring Boot Gözlemlenebilirliği için Temel Çıkarımlar

  • Observation API metrikleri ve izlemeyi birleştirir: tek bir Observation.observe() çağrısı hem timer metriği hem de span üretir, çift enstrümantasyonu ortadan kaldırır.
  • micrometer-tracing-bridge-otel ve opentelemetry-exporter-otlp eklemek OTLP exportunu etkinleştirir. Spring Boot 3.4, HTTP exporter'ı management.otlp.tracing.endpoint'ten aldığı endpoint ile otomatik yapılandırır.
  • Metriklerde görünen boyutlar için lowCardinalityKeyValue() kullanın (sınırlı değerler). Yalnızca trace verileri için highCardinalityKeyValue() kullanın (kullanıcı ID'leri, istek ID'leri).
  • spring.task.execution.propagate-context=true ile asenkron kod için bağlam yayılımını etkinleştirin ve özel executor'ları ContextPropagatingTaskDecorator ile sarın.
  • /actuator/health gibi gürültülü endpoint'leri ObservationPredicate bean'leri kullanarak filtrelemek trace'leri iş operasyonlarına odaklanmış tutar.
  • Log kalıpları, gözlemlenebilirlik backend'inizdeki dağıtık trace'lerle log satırlarını ilişkilendirmek için %X{traceId} içermelidir.
  • Gözlemlenebilirlik hakkındaki mülakat soruları kardinalite, bağlam yayılım hataları ve Observation API ile doğrudan OpenTelemetry kullanımı arasındaki ayrıma odaklanır.
Günün meydan okuması

Spring Boot kodundaki hatayı bulabilir misin?

Gerçek bir kod parçası, gizli bir hata, günde bir deneme. Denemek için hesap gerekmez.

Anthony Fillion-Maillet

Yazan:

Anthony Fillion-Maillet

SharpSkill kurucusu

10 yılı aşkın süredir fullstack geliştirici. SharpSkill’i yönetiyor ve burada yayımlanan her şeyden sorumlu.

19 Eylül 2026 tarihinde güncellendi

Etiketler

#spring-boot
#observability
#opentelemetry
#distributed-tracing
#micrometer

Paylaş

İlgili makaleler