L’interface est localisée ; les présentations et documents des Skills sont traduits automatiquement par IA dans votre langue. Le code, les commandes, chemins et termes techniques restent en version originale, et le document de l’auteur fait foi.
Explorer les Skills
Design et création · SKILL.md

observability

observability

Use this skill when the user says 'observability', 'logging', 'metrics', 'tracing', 'OpenTelemetry', 'Grafana', 'Prometheus', 'structured logs', 'distributed tracing', 'monitoring', or when setting up observability for a service. Covers: three pillars (logs, metrics, traces), structured JSON logging, OpenTelemetry SDK setup per stack, SLO/SLI/SLA definition…

Independent GitHub snapshot · Automated classification · Original documentation governs

Documentation de la Skill

GitHub

name: observability description: > Use this skill when the user says 'observability', 'logging', 'metrics', 'tracing', 'OpenTelemetry', 'Grafana', 'Prometheus', 'structured logs', 'distributed tracing', 'monitoring', or when setting up observability for a service. Covers: three pillars (logs, metrics, traces), structured JSON logging, OpenTelemetry SDK setup per stack, SLO/SLI/SLA definitions, and alert design (alert on symptoms, not causes). Works with any language/stack. Do NOT use this for: infrastructure monitoring, database performance, or frontend analytics. version: "1.0.0" author: "j4flmao" license: "MIT" compatibility: claude-code: true cursor: true codex: true windsurf: true tags: [devops, observability, phase-5]

Observability

Purpose

Set up structured logging, metrics, and distributed tracing to understand system behavior in production.

Agent Protocol

Trigger

Exact user phrases: "observability", "logging", "metrics", "tracing", "OpenTelemetry", "Grafana", "Prometheus", "structured logs", "distributed tracing", "monitoring".

Input Context

Before activating, verify:

  • The stack is known (for OpenTelemetry SDK selection).
  • The existing observability tooling is understood (Prometheus, Grafana, etc.).
  • The traffic volume is known (for trace sampling strategy).

Output Artifact

No file output. This skill produces an observability plan.

Response Format

Observability plan: logging format, metrics list, trace sampling strategy, SLOs, alert rules.

No preamble. No postamble. No explanations. No filler/hedging/transitions. Compress output — why use many token when few do trick. No explanation of why observability is important.

Completion Criteria

This skill is complete when:

  • Structured JSON logging format is defined with required fields.
  • Key metrics are listed (counters, gauges, histograms).
  • Trace sampling strategy is specified.
  • SLOs are defined with SLIs.
  • Alert rules follow symptom-based (not cause-based) design.

Max Response Length

40 lines.

Quick Start

Three pillars: logs (what happened), metrics (how often/how much), traces (where it happened). Use JSON structured logging. OpenTelemetry for traces. Alert on symptoms (user impact), not causes.

Decision Tree: Observability Strategy

  • New microservice, no existing observability → Structured JSON logs + RED metrics + OpenTelemetry traces at 10% sampling
  • Existing service with basic monitoring → Add distributed tracing, define SLOs, implement burn-rate alerts
  • High-traffic service (>10k req/s) → Tail-based sampling, cardinality management, log sampling
  • Compliance-heavy environment (PCI/HIPAA) → Structured logging with PII redaction, audit trails, trace sampling + attribute filtering
  • Serverless/event-driven → Distributed context propagation, structured logs with correlation IDs, metrics on function duration

Logging vs Metrics vs Traces Decision

What do you need to understand?
├── What happened? → Logs (structured, searchable, correlated)
├── How often / how much? → Metrics (counters, gauges, histograms)
├── Where did it happen in the request path? → Traces (span tree, timing)
└── All three → OpenTelemetry SDK + log correlation (traceId in logs)

Sampling Strategy Decision

What is the request rate?
├── < 100 req/s → 100% sampling (cheap enough to keep everything)
├── 100-1000 req/s → 10% head-based probabilistic
├── 1000-10000 req/s → 1% head-based + tail-based for errors/slow
└── > 10000 req/s → Rate-limited (100 traces/sec) + tail-based for errors

Core Workflow

Step 1: Structured Logging

// GOOD — structured JSON
{
  "level": "error",
  "message": "Payment processing failed",
  "service": "order-service",
  "traceId": "abc123",
  "userId": "user-456",
  "orderId": "order-789",
  "error": {
    "type": "PaymentTimeoutError",
    "message": "Payment gateway timeout after 30s",
    "stack": "..."
  },
  "duration_ms": 30042,
  "timestamp": "2026-05-14T10:30:00Z"
}

// BAD — unstructured text: "Error processing order: something went wrong"

Required fields: level, message, service, timestamp, traceId Context fields: userId, orderId, requestId, duration_ms

Step 2: Metrics — RED Method (for services)

MetricTypeExample
RateCounterhttp_requests_total{method, path, status}
ErrorsCounterhttp_requests_errors_total{method, path, status}
DurationHistogramhttp_request_duration_seconds{method, path}

Step 3: Metrics — USE Method (for infrastructure)

MetricTypeExample
UtilizationGaugecpu_usage_ratio, memory_usage_bytes
SaturationGaugequeue_depth, disk_io_wait_seconds
ErrorsCounterdisk_io_errors_total, network_drops_total

Step 4: Key Metrics for Every Service

# Request rate
sum(rate(http_requests_total[5m])) by (service, method, path)

# Error rate
sum(rate(http_requests_total{status=~"5.."}[5m])) by (service)

# Latency p99
histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, service))

# Active requests
sum(http_requests_active) by (service)

# SLO burn rate
(
  sum(rate(http_requests_total{status!~"5.."}[1h]))
  /
  sum(rate(http_requests_total[1h]))
)

Step 5: Prometheus Recording Rules

groups:
- name: service_slos
  interval: 30s
  rules:
  - record: service:error_rate_5m
    expr: |
      sum(rate(http_requests_total{status=~"5.."}[5m])) by (service)
      /
      sum(rate(http_requests_total[5m])) by (service)

  - record: service:latency_p99_5m
    expr: |
      histogram_quantile(0.99,
        sum(rate(http_request_duration_seconds_bucket[5m])) by (service, le)
      )

  - record: service:availability_30d
    expr: |
      sum(rate(http_requests_total{status!~"5.."}[30d])) by (service)
      /
      sum(rate(http_requests_total[30d])) by (service)

Step 6: SLO Burn Rate Alerts

groups:
- name: slo_alerts
  rules:
  - alert: HighErrorRate
    expr: |
      (
        sum(rate(http_requests_total{status=~"5.."}[1h])) by (service)
        /
        sum(rate(http_requests_total[1h])) by (service)
      ) > 0.001  # 99.9% SLO
    for: 5m
    labels:
      severity: page
      slo: 99.9
    annotations:
      summary: "Error rate above SLO budget for {{ $labels.service }}"
      description: "Error rate {{ $value | humanizePercentage }} exceeds SLO threshold"

  - alert: BurnRateTooFast
    expr: |
      (
        sum(rate(http_requests_total{status!~"5.."}[1h])) by (service)
        /
        sum(rate(http_requests_total[1h])) by (service)
      ) < 0.999
      and on(service)
      (
        sum(rate(http_requests_total{status!~"5.."}[5m])) by (service)
        /
        sum(rate(http_requests_total[5m])) by (service)
      ) < 0.99
    labels:
      severity: page
    annotations:
      summary: "SLO burn rate too fast for {{ $labels.service }}"

Step 7: Distributed Tracing with Sampling

StrategySampling RateUse Case
Head-based probabilistic1-10%High-traffic services
Tail-basedKeep errors + slowProduction critical paths
Rate limiting100 traces/secBudget-constrained
Consistent probability10% per serviceMulti-service trace correlation
// OpenTelemetry Node.js SDK with sampling
import { NodeSDK } from '@opentelemetry/sdk-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';
import { ParentBasedSampler, TraceIdRatioBasedSampler } from '@opentelemetry/sdk-trace-node';

const sdk = new NodeSDK({
  traceExporter: new OTLPTraceExporter({ url: 'http://otel-collector:4317' }),
  sampler: new ParentBasedSampler({
    root: new TraceIdRatioBasedSampler(0.1), // 10% sampling
  }),
});

Step 8: Log Aggregation with Loki

scrape_configs:
- job_name: kubernetes-pods
  kubernetes_sd_configs:
  - role: pod
  relabel_configs:
  - source_labels: [__meta_kubernetes_pod_label_app]
    action: keep
    regex: myapp
  - action: labelmap
    regex: __meta_kubernetes_pod_label_(.+)
  pipeline_stages:
  - json:
      expressions:
        level: level
        service: service
        traceId: traceId
        duration_ms: duration_ms
  - labels:
      level:
      service:
  - drop:
      expression: ".*healthcheck.*"

Step 9: Grafana Dashboard Variables

{
  "templating": {
    "list": [
      {
        "name": "service",
        "type": "query",
        "query": "label_values(up, service)"
      },
      {
        "name": "environment",
        "type": "query",
        "query": "label_values(up{service=\"$service\"}, environment)"
      }
    ]
  },
  "panels": [
    {
      "title": "Request Rate",
      "type": "timeseries",
      "targets": [{
        "expr": "sum(rate(http_requests_total{service=\"$service\"}[5m])) by (status)",
        "legendFormat": "{{ status }}"
      }]
    },
    {
      "title": "Latency p99",
      "type": "timeseries",
      "targets": [{
        "expr": "histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket{service=\"$service\"}[5m])) by (le))",
        "legendFormat": "p99"
      }]
    }
  ]
}

Step 10: Structured Logging per Language

# Python
import structlog
structlog.configure(
    processors=[
        structlog.stdlib.filter_by_level,
        structlog.stdlib.add_log_level,
        structlog.processors.TimeStamper(fmt="iso"),
        structlog.processors.JSONRenderer()
    ],
    context_class=dict,
    logger_factory=structlog.PrintLoggerFactory(),
)
log = structlog.get_logger()
log.info("order.placed", order_id="ord-123", amount=99.99)
// Go with slog
import "log/slog"
slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
    Level: slog.LevelInfo,
})))
slog.Info("payment processed",
    "order_id", "ord-123",
    "amount", 99.99,
    "trace_id", traceID)
// Java with Logback + structured layout
// logback.xml
<appender name="JSON" class="ch.qos.logback.core.ConsoleAppender">
  <encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
</appender>

Step 11: Cardinality Management

# Prometheus metrics with bounded cardinality
# BAD: label with unbounded values (user_id, email, request_id)
http_requests_total{method="GET", path="/api/users/:id", status="200", user_id="user-123"}

# GOOD: label with bounded values (method, path template, status)
http_requests_total{method="GET", path="/api/users/{id}", status="200"}

# Relabeling in Prometheus
metric_relabel_configs:
- source_labels: [path]
  regex: '/api/users/[^/]+'
  replacement: '/api/users/{id}'
  target_label: path

Step 12: OpenTelemetry Collector Configuration

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

processors:
  batch:
    timeout: 1s
    send_batch_size: 1024
  memory_limiter:
    check_interval: 1s
    limit_mib: 512
  attributes:
    actions:
      - key: environment
        value: production
        action: upsert
  filter:
    error_mode: ignore
    traces:
      span:
        - 'attributes["http.target"] == "/health"'

exporters:
  prometheus:
    endpoint: 0.0.0.0:8889
  otlp:
    endpoint: jaeger:4317
    tls:
      insecure: true
  loki:
    endpoint: http://loki:3100/loki/api/v1/push

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, batch, attributes, filter]
      exporters: [otlp]
    metrics:
      receivers: [otlp]
      processors: [memory_limiter, batch, attributes]
      exporters: [prometheus]
    logs:
      receivers: [otlp]
      processors: [memory_limiter, batch, attributes]
      exporters: [loki]

Step 13: Business Metrics — Custom Instrumentation

# metrics/business_metrics.py
from prometheus_client import Counter, Histogram, Gauge
import time

# Business counters
orders_created = Counter('orders_created_total', 'Total orders created', ['region', 'currency'])
orders_cancelled = Counter('orders_cancelled_total', 'Orders cancelled', ['reason'])
payment_success = Counter('payment_success_total', 'Successful payments', ['provider'])
payment_failed = Counter('payment_failed_total', 'Failed payments', ['provider', 'error_code'])

# Business histograms
order_value = Histogram('order_value_dollars', 'Order value distribution',
                         buckets=[10, 25, 50, 100, 250, 500, 1000, 2500, 5000])
checkout_duration = Histogram('checkout_duration_seconds', 'Checkout flow duration',
                               buckets=[1, 2, 5, 10, 30, 60, 120])

# Business gauges
active_users = Gauge('active_users', 'Currently active users', ['tier'])
cart_abandonment = Gauge('cart_abandonment_rate', 'Cart abandonment rate')

def track_order(region, currency, value):
    orders_created.labels(region=region, currency=currency).inc()
    order_value.observe(value)

def track_checkout(user_id, duration):
    checkout_duration.observe(duration)
    # Example: track user in business context
    active_users.layers(tier='premium').inc()

Step 14: SLO Definition Template

# slo-definitions.yaml
slos:
  - name: "API Availability"
    sli: "ratio of successful requests to total requests"
    measurement: "sum(rate(http_requests_total{status!~\"5..\"}[5m])) / sum(rate(http_requests_total[5m]))"
    target: 99.9%
    window: 30d
    burn_rate_alerts:
      - window: 1h
        threshold: 2x  # Exhaust SLO budget in 15 days
      - window: 5m
        threshold: 10x  # Exhaust SLO budget in 3 days

  - name: "API Latency"
    sli: "P99 response time"
    measurement: "histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, service))"
    target: "< 500ms"
    window: 30d

  - name: "API Throughput"
    sli: "requests per second"
    measurement: "sum(rate(http_requests_total[5m]))"
    target: ">= 100 req/s at P99"
    window: 7d

Step 15: Observability Maturity Model

LevelLogsMetricsTracesAlerts
1: CrawlUnstructured, grep-basedCPU/memory onlyNoneBasic threshold
2: WalkStructured JSON, aggregatedRED method per serviceHead-based samplingSymptom-based
3: RunCorrelation IDs, PII redactedUSE + RED + business metricsTail-based + consistentSLO burn-rate
4: FlyAuto-instrumented, real-timeCustom business metrics100% error tracesPredictive ML-based

Tool Comparison: Observability Platforms

FeatureGrafana + Prometheus + LokiDatadogNew RelicHoneycomb
LogsLoki (OSS, S3-backed)Log ManagementLogsLog integration
MetricsPrometheus (OSS, pull)Datadog AgentNRDBCustom events
TracesTempo (OSS)APMDistributed TracingEvents (no spans)
SLOsGrafana SLO appSLO managementSLOsSLOs
CostOSS (infra cost only)$$ (per host + data)$$ (per GB)$$ (per event)
CardinalityLimited by TSDBHigh (no limit)HighUnlimited
Best forOSS-first, K8s-nativeAll-in-one, ease of useFull-stack observabilityDebugging, high-cardinality
Self-hostedYesNoNoNo

Security Considerations

  • Never log credentials, tokens, PII, or PCI data — use log scrubbing / redaction pipelines
  • OpenTelemetry collector should run in a trusted network zone with mTLS for gRPC
  • Grafana authentication via OAuth/OIDC — never share dashboards publicly
  • Loki log retention must comply with data privacy requirements (GDPR: 30d default)
  • Trace attributes may contain sensitive query parameters — filter in OTel collector
  • Prometheus remote write should use TLS + basic auth or mTLS
  • Audit log access: who viewed what, when, and from where
  • Rate-limit Grafana query API to prevent denial of service via expensive queries
  • Encrypt Prometheus TSDB at rest if storing on persistent volumes

Production Considerations

  • Set log retention: 7-30 days for standard, 90+ days for audit compliance.
  • Configure log sampling for high-volume services (1:10 or 1:100).
  • Use recording rules to pre-compute expensive PromQL queries.
  • Set up SLO burn-rate alerts (multi-window, multi-burn-rate) for faster detection.
  • Implement log-based metrics for business-level indicators.
  • Use Exemplars to correlate metrics with traces.
  • Monitor observability pipeline itself: collector queue depth, export latency.
  • Set up silent test alerts to verify alert pipeline end-to-end weekly.
  • Use aggregation windows appropriate to pager load: 5m for paging, 15m for dashboards.
  • Configure OTel collector memory limiter to prevent OOM on traffic spikes.
  • Use metric_relabel_configs to drop high-cardinality labels before ingestion.
  • Set up Prometheus max_samples_per_send to prevent rejected remote write batches.
  • Tiered storage: hot (SSD) for 7d, warm (HDD) for 30d, cold (S3) for 90d+.

Anti-Patterns

  • Alerting on CPU/memory — these are causes, not symptoms of user impact.
  • Unstructured logging — can't parse, filter, or correlate without regex hacks.
  • No traceId in logs — impossible to correlate logs with traces.
  • Over-sampling traces — unnecessary cost and storage.
  • High cardinality metric labels — Prometheus performance degrades.
  • No SLOs — no target for reliability, no basis for paging decisions.
  • Dashboard per service instead of templated dashboards — maintenance burden.
  • Alert fatigue from flapping alerts — tune for, tolerance before paging.
  • Logging PII — compliance violation, potential data breach.
  • Not testing alert configuration — alert fires but notification fails.

References

  • references/alerting-strategies.md — Alerting Strategies
  • references/custom-metrics.md — Custom Metrics
  • references/log-aggregation.md — Log Aggregation
  • references/observability-advanced.md — Observability Advanced Topics
  • references/observability-fundamentals.md — Observability Fundamentals
  • references/observability-maturity.md — Observability Maturity Model
  • references/otel-guide.md — OpenTelemetry Setup per Stack

Handoff

After completing this skill:

  • Next skill: performance-profiler — using observability data to find bottlenecks
  • Pass context: logging format, metrics configuration, trace sampling rate
Skills enregistrées