Powrót do strony głównej

OpenTelemetry stos Go: Tempo Prometheus Loki

Artykuł opisuje wdrożenie stosu OpenTelemetry dla aplikacji Go z Tempo, Prometheus i Loki. Podano docker-compose, konfiguracje i kod Go inicjalizacji providerów. Integracja w Grafana zapewnia przejścia między metrykami, śladami i logami.

OTel stos dla Go: pełny przewodnik po wdrożeniu
Advertisement 728x90

Wdrażanie stosu OpenTelemetry dla Go: tracing, metryki i logi

Stos OpenTelemetry dla aplikacji Go zbiera tracing w Tempo, metryki w Prometheus i logi w Loki. Klient app-1 wysyła zapytania do serwera app-2 za pośrednictwem otel-collector. Grafana wizualizuje wszystkie dane. Pełny stos uruchamiany jest za pomocą docker-compose z minimalną konfiguracją.

Konfiguracja Docker Compose

Podstawowe serwisy: dwie aplikacje Go, otel-collector jako odbiornik telemetrii, backendy Tempo/Prometheus/Loki oraz Grafana. Sieć observability izoluje ruch.

Kluczowe porty:

Google AdInline article slot
  • app-2: 8080
  • otel-collector: 4317 (gRPC), 4318 (HTTP), 8889 (metrics)
  • Prometheus: 9090
  • Tempo: 3200
  • Loki: 3100
  • Grafana: 3000
services:
  app-1:
    build: ./app_1
    depends_on:
      otel-collector:
        condition: service_started
    networks:
      - observability
  app-2:
    build: ./app_2
    ports:
      - "8080:8080"
    networks:
      - observability
  otel-collector:
    image: otel/opentelemetry-collector-contrib:latest
    ports:
      - "4318:4318"
      - "4317:4317"
      - "8889:8889"
    volumes:
      - ./configs/otel-collector-config.yaml:/etc/otelcol/config.yaml:ro
    networks:
      - observability
  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./configs/prometheus.yml:/etc/prometheus/prometheus.yml:ro
    networks:
      - observability
  tempo:
    image: grafana/tempo:2.7.0
    ports:
      - "3200:3200"
    volumes:
      - ./configs/tempo-config.yaml:/etc/tempo/tempo.yaml
    networks:
      - observability
  loki:
    image: grafana/loki:3.3.2
    ports:
      - "3100:3100"
    volumes:
      - ./configs/loki-config.yaml:/etc/loki/local-config.yaml:ro
    networks:
      - observability
  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    volumes:
      - ./configs/grafana/datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml:ro
    networks:
      - observability
networks:
  observability:
    driver: bridge

Konfiguracja Tempo dla śledzenia

Tempo przyjmuje OTLP przez gRPC (4317) i HTTP (4318). Bloki śladów są kompaktowane z retencją 30m. Trace_idle_period 5s zapewnia szybką widoczność w interfejsie użytkownika.

server:
  http_listen_port: 3200
  grpc_listen_port: 9095
distributor:
  receivers:
    otlp:
      protocols:
        grpc:
          endpoint: "0.0.0.0:4317"
ingester:
  trace_idle_period: 5s
  max_block_duration: 30m
storage:
  trace:
    backend: local
    local:
      path: /var/tempo/traces
compactor:
  compaction:
    block_retention: 30m

Prometheus i reguły alertingu

Zbieranie metryk z otel-collector:8889 co 60s. Reguły alertów monitorują opóźnienie P95 > 2000ms oraz współczynnik błędów > 5%.

global:
  scrape_interval: 60s
scrape_configs:
  - job_name: "otel-collector"
    static_configs:
      - targets: ["otel-collector:8889"]

Przykładowe reguły:

Google AdInline article slot
groups:
  - name: app1-service-alerts
    rules:
      - alert: App1LatencyHigh
        expr: histogram_quantile(0.95, sum by (le) (rate(app_1_requests_latency_ms_bucket[5m]))) > 2000
        for: 3m
        labels:
          severity: warning
  - name: app2-service-alerts
    rules:
      - alert: App2HighErrorRate
        expr: rate(app_2_requests_total{status="failed"}[5m]) / rate(app_2_requests_total[5m]) > 0.05
        for: 2m
        labels:
          severity: critical

Konfiguracja Loki dla logów

Logi przechowywane są w filesystem z schematem TSDB v13. Indeksowanie w okresach 24-godzinnych. Structured metadata włączona.

auth_enabled: false
server:
  http_listen_port: 3100
common:
  path_prefix: /tmp/loki
  storage:
    filesystem:
      chunks_directory: /tmp/loki/chunks
schema_config:
  configs:
    - from: 2020-10-24
      store: tsdb
      schema: v13
      index:
        period: 24h
limits_config:
  allow_structured_metadata: true

Integracja w Grafana

Źródła danych łączą metryki→śledzenie→logi:

  • Prometheus exemplarTraceIdDestinations
  • Loki derivedFields według traceID
  • Tempo serviceMap i tracesToLogsV2

Inicjalizacja OTel w kliencie Go

Funkcja InitOTel tworzy provider'y dla wszystkich sygnałów z atrybutami zasobu. Sampling 10% dla śladów, batching dla eksportu.

Google AdInline article slot
func InitOTel(ctx context.Context, serviceName string) (*log.LoggerProvider, func(context.Context) error) {
    ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
    defer cancel()

    res := resource.NewWithAttributes(
       semconv.SchemaURL,
       semconv.ServiceName(serviceName),
       semconv.ServiceVersion("1.0.0"),
    )

    // Tracing
    traceExp, err := otlptracegrpc.New(ctx,
       otlptracegrpc.WithEndpoint("otel-collector:4317"),
       otlptracegrpc.WithInsecure(),
    )
    tracerProvider := sdktrace.NewTracerProvider(
       sdktrace.WithSampler(sdktrace.ParentBased(sdktrace.TraceIDRatioBased(0.1))),
       sdktrace.WithBatcher(traceExp),
       sdktrace.WithResource(res),
    )
    otel.SetTracerProvider(tracerProvider)

    // Metrics
    metricExp, err := otlpmetricgrpc.New(ctx,
       otlpmetricgrpc.WithEndpoint("otel-collector:4317"),
       otlpmetricgrpc.WithInsecure(),
    )
    meterProvider := sdkmetric.NewMeterProvider(
       sdkmetric.WithReader(sdkmetric.NewPeriodicReader(metricExp, sdkmetric.WithInterval(10*time.Second))),
       sdkmetric.WithResource(res),
    )
    otel.SetMeterProvider(meterProvider)

    // Logs
    logExp, _ := otlploggrpc.New(ctx,
       otlploggrpc.WithEndpoint("otel-collector:4317"),
       otlploggrpc.WithInsecure(),
    )
    logProvider := log.NewLoggerProvider(
       log.WithProcessor(log.NewBatchProcessor(logExp)),
       log.WithResource(res),
    )

    return logProvider, func(ctx context.Context) error {
       // shutdown logic
       return nil
    }
}

Co ważne

  • Pełny stos OTel: śledzenie (Tempo), metryki (Prometheus), logi (Loki) zintegrowane za pośrednictwem otel-collector
  • Instrumentacja Go: otelhttp.Transport, otelslog.Handler, metryki counter/histogram
  • Natywna integracja Grafana: przejścia metryki→śledzenie→logi według traceID
  • Wydajność: trace_idle_period 5s, sampling 10%, periodic reader 10s
  • Alerting: P95 latency > 2000ms, error rate > 5%

— Editorial Team

Advertisement 728x90

Czytaj dalej