İçeriğe atla

2025-11-05

OpenTelemetry Temelleri: Modern Observability için Başlangıç Rehberi

Pratik implementasyon örnekleri, yaygın hatalar ve detaylı terminoloji sözlüğü ile OpenTelemetry'nin trace, metric ve log sistemlerini kapsayan kapsamlı başlangıç rehberi.

Özet

OpenTelemetry (OTel), dağıtık sistemlerden telemetri verisi toplamak için birleşik, vendor-agnostic bir yaklaşım sunan açık kaynak bir observability framework’üdür. Bu kapsamlı rehber, observability temellerini, OpenTelemetry mimarisini, çalışan kod örnekleriyle pratik implementasyon pattern’lerini ve semantic convention’lar ile sampling stratejileri gibi temel kavramları ele alıyor. Uygulamaları nasıl instrument edeceğinizi, collector’ları nasıl deploy edeceğinizi, yaygın hatalardan nasıl kaçınacağınızı ve sistemlerinize production-ready observability’yi nasıl ekleyeceğinizi öğreneceksiniz.

Giriş: Dağıtık Sistem Challenge’ı

Monolitik bir uygulamayı debug etmek basittir - birkaç log statement eklersin, sorunu reproduce edersin ve execution flow’u takip edersin. Ama tek bir kullanıcı request’inin 10-50 microservice’ten geçtiği dağıtık sistemlerde, geleneksel debugging yaklaşımları yetersiz kalır. Yavaş bir checkout request’i, payment service’teki bir database query’sinden, inventory service’teki bir cache miss’ten veya shipping service’teki bir third-party API timeout’undan kaynaklanabilir.

Challenge sadece bir şeylerin yanlış olduğunu tespit etmek değildir - metrikler ve alertler bunu halleder. Asıl zorluk neden yanlış olduğunu ve problemin dağıtık sistemde nerede başladığını anlamaktır. İşte observability tam burada kritik hale gelir.

OpenTelemetry, bu challenge’a endüstri standardı çözüm olarak ortaya çıktı. Kubernetes’ten sonra CNCF’nin en aktif ikinci projesi olan ve Google, Microsoft, Amazon ve Uber dahil 1000’den fazla organizasyonun desteğini alan OpenTelemetry, vendor lock-in olmadan telemetri verisi toplamak, işlemek ve export etmek için standardize bir yol sunuyor.

Bu rehber, temel kavramları anlamaktan uygulamalarınızda production-ready instrumentation implement etmeye kadar OpenTelemetry temellerinde size yol gösterecek.

Observability Temellerini Anlamak

Observability Nedir?

Observability, bir sistemin internal state’ini external output’larını inceleyerek anlama yeteneğidir. Önceden tanımlanmış metrikler ve alert’lere dayanan ve “ne bozuk” sorusunu yanıtlayan monitoring’den farklı olarak, observability soruları önceden bilmeden sistem davranışı hakkında rastgele sorular sormanızı sağlar.

Farkı düşünün:

Monitoring: “API error rate %5’in üzerinde” Observability: “Kullanıcı X’in checkout request’i neden 14:23’te payment service’te başarısız oldu ve o anda database query pattern’leri nasıldı?”

Monitoring size bilinen problemlerin ne zaman oluştuğunu söyler. Observability bilinmeyen problemleri araştırmanıza ve production’daki sistem davranışını anlamanıza yardımcı olur.

Üç Observability Signal’i

Modern observability, tam sistem görünürlüğü sağlamak için birlikte çalışan üç correlation’lu signal’e dayanır:

Trace’ler

Bir trace, bir request’in dağıtık sistemlerdeki tüm yolculuğunu span’lerden oluşan Directed Acyclic Graph (DAG) olarak kaydeder. Her span tek bir operation’ı temsil eder ve şunları içerir:

  • Start ve end timestamp’leri - Kesin operation timing’i
  • Operation adı - Açıklayıcı identifier (örn. “GET /api/orders”)
  • Parent-child ilişkileri - Operation’ların nasıl nest olduğu ve bağlandığı
  • Attribute’lar - HTTP method, status code, database name gibi metadata
  • Event’ler - Span sırasında belirli zaman noktaları (örn. “cache miss”, “retry attempt”)
  • Status - Success, error veya unset

Trace’ler “Bu request her service’te ne kadar sürdü?” ve “Hangi service başarısızlığa neden oldu?” gibi soruları yanıtlar.

Client Request

API Gateway

Auth Service

Order Service

Payment Service

Inventory Service

Database

Metrikler

Metrikler, zaman içinde sistem performansını temsil eden aggregate edilmiş sayısal veridir:

  • Counter’lar - Monoton artan değerler (toplam request, toplam error)
  • Gauge’lar - Anlık değerler (mevcut memory kullanımı, aktif connection’lar)
  • Histogram’lar - Değer dağılımı (latency percentile’ları, response boyutları)
  • UpDownCounter’lar - Artan veya azalan değerler (queue depth, concurrent kullanıcılar)

Metrikler “95th percentile latency nedir?” ve “Service saniyede kaç request handle ediyor?” gibi soruları yanıtlar.

Log’lar

Log’lar, service’lerden belirli event’ler hakkında detaylı context sağlayan timestamp’li mesajlardır. trace_id ve span_id kullanarak trace’lerle correlation yapıldığında, log’lar önemli ölçüde daha değerli hale gelir ve bir trace’ten ilgili log mesajlarına anında atlama yapmanızı sağlar.

Log’lar “Tam error mesajı neydi?” ve “Exception oluştuğunda variable değerleri nelerdi?” gibi soruları yanıtlar.

Üç Signal’in Önemi

Her signal farklı insight’lar sağlar:

  • Metrikler problemleri tespit eder ve zaman içinde trend’leri gösterir
  • Trace’ler request flow’unu açıklar ve bottleneck’leri tanımlar
  • Log’lar detaylı event-level bilgi sağlar

Asıl güç üç signal’in correlation’ından gelir. Metriklere dayalı bir alert tetiklendiğinde, error status’üne göre trace’leri filtreleyerek başarısız request’leri tanımlarsın, problematic service’i bulmak için trace detaylarını incelersin, sonra root cause’u anlamak için correlation’lu log’lara bakarsın. Bu unified troubleshooting workflow, Mean Time To Resolution (MTTR)‘ı önemli ölçüde azaltır.

OpenTelemetry Mimarisi

OpenTelemetry, birbirine bağlı birkaç component aracılığıyla eksiksiz bir observability framework sağlar. Bu mimariyi anlamak, instrumentation’ı etkili bir şekilde implement etmenize ve sorunlar ortaya çıktığında troubleshoot etmenize yardımcı olur.

Backends

Collector

Application

Application Code

OTel API

OTel SDK

Instrumentation Libraries

Receivers

Processors

Exporters

Jaeger

Prometheus

Elastic

Cloud Services

API Layer

OpenTelemetry API, implementation detaylarını belirlemeden telemetri generate etmek için language-specific interface’ler tanımlar. API versiyonlar arasında stabil’dir ve şunları sağlar:

  • Tracer, meter ve logger oluşturmak için interface’ler
  • Context propagation mekanizmaları
  • SDK configure edilmediğinde no-op implementation’lar
  • Instrumentation code ile telemetri export arasında decoupling

Instrumentation kodunu API’ye göre yazarsın ve SDK gerçek implementation’ı sağlar. Bu ayrım esneklik sağlar - application kodunu değiştirmeden SDK implementation’larını değiştirebilirsin.

SDK Implementation

SDK, API specification’ı implement eder ve şunları handle eder:

  • TracerProvider initialization - Tracing infrastructure’ını kurar
  • Span lifecycle management - Span’leri oluşturur, yönetir ve export eder
  • Metric instrument registration - Counter’ları, gauge’ları, histogram’ları configure eder
  • Context propagation - Operation’lar arasında trace context’ini korur
  • Resource attribute’ları - Service’i tanımlar (name, version, environment)
  • Sampling kararları - Hangi trace’lerin tutulacağına karar verir
  • Exporter configuration - Telemetriyi destination’lara gönderir

Instrumentation Library’leri

Pre-built instrumentation library’leri, popüler framework’lerden kod değişikliği olmadan otomatik olarak telemetri yakalar. Bu library’ler, operation’ları intercept etmek ve otomatik olarak span generate etmek için bytecode injection (Java), monkey-patching (Python, Node.js) veya middleware (Go) gibi teknikler kullanır.

Yaygın instrumentation library’leri:

  • HTTP server’lar - Express, FastAPI, Spring Boot, Gin
  • HTTP client’lar - Axios, requests, HttpClient
  • Database’ler - PostgreSQL, MongoDB, Redis, MySQL
  • RPC framework’leri - gRPC, Thrift
  • Message queue’lar - Kafka, RabbitMQ, SQS, Pub/Sub

Auto-instrumentation, minimum çabayla observability değerinin %80’ini sağlar. Sonra business-specific operation’lar için manual instrumentation eklersin.

OpenTelemetry Collector

Collector, configurable pipeline’lar aracılığıyla telemetriyi alıp işleyip export eden vendor-agnostic bir proxy’dir. Application’lar ile observability backend’leri arasında ara katman görevi görür ve şunları sağlar:

Temel avantajlar:

  • Buffering ve retry’lar - Backend unavailability’yi gracefully handle eder
  • Protocol translation - Telemetri formatları arasında convert eder (OTLP, Jaeger, Zipkin)
  • Data preprocessing - Telemetriyi filtreler, transform eder ve enrich eder
  • Multi-backend export - Aynı anda birden fazla destination’a telemetri gönderir
  • Centralized configuration - Telemetri pipeline’larını tek yerden yönetir
  • Resource optimization - Batching ve compression network overhead’i azaltır

Collector pipeline component’leri:

  • Receiver’lar - Telemetriyi kabul eder (OTLP, Jaeger, Prometheus, Zipkin)
  • Processor’lar - Veriyi transform eder (batch, memory_limiter, attributes, filter)
  • Exporter’lar - Backend’lere gönderir (Jaeger, Prometheus, Elasticsearch, cloud services)

Başlarken: Pratik Implementation

Çalışan örneklerle OpenTelemetry instrumentation’ı implement edelim. Hemen değer elde etmek için auto-instrumentation ile başlayacağız, sonra business logic için manual instrumentation ekleyeceğiz.

Node.js Auto-Instrumentation

İlk olarak gerekli paketleri yükle:

npm install @opentelemetry/sdk-node \
            @opentelemetry/auto-instrumentations-node \
            @opentelemetry/exporter-trace-otlp-grpc \
            @opentelemetry/semantic-conventions

Application kodunu import etmeden önce OpenTelemetry’yi initialize etmek için tracing.js oluştur:

// tracing.js - Bunu ilk olarak import et, diğer import'lardan önce
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-grpc');
const { Resource } = require('@opentelemetry/resources');
const { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } = require('@opentelemetry/semantic-conventions');

// Service'ini tanımlamak için resource attribute'ları configure et
const resource = new Resource({
  [ATTR_SERVICE_NAME]: 'payment-service',
  [ATTR_SERVICE_VERSION]: '1.2.0',
});

// OTLP exporter'ı configure et (local dev için console exporter'a değiştir)
const traceExporter = new OTLPTraceExporter({
  url: 'http://localhost:4317', // OpenTelemetry Collector endpoint
});

// Auto-instrumentation ile SDK'yı initialize et
const sdk = new NodeSDK({
  resource,
  traceExporter,
  instrumentations: [getNodeAutoInstrumentations()],
});

// SDK'yı başlat
sdk.start();

// Graceful shutdown
process.on('SIGTERM', () => {
  sdk.shutdown()
    .then(() => console.log('Tracing terminated'))
    .catch((error) => console.log('Error terminating tracing', error))
    .finally(() => process.exit(0));
});

Application entry point’ini tracing’i önce import edecek şekilde güncelle:

// server.js
require('./tracing'); // İlk import olmalı

const express = require('express');
const app = express();

app.get('/api/orders/:id', async (req, res) => {
  // Bu HTTP request otomatik olarak trace ediliyor
  const order = await fetchOrder(req.params.id);
  res.json(order);
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

Application’ını başlat:

node server.js

Her HTTP request artık ek kod olmadan otomatik olarak trace ediliyor. Auto-instrumentation HTTP method, URL, status code ve response time’ı otomatik olarak yakalar.

Python Auto-Instrumentation

OpenTelemetry paketlerini yükle:

pip install opentelemetry-distro \
            opentelemetry-exporter-otlp \
            opentelemetry-instrumentation-flask

Flask app’ini oluşturmadan önce instrumentation’ı initialize et:

# app.py
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.resources import Resource
from opentelemetry.semconv.attributes import ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION
from opentelemetry.instrumentation.flask import FlaskInstrumentor

# Resource attribute'larını configure et
resource = Resource.create({
    ATTR_SERVICE_NAME: "order-service",
    ATTR_SERVICE_VERSION: "1.0.0",
})

# Tracer provider'ı initialize et
provider = TracerProvider(resource=resource)
processor = BatchSpanProcessor(OTLPSpanExporter(endpoint="http://localhost:4317"))
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)

# Flask app'i oluştur
from flask import Flask, jsonify
app = Flask(__name__)

# Flask'ı auto-instrument et
FlaskInstrumentor().instrument_app(app)

@app.route('/api/orders/<order_id>')
def get_order(order_id):
    # Bu endpoint otomatik olarak trace ediliyor
    order = fetch_order_from_db(order_id)
    return jsonify(order)

if __name__ == '__main__':
    app.run(port=5000)

Application’ını çalıştır:

python app.py

Business Logic için Manual Instrumentation

Auto-instrumentation framework-level operation’ları yakalar, ama business logic için manual span’lere ihtiyacın var:

// Node.js manual instrumentation
const { trace, SpanStatusCode } = require('@opentelemetry/api');

async function processPayment(orderId, amount) {
  const tracer = trace.getTracer('payment-service');

  // Bu business operation için custom span oluştur
  return await tracer.startActiveSpan('processPayment', async (span) => {
    try {
      // Business context'i span attribute olarak ekle
      span.setAttribute('order.id', orderId);
      span.setAttribute('payment.amount', amount);
      span.setAttribute('payment.currency', 'USD');

      // Payment processing'i simulate et
      const result = await chargeCustomer(amount);

      // Result bilgisini ekle
      span.setAttribute('payment.transaction_id', result.transactionId);
      span.setAttribute('payment.status', 'success');

      span.setStatus({ code: SpanStatusCode.OK });
      return result;

    } catch (error) {
      // Error bilgisini kaydet
      span.recordException(error);
      span.setStatus({
        code: SpanStatusCode.ERROR,
        message: error.message,
      });
      throw error;
    } finally {
      span.end(); // Her zaman span'i bitir
    }
  });
}

Python manual instrumentation:

# Python manual instrumentation
from opentelemetry import trace
from opentelemetry.trace import Status, StatusCode

tracer = trace.get_tracer(__name__)

def process_order(order_id):
    with tracer.start_as_current_span("process_order") as span:
        try:
            # Business context ekle
            span.set_attribute("order.id", order_id)
            span.set_attribute("order.type", "express")

            # Business logic'i gerçekleştir
            order = validate_order(order_id)
            span.set_attribute("order.items_count", len(order.items))

            inventory_result = check_inventory(order)
            span.set_attribute("inventory.available", inventory_result.available)

            # Payment operation için nested span
            with tracer.start_as_current_span("charge_payment") as payment_span:
                payment_span.set_attribute("payment.amount", order.total)
                payment_result = charge_customer(order)
                payment_span.set_attribute("payment.status", payment_result.status)

            span.set_status(Status(StatusCode.OK))
            return {"success": True, "order_id": order_id}

        except Exception as e:
            span.record_exception(e)
            span.set_status(Status(StatusCode.ERROR, str(e)))
            raise

Service’ler Arası Context Propagation

Distributed tracing’in çalışması için trace context’inin service boundary’leri arasında flow etmesi gerekir. OpenTelemetry, W3C Trace Context standardını kullanarak context’i HTTP header’larında propagate eder.

Auto-instrumentation bunu otomatik olarak handle eder HTTP request’leri için:

// Service A, Service B'ye HTTP request yapar
const axios = require('axios');

// OpenTelemetry auto-instrumentation otomatik olarak
// traceparent ve tracestate header'larını bu request'e inject eder
const response = await axios.get('http://service-b/api/data');

Manual HTTP client’lar veya message queue’lar için context’i explicit olarak inject et:

const { propagation, context } = require('@opentelemetry/api');

// Mevcut context'i al
const ctx = context.active();

// Context'i HTTP header'larına inject et
const headers = {};
propagation.inject(ctx, headers);

// Propagate edilmiş header'larla request yap
await fetch('http://service-b/api/data', { headers });

Python context propagation:

from opentelemetry import propagate
from opentelemetry.propagators.cloud_trace_propagator import CloudTraceFormatPropagator
import requests

# Trace context'ini header'lara inject et
headers = {}
propagate.inject(headers)

# Propagate edilmiş context ile request yap
response = requests.get('http://service-b/api/data', headers=headers)

OpenTelemetry Collector Configuration

Collector, application’lar ile observability backend’leri arasında kritik bir ara katman görevi görür. İşte production-ready bir configuration:

# otel-collector-config.yaml
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

processors:
  # Memory limiter OOM crash'lerini önler
  memory_limiter:
    check_interval: 1s
    limit_mib: 512
    spike_limit_mib: 128

  # Batch processor network overhead'i azaltır
  batch:
    timeout: 200ms
    send_batch_size: 8192
    send_batch_max_size: 10000

  # Resource attribute'ları ekle
  resource:
    attributes:
      - key: deployment.environment
        value: production
        action: upsert

exporters:
  # Trace'leri Jaeger'a gönder
  jaeger:
    endpoint: jaeger-collector:14250
    tls:
      insecure: true

  # Metrikleri Prometheus'a gönder
  prometheus:
    endpoint: "0.0.0.0:8889"

  # Debug için console exporter
  logging:
    loglevel: info

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, batch, resource]
      exporters: [jaeger, logging]

    metrics:
      receivers: [otlp]
      processors: [memory_limiter, batch]
      exporters: [prometheus]

Collector’ı Docker ile deploy et:

docker run -d --name otel-collector \
  -p 4317:4317 \
  -p 4318:4318 \
  -p 8889:8889 \
  -v $(pwd)/otel-collector-config.yaml:/etc/otel-collector-config.yaml \
  otel/opentelemetry-collector:latest \
  --config=/etc/otel-collector-config.yaml

Collector Deployment Pattern’leri

Agent Pattern:

  • Her application’ın yanında sidecar veya DaemonSet olarak collector deploy et
  • Gateway’e göndermeden önce local aggregation yapar
  • Network trafiğini azaltır ama resource consumption’ı artırır

Gateway Pattern:

  • Centralized collector service
  • Tüm application’lar gateway’e telemetri gönderir
  • Managment’i basitleştirir ama potential bottleneck oluşturur

Hierarchical Pattern (Önerilen):

  • Agent’lar basic processing ile locally collect eder
  • Gateway’ler heavy processing ve routing yapar
  • Reliability ve performance’ın en iyi dengesi

Backends

Gateway Layer

Application Hosts

App 1

Agent Collector

App 2

Agent Collector

App 3

Agent Collector

Gateway Collector

Jaeger

Prometheus

Elasticsearch

Temel Kavramlar

Semantic Convention’lar

Semantic convention’lar, interoperability için attribute isimlendirmeyi standardize eder. Herkes method, request.method veya http_method gibi varyasyonlar yerine http.method kullandığında, observability tool’ları service’ler arasında consistent analiz sağlar.

Attribute isimlendirme kuralları:

  • Lowercase ve underscore kullan (snake_case)
  • Namespace prefix ile başla (http., db., messaging.)
  • Custom attribute’lar için reverse domain notation kullan (com.company.attribute)

Yaygın semantic convention namespace’leri:

// HTTP operation'lar
span.setAttribute('http.method', 'GET');
span.setAttribute('http.route', '/api/orders/:id');
span.setAttribute('http.status_code', 200);
span.setAttribute('http.url', 'https://api.example.com/orders/123');

// Database operation'lar
span.setAttribute('db.system', 'postgresql');
span.setAttribute('db.name', 'orders_db');
span.setAttribute('db.statement', 'SELECT * FROM orders WHERE id = $1');
span.setAttribute('db.operation', 'SELECT');

// Messaging operation'lar
span.setAttribute('messaging.system', 'kafka');
span.setAttribute('messaging.destination', 'order-events');
span.setAttribute('messaging.operation', 'publish');

// RPC operation'lar
span.setAttribute('rpc.system', 'grpc');
span.setAttribute('rpc.service', 'OrderService');
span.setAttribute('rpc.method', 'GetOrder');

// Exception bilgisi
span.setAttribute('exception.type', 'PaymentException');
span.setAttribute('exception.message', 'Insufficient funds');

Sampling Stratejileri

Scale’de, trace’lerin %100’ünü collect etmek prohibitively expensive hale gelir. Saniyede 10,000 request işleyen high-traffic bir service, massive telemetri volume generate eder. Sampling, görünürlüğü korurken maliyetleri azaltır.

Head-Based Sampling:

Karar trace root’ta verilir. Basit probabilistic sampling tüm trace’lerin bir yüzdesini tutar:

// Tüm trace'lerin %10'unu sample et
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { TraceIdRatioBasedSampler } = require('@opentelemetry/sdk-trace-base');

const sdk = new NodeSDK({
  sampler: new TraceIdRatioBasedSampler(0.1), // %10 sampling
  // ... diğer config
});

Tail-Based Sampling:

Karar trace tamamlandıktan sonra verilir. Collector, tutup tutmamaya karar vermeden önce full trace’i inceler. Bu intelligent sampling sağlar:

  • Error’ların %100’ünü tut
  • Latency threshold’ları aşan trace’leri tut
  • Belirli kullanıcılar veya operation’lar için trace’leri tut
  • Başarılı fast trace’leri drop et

Tail-based sampling collector configuration gerektirir:

# Collector tail sampling configuration
processors:
  tail_sampling:
    decision_wait: 10s
    num_traces: 100000
    policies:
      - name: errors
        type: status_code
        status_code:
          status_codes: [ERROR]
      - name: slow-traces
        type: latency
        latency:
          threshold_ms: 1000
      - name: probabilistic
        type: probabilistic
        probabilistic:
          sampling_percentage: 5

Pratik sampling stratejisi:

  1. Implementation sırasında %100 sampling ile başla
  2. Instrumentation’ı validate ettikten sonra %10’da head-based sampling ekle
  3. Tüm error’ları tutmak için tail-based sampling implement et
  4. Veri değerini anladıkça baseline sampling’i azalt
  5. Sampling effectiveness’ını monitor et - gerçek issue’ları yakalıyor musun?

Resource Attribute’ları

Resource attribute’ları telemetri kaynağını tanımlar ve bir service’ten gelen tüm signal’lerde consistent olmalıdır:

const { Resource } = require('@opentelemetry/resources');
const { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } = require('@opentelemetry/semantic-conventions');

const resource = new Resource({
  [ATTR_SERVICE_NAME]: 'payment-service',
  [ATTR_SERVICE_VERSION]: '2.1.0',
  'deployment.environment': 'production',
  'service.instance.id': process.env.HOSTNAME,
  'cloud.provider': 'aws',
  'cloud.region': 'us-east-1',
  'cloud.availability_zone': 'us-east-1a',
});

Resource attribute’ları şunları sağlar:

  • Environment veya version’a göre trace’leri filtreleme
  • Region veya availability zone’a göre metrikleri gruplama
  • Issue’ları belirli deployment’larla correlation yapma
  • Infrastructure-level pattern’leri anlama

Yaygın Hatalar ve Çözümleri

1. Late Initialization

Problem: OpenTelemetry SDK’yı application framework’lerini import ettikten sonra initialize etmek missed instrumentation’a neden olur. Auto-instrumentation module import’larını intercept etmeye dayanır.

Semptom: Eksik HTTP veya database span’leri olan incomplete trace’ler.

Çözüm: OpenTelemetry’yi herhangi bir application import’undan önce import et ve initialize et:

// Yanlış - app tracing'den önce import edilmiş
const express = require('express');
require('./tracing');

// Doğru - tracing önce import edilmiş
require('./tracing');
const express = require('express');

2. High Cardinality Attribute’lar

Problem: Span attribute olarak unbounded değerler eklemek (user ID’ler, timestamp’ler, query parameter’lı full URL’ler) milyonlarca unique combination oluşturur ve storage’ı overwhelm eder.

Semptom: Massive storage maliyetleri, yavaş query’ler, backend veriyi reject ediyor.

Çözüm: Attribute’lar için bounded değerler kullan. Unbounded değerleri span event olarak store et:

// Yanlış - high cardinality
span.setAttribute('user.id', userId); // Milyonlarca unique kullanıcı
span.setAttribute('order.timestamp', Date.now()); // Her request'te unique
span.setAttribute('http.url', fullUrlWithParams); // Request başına unique

// Doğru - bounded değerler
span.setAttribute('http.route', '/api/orders/:id'); // Sınırlı route'lar
span.setAttribute('user.tier', 'premium'); // Az sayıda tier
span.addEvent('order_created', { 'order.id': orderId }); // Event, attribute değil

3. Eksik Context Propagation

Problem: Service boundary’leri arasında trace context propagate edilmemesi, ayrı operation’lar gibi görünen broken trace’lere neden olur.

Semptom: Her service isolated span’ler gösteriyor; service’ler arası request flow’u takip edilemiyor.

Çözüm: HTTP client’ların trace context header’larını içerdiğinden emin ol. Auto-instrumentation kullan veya context’i manuel olarak inject et:

# Context propagation'ı verify et
from opentelemetry import propagate
import requests

headers = {}
propagate.inject(headers)  # Trace context'i inject et
print(f"Headers: {headers}")  # traceparent içermeli

response = requests.get('http://service-b/api/data', headers=headers)

4. Memory Limiter’ları Unutmak

Problem: Memory limiter olmayan collector’lar, traffic spike’larında telemetri buffering mevcut memory’yi aştığında crash olur.

Semptom: OOM error’larıyla collector crash’leri; telemetri verilerinde gap’ler.

Çözüm: Batch processor’dan önce her zaman memory_limiter processor configure et:

processors:
  memory_limiter:
    check_interval: 1s
    limit_mib: 512  # Container memory'nin %80'i
  batch:
    timeout: 200ms

service:
  pipelines:
    traces:
      processors: [memory_limiter, batch]  # memory_limiter İLK

5. Over-Instrumentation

Problem: Her function call için span oluşturmak massive span count generate eder, trace’leri analiz etmeyi zorlaştırır ve maliyetleri artırır.

Semptom: Basit request’ler için 500+ span’li trace’ler; yavaş query’ler; bottleneck’leri tanımlamak zor.

Çözüm: Sadece service boundary’lerinde ve kritik business operation’larda instrument et:

// Yanlış - çok fazla span
function processOrder(order) {
  return tracer.startActiveSpan('processOrder', (span1) => {
    const validated = tracer.startActiveSpan('validateOrder', (span2) => {
      const result = tracer.startActiveSpan('checkFields', (span3) => {
        // Her küçük fonksiyon trace ediliyor
      });
    });
  });
}

// Doğru - stratejik span'ler
function processOrder(order) {
  return tracer.startActiveSpan('processOrder', async (span) => {
    span.setAttribute('order.id', order.id);

    // Internal validation trace edilmemiş - hızlı
    validateOrder(order);

    // Sadece önemli operation'ları trace et
    const payment = await tracer.startActiveSpan('chargePayment', async (paymentSpan) => {
      return await chargeCustomer(order.total);
    });
  });
}

Guideline: İyi tasarlanmış trace’te service başına 5-15 span olur, yüzlerce değil.

6. Semantic Convention’ları İgnore Etmek

Problem: Standard convention’lar yerine custom attribute isimleri kullanmak interoperability’yi bozar ve automatic backend analizi önler.

Semptom: Dashboard’lar populate olmuyor; automatic service map’ler yok; standard metrikler eksik.

Çözüm: Her zaman OpenTelemetry semantic convention’larına refer et:

// Yanlış - custom isimler
span.setAttribute('request_method', 'GET');
span.setAttribute('status', 200);
span.setAttribute('db_type', 'postgres');

// Doğru - semantic convention'lar
span.setAttribute('http.method', 'GET');
span.setAttribute('http.status_code', 200);
span.setAttribute('db.system', 'postgresql');

7. Collector Olmadan Doğrudan Export

Problem: Application’ların doğrudan observability backend’lerine export etmesi tight coupling yaratır ve single point of failure oluşturur.

Semptom: Backend down olduğunda application takılıyor; retry logic yok; buffering yok.

Çözüm: Application’lar ile backend’ler arasında her zaman OpenTelemetry Collector kullan:

// Doğru - collector'a export et
const traceExporter = new OTLPTraceExporter({
  url: 'http://otel-collector:4317', // Doğrudan backend'e değil collector'a
});

İstisna: Collector overhead’inin prohibitive olduğu serverless function’lar doğrudan export edebilir.

8. Inconsistent Resource Attribute’lar

Problem: Service’lerin resource attribute’ları için farklı formatlar kullanması correlation’ı ve filtrelemeyi önler.

Semptom: Service’ler dashboard’larda duplicate görünüyor; environment’a göre filtre yapılamıyor; broken dependency’ler.

Çözüm: Organizasyon genelinde resource attribute’ları standardize et:

// Standardize edilmiş format
const resource = new Resource({
  'service.name': 'payment-service',  // Her zaman kebab-case
  'service.version': '1.2.0',  // Her zaman semantic versioning
  'deployment.environment': 'production', // Her zaman lowercase: dev/staging/production
});

9. Instrumentation’ı Test Etmemek

Problem: Instrumentation kodu test edilmediğinde production’da failure’lar ortaya çıkıyor.

Semptom: Production’da eksik span’ler, yanlış attribute’lar keşfediliyor.

Çözüm: Instrumentation için test’ler yaz:

const { InMemorySpanExporter } = require('@opentelemetry/sdk-trace-base');

describe('Payment Processing', () => {
  let spanExporter;

  beforeEach(() => {
    spanExporter = new InMemorySpanExporter();
    // SDK'yı in-memory exporter ile configure et
  });

  it('creates span with correct attributes', async () => {
    await processPayment('order-123', 99.99);

    const spans = spanExporter.getFinishedSpans();
    expect(spans).toHaveLength(1);
    expect(spans[0].name).toBe('processPayment');
    expect(spans[0].attributes['order.id']).toBe('order-123');
    expect(spans[0].attributes['payment.amount']).toBe(99.99);
  });
});

10. Erken Aggressive Sampling

Problem: Rollout sırasında aggressive sampling (%0.1) implement etmek instrumentation issue’larını keşfetmeyi önler.

Semptom: Problemler için eksik trace’ler; instrumentation validate edilemiyor.

Çözüm: Initial implementation sırasında yüksek sampling rate (%50-100) ile başla. Veri değerini anladıkça kademeli olarak azalt.

OpenTelemetry Terminoloji Sözlüğü

Temel Kavramlar

Observability Bir sistemin internal state’ini external output’larını (trace’ler, metrikler, log’lar) inceleyerek anlama yeteneği. Önceden tanımlanmış monitoring olmadan sistem davranışı hakkında rastgele sorular sormanızı sağlar.

Telemetry Sistemlerin operation’larını tanımlayan verileri. OpenTelemetry context’inde trace’leri, metrikleri ve log’ları ifade eder.

Signal Telemetri verisinin bir kategorisi. OpenTelemetry üç signal tanımlar: trace’ler, metrikler ve log’lar.

Instrumentation Telemetri verisi generate eden kod. Automatic (library’ler aracılığıyla) veya manual (custom kod) olabilir.

Tracing Terminolojisi

Trace Tek bir request’in dağıtık sistemlerdeki yolculuğunun span’lerden oluşan Directed Acyclic Graph (DAG) olarak eksiksiz kaydı.

Span Bir trace içindeki tek bir operation; start time, end time, operation adı, attribute’lar, event’ler ve parent-child ilişkileri içerir.

Trace Context Span’leri complete trace’lere correlate etmek için service boundary’leri arasında propagate edilen metadata. Trace ID, span ID ve sampling kararını içerir.

Span Attribute’ları Metadata sağlayan span’lere eklenmiş key-value pair’ler (örn. http.method, db.statement).

Span Event’leri Span lifetime sırasında discrete occurrence’ları temsil eden timestamp’li mesajlar (örn. “cache miss”, “retry attempt”).

Span Status Operation’ın succeed olup olmadığını (OK), fail olup olmadığını (ERROR) veya status’ün unknown (UNSET) olduğunu gösterir.

Parent Span Child span’leri başlatan span, operation nesting’i gösteren hiyerarşik ilişkiler oluşturur.

Root Span Bir trace’teki ilk span, request’in sisteme entry point’ini temsil eder.

Context Propagation Trace context’ini service boundary’leri arasında geçirmek için mekanizma, distributed tracing’i mümkün kılar. HTTP header’ları aracılığıyla W3C Trace Context standardını kullanır.

Baggage Cross-cutting concern’lar (user ID, feature flag’ler) için trace context’i ile birlikte propagate edilen key-value pair’ler. Span verisine dahil değil.

Metrik Terminolojisi

Metric Zaman içinde capture edilen sistem performansının aggregate edilmiş sayısal ölçümü.

Counter Cumulative değerleri temsil eden monoton artan metrik (toplam request’ler, toplam error’lar).

Gauge Artabilen veya azalabilen point-in-time ölçüm (mevcut memory kullanımı, aktif connection’lar).

Histogram Min, max, sum, count ve bucket’ları kaydeden ölçüm dağılımı (latency dağılımı, response boyutları).

UpDownCounter Artabilen veya azalabilen metrik, yukarı ve aşağı giden değerleri track eder (queue depth, concurrent kullanıcılar).

Metric Instrument Ölçümleri kaydetmek için API interface’i (meter aracılığıyla oluşturulur).

Aggregation Metrik ölçümlerini zaman içinde ve dimension’lar arasında combine etme yöntemi.

Collector Terminolojisi

Collector Configurable pipeline’lar aracılığıyla telemetri verisini alıp işleyip export eden vendor-agnostic proxy.

Receiver Çeşitli protokoller (OTLP, Jaeger, Zipkin, Prometheus) aracılığıyla telemetri verisini kabul eden collector component’i.

Processor Telemetri verisini transform eden collector component’i (batching, filtering, attribute modification, sampling).

Exporter İşlenmiş telemetriyi observability backend’lerine gönderen collector component’i.

Pipeline Collector’daki receiver’lar, processor’lar ve exporter’lar aracılığıyla configure edilmiş telemetri flow’u.

OTLP (OpenTelemetry Protocol) Telemetri verisini transmit etmek için native protokol. gRPC (port 4317) ve HTTP (port 4318) destekler.

Sampling Terminolojisi

Sampling İstatistiksel önemi korurken sadece trace’lerin bir subset’ini tutarak telemetri volume’ünü azaltma tekniği.

Head-Based Sampling Complete trace’i görmeden trace root’ta verilen sampling kararı. Basit ama intelligent kararlar veremez.

Tail-Based Sampling Trace tamamlandıktan sonra verilen sampling kararı, trace karakteristiklerine (error’lar, latency) dayalı intelligent sampling’i mümkün kılar.

Sampling Rate Tutulan trace’lerin yüzdesi. 0.1, trace’lerin %10’unun sample edildiği anlamına gelir.

Sampler Configure edilmiş stratejiye dayalı sampling kararları veren component.

Semantic Convention Terminolojisi

Semantic Convention’lar Interoperability sağlayan attribute’lar, metrikler ve resource attribute’ları için standardize edilmiş isimlendirme convention’ları.

Resource Attribute’ları Telemetri kaynağını tanımlayan attribute’lar (service adı, version, environment, cloud provider).

Attribute Namespace İlgili attribute’ları gruplayan prefix (http.*, db.*, messaging.*).

Span Kind Span’in trace’teki rolünü tanımlayan kategori: INTERNAL, SERVER, CLIENT, PRODUCER, CONSUMER.

API ve SDK Terminolojisi

API Implementation’ı prescribe etmeden telemetri generate etmenin nasıl yapılacağını tanımlayan language-specific interface’ler.

SDK Telemetri generate etmek ve export etmek için gerçek functionality sağlayan API specification’ın implementation’ı.

TracerProvider Tracer’ları oluşturmak için factory, exporter’lar, sampler’lar ve processor’larla configure edilir.

Tracer Belirli bir instrumentation scope içinde span’leri oluşturmak için interface (library veya service).

MeterProvider Metrik kaydetmek için kullanılan meter’ları oluşturmak için factory.

Meter Metrik instrument’ları (counter’lar, gauge’lar, histogram’lar) oluşturmak için interface.

Resource Resource attribute’larla tanımlanan telemetri üreten entity’nin immutable temsili.

Propagator Trace context’ini boundary’ler arasında inject etmekten ve extract etmekten sorumlu component.

Yaygın Kısaltmalar

OTel - OpenTelemetry OTLP - OpenTelemetry Protocol CNCF - Cloud Native Computing Foundation APM - Application Performance Monitoring SLI - Service Level Indicator SLO - Service Level Objective MTTR - Mean Time To Resolution MTTD - Mean Time To Detection RED - Rate, Errors, Duration (key metrikler) DAG - Directed Acyclic Graph W3C - World Wide Web Consortium

Sonraki Adımlar ve Kaynaklar

Önerilen Öğrenme Yolu

  1. Local environment’ı kur Experimentation için Docker Compose kullanarak OpenTelemetry Collector ve Jaeger deploy et

  2. Sample bir service’i instrument et Hemen sonuç görmek için Node.js veya Python’da auto-instrumentation ile başla

  3. Manual instrumentation ekle Manual instrumentation pattern’lerini anlamak için business logic için custom span’ler oluştur

  4. Staging’e deploy et Realistic traffic ile collector configuration’ı ve sampling stratejilerini test et

  5. Correlation implement et Log’lara trace_id ekle ve trace’lerden metrikler generate et

  6. Production’a roll out yap Non-critical service’lerle başlayarak incremental olarak deploy et

Official Kaynaklar

Dokümantasyon:

Community:

Öğrenme:

Önerilen Backend’ler

Open Source:

  • Jaeger - Distributed tracing odaklı
  • Grafana Tempo - Scalable trace storage
  • Prometheus - Metrik monitoring
  • SigNoz - Unified observability platform

Commercial:

  • Datadog - Comprehensive observability
  • Honeycomb - Query-driven exploration
  • New Relic - Full-stack observability
  • Lightstep - Enterprise tracing

Sonuç

OpenTelemetry, dağıtık sistemlerde observability için endüstri standardı yaklaşımı sağlıyor. Auto-instrumentation implement ederek, collector’ları deploy ederek, semantic convention’ları takip ederek ve signal’leri correlate ederek, debugging’i saatler süren investigation’lardan dakikalara dönüştüren derin sistem görünürlüğü elde edersin.

Bir service ile başla, yaklaşımı validate et ve incremental olarak genişlet. Setup ve öğrenmedeki initial investment, daha hızlı incident resolution, önlenen outage’lar ve gelişmiş sistem anlayışı sayesinde kendini geri öder.

OpenTelemetry ile çalışmak bana observability’nin mümkün olan tüm veriyi toplamakla ilgili olmadığını gösterdi - doğru veriyi, doğru zamanda, doğru context ile toplamakla ilgili. Burada açıklanan framework’ler ve pattern’ler bu foundation’ı sağlıyor.

OpenTelemetry ecosystem’i yeni instrumentation library’leriyle, enhanced collector capability’leriyle ve expanded semantic convention’larla evrim geçirmeye devam ediyor. Bugün OpenTelemetry’ye yatırım yapmak, observability’nin geleceğine yatırım yapmak demek - vendor-neutral, standards-based ve community-driven bir gelecek.

İlgili yazılar

Metriklerin Ötesinde Observability: Sistem Hikaye Anlatıcılığı Sanatı

Yeşil ışıklarla dolu dashboard'lardan, dağıtık izleme ve AI destekli analiz ile sistem davranışı, kullanıcı yolculukları ve iş etkisi hakkında etkileyici hikayeler anlatan observability sistemlerine geçiş

observabilitymonitoringdistributed-tracing+5
Production Sistemleri için Prompt Engineering: Sistematik Bir Mühendislik Yaklaşımı

Kurumsal LLM uygulamaları için production-grade prompt engineering sistemleri oluşturmak üzerine kapsamlı bir teknik rehber: sistematik tasarım, güvenlik, observability ve maliyet optimizasyonu.

prompt-engineeringllmai-development+6
AI Agent Güvenliği: Production Sistemler için Guardrail'ler ve Defense Pattern'leri

Production ortamında AI agent'ları güvenli hale getirmek için AWS Bedrock Guardrails, defense-in-depth stratejileri ve prompt injection, tool misuse ve multi-agent saldırılarını önlemeye yönelik pratik implementasyon pattern'leri rehberi.

ai-agentsaws-bedrocksecurity+5
Custom MCP Server Geliştirme: Production-Ready Kılavuz

TypeScript ile organizasyonunuzun internal sistemleri için custom Model Context Protocol serverları nasıl geliştirip, güvenli hale getirip, deploy edeceğinizi öğren. Authentication, monitoring ve Kubernetes deployment örnekleriyle.

typescriptmcpnodejs+5
LangChain Production'da: Çalışan Patternler ve İşe Yaramayan Anti-Patternler

LangChain uygulamalarını production'a taşırken öğrendiklerim. Başarısızlığa yol açan anti-patternler, başarıyı sağlayan patternler, çalışan kod örnekleri ve maliyet optimizasyon stratejileri.

langchainllmproduction+5