Monitoring Operations

SkillMonitoring & ops

Observability patterns - metrics, logging, tracing, alerting, and infrastructure monitoring. Use for: monitoring, observability, prometheus, grafana, metrics, alerting, structured logging, distributed tracing, opentelemetry, SLO, SLI, dashboard, health check, loki, jaeger, datadog, pagerduty.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Monitoring Operations skill

What this skill tells your AI

The instructions your AI receives, as published by 0xdarkmatter/claude-mods in skills/monitoring-ops/SKILL.md and read by ahel’s review.

Comprehensive observability patterns covering the three pillars (metrics, logging, tracing), alerting strategies, dashboard design, and infrastructure monitoring for production systems.


Three Pillars Quick Reference

Use this table to decide which observability signal fits your need:

PillarBest ForToolsData Type
MetricsAggregated numeric measurements, trends, alerting on thresholdsPrometheus, Datadog, CloudWatch, StatsDTime-series (numeric)
LogsDiscrete events, error details, audit trails, debugging contextLoki, ELK, CloudWatch Logs, FluentdUnstructured/structured text
TracesRequest flow across services, latency breakdown, dependency mappingJaeger, Tempo, Zipkin, Datadog APMSpan trees (structured)

When to use which:

  • "How many requests per second?" → Metrics (counter + rate)
  • "Why did this specific request fail?" → Logs (error message + stack trace)
  • "Where is the latency in this request?" → Traces (span waterfall)
  • "Is the system healthy right now?" → Metrics (gauges + alerts)
  • "What happened at 3:42 AM?" → Logs (timestamped event search)
  • "Which downstream service caused the timeout?" → Traces (span analysis)

Correlation is key: Connect all three by embedding trace_id in log entries, recording exemplars in metrics, and linking trace spans to log queries.


Metrics Type Decision Tree

Use this tree to select the correct metric type:

What are you measuring?
│
├─ A count of events that only goes up?
│  └─ COUNTER
│     Examples: http_requests_total, errors_total, bytes_sent_total
│     Use rate() or increase() to get per-second or per-interval values
│     Never use a counter's raw value — it resets on restart
│
├─ A current value that goes up AND down?
│  └─ GAUGE
│     Examples: temperature_celsius, active_connections, queue_depth
│     Use for snapshots of current state
│     Can use avg_over_time(), max_over_time() for trends
│
├─ A distribution of values (latency, size)?
│  │
│  ├─ Need aggregatable quantiles across instances?
│  │  └─ HISTOGRAM
│  │     Examples: http_request_duration_seconds, response_size_bytes
│  │     Define buckets: [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10]
│  │     Use histogram_quantile() for percentiles (p50, p95, p99)
│  │     Aggregatable across instances (histograms can be summed)
│  │
│  └─ Need pre-calculated quantiles on a single instance?
│     └─ SUMMARY
│        Examples: go_gc_duration_seconds
│        Pre-calculates quantiles client-side
│        NOT aggregatable across instances
│        Prefer histogram unless you have a specific reason
│
└─ None of the above?
   └─ INFO metric (labels only, value=1)
      Examples: build_info{version="1.2.3", commit="abc123"}
      Use for metadata exposed as metrics

Rule of thumb: Start with counters and histograms. Add gauges for current state. Avoid summaries unless you have a compelling reason.


Alerting Decision Tree

What type of alert do you need?
│
├─ Known threshold with a fixed boundary?
│  └─ THRESHOLD-BASED
│     Example: CPU > 90% for 5 minutes
│     Pros: Simple, predictable, easy to understand
│     Cons: Requires manual tuning, doesn't adapt to patterns
│     Best for: Resource limits, error rate spikes, queue depth
│
├─ Normal behavior varies by time/season?
│  └─ ANOMALY-BASED
│     Example: Traffic 3 standard deviations below normal for this hour
│     Pros: Adapts to patterns, catches novel failures
│     Cons: Noisy during transitions, requires training data
│     Best for: Traffic patterns, business metrics, gradual degradation
│
└─ Defined reliability targets?
   └─ SLO-BASED (PREFERRED)
      Example: Error budget burn rate > 14.4x for 1 hour
      Pros: Aligned with user impact, reduces noise, principled
      Cons: Requires SLI/SLO definition, more complex setup
      Best for: User-facing services, platform reliability

Severity Levels

SeverityResponseExamplesRouting
Critical (P1)Page on-call immediatelyService down, data loss risk, security breachPagerDuty high-urgency, phone call
Warning (P2)Investigate within hoursElevated error rate, disk 80% full, SLO burn rate elevatedPagerDuty low-urgency, Slack alert channel
Info (P3)Review next business dayDeployment completed, certificate expiring in 30 daysSlack info channel, ticket auto-created

When to Page vs When to Ticket

Page (wake someone up) when:

  • Users are currently impacted
  • Data loss is occurring or imminent
  • Security incident is active
  • Error budget will be exhausted within hours

Create ticket (don't page) when:

  • Issue is not user-facing yet
  • Automated remediation is possible
  • Degradation is slow and has runway
  • Issue is during business hours and can be triaged normally

Structured Logging Quick Reference

Standard JSON Log Format

{
  "timestamp": "2026-03-09T14:32:01.123Z",
  "level": "ERROR",
  "message": "Failed to process payment",
  "service": "payment-api",
  "version": "1.4.2",
  "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
  "span_id": "00f067aa0ba902b7",
  "request_id": "req-abc123",
  "user_id": "usr-789",
  "error": {
    "type": "PaymentGatewayTimeout",
    "message": "Gateway response timeout after 30s",
    "stack": "..."
  },
  "duration_ms": 30042,
  "http": {
    "method": "POST",
    "path": "/api/v1/payments",
    "status_code": 504
  }
}

Log Level Decision Guide

LevelWhen to UseExamples
DEBUGDevelopment only, verbose internal stateVariable values, SQL queries, cache hits/misses
INFONormal operations worth recordingRequest completed, job started/finished, config loaded
WARNDegraded but still functioningRetry succeeded, fallback used, approaching limit
ERROROperation failed, needs attentionPayment failed, API call error, constraint violation
FATALProcess cannot continue, must exitDatabase unreachable at startup, invalid config, OOM

Rules:

  • Never log at ERROR for expected conditions (user input validation → WARN)
  • Every ERROR should be actionable — if no one will act on it, use WARN
  • DEBUG should be off in production by default
  • INFO should not be noisy — 1-5 log lines per request, not 50

Correlation IDs

  • Generate a request_id (UUID v4 or ULID) at the edge/gateway
  • Propagate through all internal services via headers (X-Request-ID)
  • Include trace_id and span_id from distributed tracing
  • Log all three IDs in every log entry for cross-referencing

Distributed Tracing Quick Reference

Core Concepts

  • Trace: End-to-end journey of a request across all services
  • Span: A single unit of work (HTTP call, DB query, function execution)
  • Context propagation: Passing trace/span IDs between services via headers

W3C TraceContext Header

traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
              │  │                                  │                  │
              │  │                                  │                  └─ flags (01=sampled)
              │  │                                  └─ parent span ID (16 hex)
              │  └─ trace ID (32 hex)
              └─ version (00)

Sampling Strategies

StrategyHow It WorksUse When
Head-based (ratio)Decide at trace start, propagate decisionLow traffic, need predictable volume
Always-onSample everythingDevelopment, low-traffic services
Parent-basedFollow parent's sampling decisionDefault for most services
Tail-basedDecide after trace completes (at Collector)Need error/slow traces, high traffic

Recommendation: Use parent-based + tail-based at the Collector. This captures all error traces and slow traces while controlling volume.

Trace ID in Logs

Always include trace_id in structured log entries. This enables jumping from a log line to the full trace view:

Log entry → trace_id → Jaeger/Tempo → full request waterfall

Tool Selection Matrix

FeaturePrometheus + GrafanaDatadogGrafana CloudCloudWatch
CostFree (infra costs)$$$$ (per host/metric)$$ (usage-based)$$ (AWS-native)
Setup complexityHigh (self-managed)Low (SaaS agent)Medium (managed)Low (AWS-native)
MetricsPrometheus (excellent)Built-in (excellent)Mimir (excellent)Built-in (good)
LogsLoki (good)Built-in (excellent)Loki (good)CloudWatch Logs (good)
TracesJaeger/Tempo (good)APM (excellent)Tempo (good)X-Ray (adequate)
AlertingAlertmanager (good)Built-in (excellent)Grafana Alerting (good)CloudWatch Alarms (adequate)
DashboardsGrafana (excellent)Built-in (excellent)Grafana (excellent)Dashboards (adequate)
RetentionConfigurable (unlimited)15 months defaultConfigurableUp to 15 months
Multi-cloudYesYesYesAWS only
Best forCost-conscious, controlFull-featured, enterpriseOpen-source + managedAWS-native shops

Recommendation path:

  • Starting out / budget-conscious: Prometheus + Grafana + Loki + Tempo (all free, self-hosted)
  • Small team, want managed: Grafana Cloud free tier (10k metrics, 50GB logs, 50GB traces)
  • Enterprise, need everything: Datadog (expensive but comprehensive)
  • AWS-only shop: CloudWatch + X-Ray (simplest if already on AWS)

Dashboard Design

USE Method (Infrastructure)

For every resource (CPU, memory, disk, network):

SignalQuestionMetric Example
UtilizationHow busy is it?node_cpu_seconds_total (% busy)
SaturationHow overloaded is it?node_load1 (run queue length)
ErrorsAre there error events?node_network_receive_errs_total

RED Method (Services)

For every service endpoint:

SignalQuestionMetric Example
RateHow many requests per second?rate(http_requests_total[5m])
ErrorsHow many are failing?rate(http_requests_total{status=~"5.."}[5m])
DurationHow long do they take?histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))

Four Golden Signals (Google SRE)

SignalWhat to MeasureAlert Threshold Guidance
LatencyTime to serve a request (distinguish success vs error latency)p99 > 2x baseline
TrafficDemand on the system (requests/sec, sessions, transactions)Anomaly detection
ErrorsRate of failed requests (explicit 5xx, implicit policy violations)> 0.1% of traffic
SaturationHow "full" the service is (CPU, memory, queue depth)> 80% capacity

Dashboard Layout Best Practices

  1. Top row: Key health indicators (error rate, latency p99, availability %)
  2. Second row: Traffic and throughput (requests/sec, active users)
  3. Third row: Resource utilization (CPU, memory, disk, network)
  4. Bottom rows: Detailed breakdowns (by endpoint, by status code, by region)
  5. Use variables: Service, environment, time range as dropdown selectors
  6. Include annotations: Deployments, incidents, config changes as vertical markers

Common Gotchas

GotchaWhy It HappensFix
Cardinality explosionUsing unbounded label values (user ID, request path, query string)Use bounded labels only; aggregate high-cardinality data in logs, not metrics
Alert fatigueToo many alerts, too sensitive thresholds, alerts on non-actionable symptomsRequire runbook for every alert; tune thresholds; use SLO-based alerting
Missing correlation IDsLogs, metrics, and traces not linked togetherInclude trace_id in all log entries; use exemplars in metrics
Sampling biasHead-based sampling drops error/slow traces at high sample ratesUse tail-based sampling at the Collector to always capture errors and slow traces
Log volume costsDEBUG or verbose INFO in production, logging full request/response bodiesSet production to INFO minimum; truncate large payloads; use sampling for verbose paths
Metric naming inconsistencyDifferent teams use different naming conventionsAdopt OpenMetrics naming: namespace_subsystem_unit_suffix (e.g., http_server_request_duration_seconds)
Dashboard sprawlEveryone creates dashboards, nobody maintains themStandardize with USE/RED templates; review quarterly; delete unused dashboards
SLO too aggressiveSetting 99.99% availability without the budget or architecture for itStart with 99.5% or 99.9%; tighten only when consistently meeting targets with margin
Missing baselineAlerting on absolute thresholds without understanding normal behaviorCollect 2-4 weeks of baseline data before setting alert thresholds
Over-instrumentationInstrumenting every function, creating too many spans/metricsInstrument at service boundaries; use auto-instrumentation for HTTP/DB/gRPC; add manual spans selectively
Ignoring metric stalenessAssuming a metric that stops reporting means zeroUse absent() or up == 0 to detect missing scrapers; distinguish "zero" from "not reporting"
Alerting on cause not symptomAlerting on CPU usage instead of user-facing error rateAlert on symptoms (error rate, latency); use cause metrics (CPU, memory) for investigation
No retention policyStoring all metrics/logs at full resolution foreverDefine retention tiers: 15s resolution for 2 weeks, 1m for 3 months, 5m for 1 year
Dashboard without contextGraphs with no units, no description, no threshold linesAdd units to Y-axis, threshold lines for SLOs, panel descriptions explaining what "good" looks like

Reference Files

FileContentsLines
metrics-alerting.mdPrometheus, Grafana, OpenTelemetry metrics, SLI/SLO/SLA, alert routing, runbooks, uptime monitoring~650
logging.mdStructured logging, log levels, correlation IDs, aggregation (Loki, ELK), retention, PII masking, language-specific~550
tracing.mdOpenTelemetry, spans, context propagation, sampling, Jaeger, async tracing, DB/HTTP/gRPC instrumentation~600
infrastructure.mdHealth checks, K8s probes, Docker HEALTHCHECK, infra metrics, APM, cost optimization, incident response~550

See Also

Signals

GitHub stars
36
Forks
5
Last commit
Aug 2026
Advanced
Catalog kind
skill
Gateway key
monitoring-ops
Source
github.com/0xdarkmatter/claude-mods