
observability
by srstomp
An orchestration plugin for Claude Code that enables reliable autonomous development sessions with configurable checkpoints and task management.
SKILL.md
name: observability description: Implement logging, metrics, tracing, and alerting for production applications. Covers structured logging (Pino, Winston), metrics (Prometheus, DataDog, CloudWatch), distributed tracing (OpenTelemetry), and alert design. Use this skill when adding logging to services, setting up monitoring, creating alerts, debugging production issues, or designing SLIs/SLOs. Triggers on "logging", "monitoring", "alerting", "observability", "metrics", "tracing", "debug production", "correlation id", "structured logging", "dashboards", "SLI", "SLO".
Observability
Implement the three pillars of observability: logs, metrics, and traces.
The Three Pillars
| Pillar | Purpose | Key Question |
|---|---|---|
| Logs | Discrete events with context | What happened? |
| Metrics | Aggregated measurements | How much/many? |
| Traces | Request flow across services | Where did time go? |
Quick pick:
- Need to debug specific request? → Logs + Traces
- Need to alert on thresholds? → Metrics
- Need to understand system health? → All three
- Starting from zero? → Logs first, then metrics, then traces
Logging Fundamentals
Log Level Selection
FATAL → System is unusable, immediate action required
ERROR → Operation failed, needs attention soon
WARN → Unexpected but recoverable, investigate later
INFO → Significant business events, state changes
DEBUG → Detailed diagnostic info (never in prod default)
TRACE → Most granular, function-level (dev only)
Decision guide:
| Situation | Level | Example |
|---|---|---|
| Payment succeeded | INFO | { level: 'info', event: 'payment_completed', amount: 50 } |
| Payment retry needed | WARN | { level: 'warn', event: 'payment_retry', attempt: 2 } |
| Payment failed | ERROR | { level: 'error', event: 'payment_failed', code: 'DECLINED' } |
| Database connection lost | FATAL | { level: 'fatal', event: 'db_connection_lost' } |
Structured Logging Pattern
// ✅ Good: Structured, searchable
logger.info({
event: 'order_created',
orderId: '123',
userId: 'user_456',
amount: 99.99,
duration_ms: 45
});
// ❌ Bad: String concatenation
logger.info(`Order 123 created for user user_456 with amount 99.99`);
Required fields for every log:
timestamp(ISO 8601)level(string)messageorevent(what happened)correlation_id(request tracing)
Contextual fields (when applicable):
user_id,tenant_id(who)duration_ms(how long)error.message,error.stack(what went wrong)
Quick Setup: Pino (Recommended)
import pino from 'pino';
const logger = pino({
level: process.env.LOG_LEVEL || 'info',
formatters: {
level: (label) => ({ level: label }),
},
timestamp: pino.stdTimeFunctions.isoTime,
redact: ['req.headers.authorization', 'password', 'ssn'],
});
// Request-scoped logging
app.use((req, res, next) => {
req.log = logger.child({
correlationId: req.headers['x-correlation-id'] || crypto.randomUUID(),
method: req.method,
path: req.path,
});
next();
});
Sensitive Data Handling
Never log:
- Passwords, API keys, tokens
- PII (SSN, credit cards, full DOB)
- Session tokens, JWTs (log sub claim only)
- Full request bodies with sensitive fields
Redaction pattern:
const logger = pino({
redact: {
paths: ['password', '*.password', 'req.headers.authorization', 'creditCard'],
censor: '[REDACTED]'
}
});
Metrics Fundamentals
Metric Types
| Type | Use Case | Example |
|---|---|---|
| Counter | Things that only increase | http_requests_total |
| Gauge | Current value, can go up/down | active_connections |
| Histogram | Distribution of values | request_duration_seconds |
| Summary | Pre-calculated percentiles | request_duration_p99 |
The Four Golden Signals
┌─────────────────────────────────────────────────────────────┐
│ Four Golden Signals │
├──────────────┬──────────────┬──────────────┬───────────────┤
│ Latency │ Traffic │ Errors │ Saturation │
│ How fast? │ How much? │ How often? │ How full? │
├──────────────┼──────────────┼──────────────┼───────────────┤
│ p50, p95, │ req/sec │ error_rate │ CPU, memory │
│ p99 latency │ concurrent │ 5xx count │ queue depth │
└──────────────┴──────────────┴──────────────┴───────────────┘
Essential metrics for any service:
// Latency
const httpDuration = new Histogram({
name: 'http_request_duration_seconds',
help: 'Duration of HTTP requests',
labelNames: ['method', 'route', 'status_code'],
buckets: [0.01, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10]
});
// Traffic
const httpRequests = new Counter({
name: 'http_requests_total',
help: 'Total HTTP requests',
labelNames: ['method', 'route', 'status_code']
});
// Errors
const httpErrors = new Counter({
name: 'http_errors_total',
help: 'Total HTTP errors',
labelNames: ['method', 'route', 'error_type']
});
// Saturation
const activeConnections = new Gauge({
name: 'active_connections',
help: 'Number of active connections'
});
Naming Conventions
<namespace>_<name>_<unit>
✅ http_request_duration_seconds
✅ database_query_total
✅ cache_hit_ratio
✅ queue_messages_pending
❌ requestTime (no unit, camelCase)
❌ db-queries (hyphens)
❌ numRequests (abbreviations)
Label guidelines:
- Use labels for dimensions you'll filter/group by
- Keep cardinality low (< 1000 unique combinations)
- Never use high-cardinality values as labels (user IDs, request IDs)
Alerting Principles
Alert Quality Matrix
Fires Appropriately
↑
No │ Yes
│
┌─────────────────┼─────────────────┐
│ │ │
Low │ Broken Alert │ Noisy Alert │ High
Noise │ (silent fail) │ (tune down) │ Noise
│ │ │
├─────────────────┼─────────────────┤
│ │ │
│ Good Alert │ Perfect Alert │
│ (but rare?) │ (goal) │
│ │ │
└─────────────────┴─────────────────┘
Actionability →
Alert Design Rules
-
Page only for user-facing impact
- Revenue loss
- Complete feature unavailability
- Data integrity issues
-
Every alert needs a runbook
- What does this alert mean?
- How do I investigate?
- What are the fix options?
-
Alert fatigue = alert failure
- If it pages >5x/week without action → fix or delete
- Group related alerts
- Use escalation tiers
SLI/SLO Basics
SLI (Service Level Indicator): Measurable metric SLO (Service Level Objective): Target for the SLI Error Budget: How much "failure" is acceptable
Common SLIs:
- Availability: successful_requests / total_requests
- Latency: p99_response_time < threshold
- Error rate: errors / total_requests
Example SLO:
- "99.9% of requests complete successfully"
- "p99 latency < 200ms"
Alert Severity Levels
| Level | Response Time | Criteria | Channel |
|---|---|---|---|
| P1 Critical | Immediate | User-facing outage, data loss | PagerDuty + phone |
| P2 High | < 4 hours | Degraded service, partial outage | PagerDuty + Slack |
| P3 Medium | < 24 hours | Non-critical issues, single user | Slack only |
| P4 Low | Best effort | Warnings, approaching limits | Dashboard |
Tracing Fundamentals
Distributed Tracing Concepts
Request Flow:
┌────────────┐ ┌────────────┐ ┌────────────┐
│ API GW │ → │ Service A │ → │ Service B │
│ Span 1 │ │ Span 2 │ │ Span 3 │
└────────────┘ └────────────┘ └────────────┘
↓
┌────────────┐
│ Database │
│ Span 4 │
└────────────┘
Trace = Collection of all spans for one request
Span = Single unit of work with timing
Correlation IDs
Implementation pattern:
// Generate at entry point (API gateway, load balancer)
const correlationId = req.headers['x-correlation-id'] || crypto.randomUUID();
// Propagate to all downstream calls
const response = await fetch('http://service-b/api', {
headers: { 'x-correlation-id': correlationId }
});
// Include in all logs
logger.info({ correlationId, event: 'request_received' });
Header standards:
x-correlation-id(common)x-request-id(also common)traceparent(W3C standard for distributed tracing)
OpenTelemetry Quick Start
import { NodeSDK } from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
const sdk = new NodeSDK({
traceExporter: new OTLPTraceExporter({
url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
}),
instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();
Production Debugging Workflow
1. Identify the symptom
└─→ Alert fired? Error spike? User report?
2. Find correlation ID
└─→ From error tracking, user report, or API response header
3. Search logs with correlation ID
└─→ Follow the request path
4. Check metrics dashboard
└─→ When did it start? What changed?
5. Examine traces (if available)
└─→ Which service/span is slow or failing?
6. Form hypothesis and verify
└─→ Check code, config, dependencies
7. Fix and verify
└─→ Deploy fix, confirm resolution
Log Analysis Patterns
# Find all errors in last hour (structured logs in JSON)
cat app.log | jq 'select(.level == "error")' | head -20
# Group errors by type
cat app.log | jq 'select(.level == "error") | .error.type' | sort | uniq -c | sort -rn
# Find specific correlation ID
cat app.log | jq 'select(.correlationId == "abc-123")'
# Calculate error rate
echo "scale=4; $(grep -c '"level":"error"' app.log) / $(wc -l < app.log)" | bc
Anti-Patterns
❌ Logging Everything
// BAD: Too verbose, costs money
logger.debug({ req: req.body, res: res.body, headers: req.headers });
// GOOD: Log what you need
logger.info({ event: 'api_request', path: req.path, status: res.statusCode });
❌ Alert on Every Error
# BAD: Alerts on transient errors
alert: AnyErrorOccurred
expr: http_errors_total > 0
# GOOD: Alert on sustained error rate
alert: HighErrorRate
expr: rate(http_errors_total[5m]) / rate(http_requests_total[5m]) > 0.01
for: 5m # Must persist for 5 minutes
❌ High-Cardinality Labels
// BAD: Millions of unique combinations
httpRequests.inc({ userId: user.id, requestId: req.id });
// GOOD: Bounded cardinality
httpRequests.inc({ userTier: user.tier, route: req.route });
❌ Missing Context in Logs
// BAD: No way to trace
logger.error('Payment failed');
// GOOD: Full context for debugging
logger.error({
event: 'payment_failed',
correlationId,
userId,
paymentId,
error: { message: err.message, code: err.code }
});
Integration Points
With CI/CD (ci-cd-expert):
- Deployment markers in metrics
- Log version/commit hash
- Canary metrics for deployment validation
With error tracking (Sentry):
- Link traces to error events
- Breadcrumbs from structured logs
- User context propagation
With incident management:
- Alert → PagerDuty/OpsGenie
- Runbook links in alerts
- Post-incident metrics analysis
Skill Usage
Adding logging to a service:
- Install Pino or Winston
- Read references/logging-patterns.md
- Implement request-scoped logging with correlation IDs
- Configure redaction for sensitive fields
Setting up monitoring:
- Identify the four golden signals for your service
- Read references/metrics-guide.md
- Instrument with Prometheus/DataDog/CloudWatch
- Create dashboards for key metrics
Creating alerts:
- Define SLIs and SLOs
- Read references/alerting-guide.md
- Create runbooks for each alert
- Generate ohno tasks for alert implementation
Adding distributed tracing:
- Implement correlation ID propagation
- Read references/tracing-basics.md
- Set up OpenTelemetry if needed
Debugging production issues:
- Follow the debugging workflow above
- Use correlation IDs to trace requests
- Correlate logs, metrics, and traces
References:
- references/logging-patterns.md — Pino/Winston setup, structured logging, log aggregation
- references/metrics-guide.md — Prometheus, DataDog, CloudWatch, dashboard patterns
- references/alerting-guide.md — Alert design, runbook templates, SLI/SLO deep dive
- references/tracing-basics.md — OpenTelemetry setup, Jaeger, trace analysis
Score
Total Score
Based on repository quality metrics
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
3ヶ月以内に更新がある
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
Reviews
Reviews coming soon