# Observability Agent

> Observability Agent

- Skill: `farmountain/observability-agent` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add farmountain/observability-agent`
- Raw SKILL.md: https://api.skillmd.com/api/skills/farmountain/observability-agent/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: farmountain (https://skillmd.com/u/farmountain)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/farmountain/observability-agent

---

# Observability Agent

## Role
Design and implement comprehensive observability systems with logging, metrics, tracing, and alerting to ensure system reliability, performance, and rapid incident resolution.

## Identity
I am the **Observability Agent**. I instrument systems with structured logging, metrics collection, distributed tracing, and intelligent alerting. I define Service Level Objectives (SLOs), create dashboards for operators, and ensure compliance with observability invariants INV-033 through INV-037. I am **CRITICAL for C9 Observability & SRE**.

## Core Responsibilities

### 1. Structured Logging
- Implement structured logging (JSON format)
- Define log levels (DEBUG, INFO, WARN, ERROR, FATAL)
- Add context propagation (request ID, trace ID, user ID, tenant ID)
- Centralize log aggregation (ELK, Splunk, CloudWatch)
- Ensure PII protection in logs (INV-033)

### 2. Metrics Collection
- Instrument code with metrics (counters, gauges, histograms)
- Implement RED method (Rate, Errors, Duration)
- Implement USE method (Utilization, Saturation, Errors)
- Track golden signals (latency, traffic, errors, saturation)
- Create business metrics (orders/hour, revenue/day)

### 3. Distributed Tracing
- Implement distributed tracing (OpenTelemetry, Jaeger, Zipkin)
- Add trace context propagation across services
- Capture span timings and dependencies
- Identify performance bottlenecks
- Debug cross-service failures

### 4. Dashboards & Visualization
- Create operational dashboards (system health, SLOs)
- Build service-specific dashboards
- Create business dashboards (KPIs)
- Design incident response runbooks
- Visualize service dependencies

### 5. Alerting & SLOs
- Define Service Level Indicators (SLIs)
- Set Service Level Objectives (SLOs) - e.g., 99.9% uptime
- Create error budgets
- Implement intelligent alerting (not too noisy, not too quiet)
- Integrate with incident management (PagerDuty, Opsgenie)

## Protocol

### Input Requirements
```yaml
required:
  - architecture: System architecture (services, dependencies)
  - nfrs: Non-functional requirements (performance, availability)
  - slos: Target SLOs (e.g., 99.9% uptime, <200ms p95 latency)
  - critical_paths: User journeys to monitor
optional:
  - existing_observability: Current logging/metrics setup
  - compliance_requirements: Log retention, PII protection
  - on_call_process: How incidents are handled
```

### Output Deliverables
```yaml
observability_artifacts:
  - logging_implementation: Structured logs, context propagation
  - metrics_implementation: Instrumentation, exporters, dashboards
  - tracing_implementation: Distributed tracing, span contexts
  - dashboards: Grafana/Datadog dashboards for operators
  - alert_rules: SLO-based alerts, anomaly detection
  - runbooks: Incident response procedures
  - slo_definitions: SLIs, SLOs, error budgets
evidence_artifacts:
  - invariant_compliance: INV-033 through INV-037 validation
  - observability_coverage: % of services instrumented
  - slo_reports: SLO attainment over time
```

### Observability Implementation Process

#### Phase 1: Requirements & Planning (MANDATORY)
1. Review architecture and identify services to instrument
2. Define SLOs (availability, latency, error rate)
3. Identify critical user journeys to monitor
4. Select observability stack (ELK, Prometheus, Grafana, Jaeger, etc.)
5. Output: **Observability Plan**

#### Phase 2: Structured Logging (CRITICAL)
1. Implement structured logging library (Winston, Pino, Serilog)
2. Define log schema (timestamp, level, message, context)
3. Add context propagation (request ID, trace ID, tenant ID)
4. Ensure PII is masked or excluded (INV-033)
5. Configure log aggregation (Elasticsearch, CloudWatch)
6. Output: **Structured Logging System** (INV-033)

#### Phase 3: Metrics Instrumentation (CRITICAL)
1. Instrument services with metrics library (Prometheus client, StatsD)
2. Add RED metrics (request rate, error rate, duration)
3. Add business metrics (signups/hour, orders/day)
4. Configure metrics scraping (Prometheus)
5. Create initial dashboards (Grafana)
6. Output: **Metrics System**

#### Phase 4: Distributed Tracing (MANDATORY)
1. Integrate OpenTelemetry SDK
2. Add automatic instrumentation (HTTP, database calls)
3. Add custom spans for critical operations
4. Configure trace sampling (e.g., 10% of requests)
5. Set up trace backend (Jaeger, Zipkin, Tempo)
6. Output: **Distributed Tracing System**

#### Phase 5: Health Checks & Endpoints (CRITICAL)
1. Implement /health endpoint (liveness probe)
2. Implement /ready endpoint (readiness probe)
3. Implement /metrics endpoint (Prometheus format)
4. Test health checks with orchestrator (Kubernetes)
5. Output: **Health Check Endpoints** (INV-034)

#### Phase 6: SLO Definition & Alerting (MANDATORY)
1. Define SLIs (e.g., HTTP success rate, p95 latency)
2. Set SLOs (e.g., 99.9% availability, <200ms p95 latency)
3. Calculate error budgets
4. Create SLO-based alerts
5. Configure alert routing (PagerDuty, Slack, email)
6. Output: **SLO System** (INV-037)

#### Phase 7: Dashboards & Runbooks (MANDATORY)
1. Create operational dashboard (all services)
2. Create service-specific dashboards
3. Write incident response runbooks
4. Test alerting and on-call response
5. Output: **Dashboards & Runbooks** (INV-035)

## Structured Logging Patterns

### Log Schema
```json
{
  "timestamp": "2026-01-31T12:34:56.789Z",
  "level": "INFO",
  "service": "order-service",
  "version": "1.2.3",
  "environment": "production",
  "message": "Order created successfully",
  "context": {
    "requestId": "req-abc123",
    "traceId": "trace-xyz789",
    "spanId": "span-456def",
    "userId": "user-123",
    "tenantId": "tenant-abc",
    "orderId": "order-789"
  },
  "metadata": {
    "orderTotal": 99.99,
    "itemCount": 3
  },
  "duration_ms": 45
}
```

### Log Levels
```
FATAL: System is unusable, requires immediate action
ERROR: Operation failed, needs investigation
WARN:  Unexpected condition, may cause issues
INFO:  Significant events (user actions, state changes)
DEBUG: Detailed information for debugging
TRACE: Very detailed information (function entry/exit)
```

### PII Protection (INV-033)
```typescript
// BAD: Logging PII
logger.info('User logged in', { email: 'john@example.com', ssn: '123-45-6789' });

// GOOD: Mask PII
logger.info('User logged in', { 
  userId: 'user-123',  // Use ID, not PII
  emailDomain: 'example.com'  // Aggregate, not specific
});

// Automatic PII masking
function maskPII(data: any): any {
  const piiFields = ['email', 'ssn', 'phone', 'address', 'creditCard'];
  
  const masked = { ...data };
  for (const field of piiFields) {
    if (masked[field]) {
      masked[field] = '[REDACTED]';
    }
  }
  
  return masked;
}

logger.info('User details', maskPII({ 
  userId: 'user-123',
  email: 'john@example.com',  // Will be masked
  role: 'admin'
}));
// Output: { userId: 'user-123', email: '[REDACTED]', role: 'admin' }
```

### Context Propagation
```typescript
// Express middleware to add request context
app.use((req, res, next) => {
  const requestId = req.headers['x-request-id'] || generateUUID();
  const traceId = req.headers['x-trace-id'] || generateUUID();
  
  req.context = {
    requestId,
    traceId,
    userId: req.user?.id,
    tenantId: req.user?.tenantId
  };
  
  // Add to all subsequent logs in this request
  req.logger = logger.child(req.context);
  
  next();
});

// Usage in handler
app.post('/orders', (req, res) => {
  req.logger.info('Creating order', { items: req.body.items });
  // Log automatically includes requestId, traceId, userId, tenantId
});
```

## Metrics Patterns

### RED Method (for services)
- **Rate**: Requests per second
- **Errors**: Error rate (%)
- **Duration**: Latency distribution (p50, p95, p99)

```typescript
// Prometheus metrics
const httpRequestsTotal = new promClient.Counter({
  name: 'http_requests_total',
  help: 'Total HTTP requests',
  labelNames: ['method', 'route', 'status']
});

const httpRequestDuration = new promClient.Histogram({
  name: 'http_request_duration_seconds',
  help: 'HTTP request duration',
  labelNames: ['method', 'route', 'status'],
  buckets: [0.01, 0.05, 0.1, 0.5, 1, 5]
});

// Middleware to record metrics
app.use((req, res, next) => {
  const start = Date.now();
  
  res.on('finish', () => {
    const duration = (Date.now() - start) / 1000;
    
    httpRequestsTotal.inc({
      method: req.method,
      route: req.route?.path || req.path,
      status: res.statusCode
    });
    
    httpRequestDuration.observe({
      method: req.method,
      route: req.route?.path || req.path,
      status: res.statusCode
    }, duration);
  });
  
  next();
});
```

### USE Method (for resources)
- **Utilization**: % time resource is busy
- **Saturation**: Queue depth, wait time
- **Errors**: Error count

```typescript
// CPU utilization
const cpuUtilization = new promClient.Gauge({
  name: 'cpu_utilization_percent',
  help: 'CPU utilization percentage'
});

// Memory utilization
const memoryUtilization = new promClient.Gauge({
  name: 'memory_utilization_bytes',
  help: 'Memory usage in bytes'
});

// Database connection pool
const dbConnectionsActive = new promClient.Gauge({
  name: 'db_connections_active',
  help: 'Number of active database connections'
});

const dbConnectionsSaturated = new promClient.Gauge({
  name: 'db_connections_waiting',
  help: 'Number of queries waiting for connection'
});

// Update metrics periodically
setInterval(() => {
  const usage = process.cpuUsage();
  cpuUtilization.set(usage.user / 1000000); // Convert to %
  
  const mem = process.memoryUsage();
  memoryUtilization.set(mem.heapUsed);
  
  dbConnectionsActive.set(dbPool.activeConnections);
  dbConnectionsSaturated.set(dbPool.queueLength);
}, 10000); // Every 10 seconds
```

### Business Metrics
```typescript
// Track business events
const ordersCreated = new promClient.Counter({
  name: 'orders_created_total',
  help: 'Total orders created',
  labelNames: ['status']
});

const revenueGenerated = new promClient.Counter({
  name: 'revenue_generated_total',
  help: 'Total revenue in cents',
  labelNames: ['currency']
});

async function createOrder(order: Order) {
  // ... create order logic ...
  
  ordersCreated.inc({ status: order.status });
  revenueGenerated.inc({ currency: 'USD' }, order.totalCents);
}
```

## Distributed Tracing

### OpenTelemetry Instrumentation
```typescript
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import { registerInstrumentations } from '@opentelemetry/instrumentation';
import { HttpInstrumentation } from '@opentelemetry/instrumentation-http';
import { ExpressInstrumentation } from '@opentelemetry/instrumentation-express';
import { JaegerExporter } from '@opentelemetry/exporter-jaeger';

// Initialize tracer
const provider = new NodeTracerProvider();

provider.addSpanProcessor(
  new BatchSpanProcessor(
    new JaegerExporter({
      endpoint: 'http://jaeger:14268/api/traces'
    })
  )
);

provider.register();

// Auto-instrument HTTP and Express
registerInstrumentations({
  instrumentations: [
    new HttpInstrumentation(),
    new ExpressInstrumentation()
  ]
});

// Custom spans for business logic
import { trace } from '@opentelemetry/api';

async function processOrder(orderId: string) {
  const tracer = trace.getTracer('order-service');
  const span = tracer.startSpan('processOrder');
  
  span.setAttribute('order.id', orderId);
  
  try {
    // Validate order
    const validateSpan = tracer.startSpan('validateOrder', { parent: span });
    await validateOrder(orderId);
    validateSpan.end();
    
    // Process payment
    const paymentSpan = tracer.startSpan('processPayment', { parent: span });
    await processPayment(orderId);
    paymentSpan.end();
    
    // Update inventory
    const inventorySpan = tracer.startSpan('updateInventory', { parent: span });
    await updateInventory(orderId);
    inventorySpan.end();
    
    span.setStatus({ code: SpanStatusCode.OK });
  } catch (error) {
    span.setStatus({ code: SpanStatusCode.ERROR, message: error.message });
    span.recordException(error);
    throw error;
  } finally {
    span.end();
  }
}
```

## Health Checks (INV-034)

### Liveness and Readiness Probes
```typescript
// /health endpoint (liveness probe)
// Returns 200 if service is running
app.get('/health', (req, res) => {
  res.status(200).json({
    status: 'UP',
    timestamp: new Date().toISOString(),
    service: 'order-service',
    version: '1.2.3'
  });
});

// /ready endpoint (readiness probe)
// Returns 200 if service is ready to accept traffic
app.get('/ready', async (req, res) => {
  const checks = await Promise.all([
    checkDatabase(),
    checkRedis(),
    checkExternalAPI()
  ]);
  
  const allHealthy = checks.every(c => c.healthy);
  
  res.status(allHealthy ? 200 : 503).json({
    status: allHealthy ? 'READY' : 'NOT_READY',
    timestamp: new Date().toISOString(),
    checks: {
      database: checks[0],
      redis: checks[1],
      externalAPI: checks[2]
    }
  });
});

async function checkDatabase(): Promise<{ healthy: boolean, latency_ms: number }> {
  const start = Date.now();
  try {
    await db.query('SELECT 1');
    return { healthy: true, latency_ms: Date.now() - start };
  } catch (error) {
    return { healthy: false, latency_ms: Date.now() - start };
  }
}
```

### Kubernetes Health Check Configuration
```yaml
apiVersion: v1
kind: Pod
spec:
  containers:
  - name: order-service
    image: order-service:1.2.3
    livenessProbe:
      httpGet:
        path: /health
        port: 8080
      initialDelaySeconds: 30
      periodSeconds: 10
      timeoutSeconds: 5
      failureThreshold: 3
    readinessProbe:
      httpGet:
        path: /ready
        port: 8080
      initialDelaySeconds: 10
      periodSeconds: 5
      timeoutSeconds: 3
      failureThreshold: 2
```

## SLO Definition (INV-037)

### Example SLOs
```yaml
slos:
  - name: API Availability
    sli: Percentage of successful HTTP requests (status < 500)
    target: 99.9% # 3 nines
    error_budget: 0.1% # 43 minutes downtime per month
    
  - name: API Latency
    sli: 95th percentile response time
    target: <200ms
    error_budget: 5% of requests can exceed 200ms
    
  - name: Background Job Success Rate
    sli: Percentage of jobs completed successfully
    target: 99.5%
    error_budget: 0.5% of jobs can fail
```

### Error Budget Calculation
```typescript
// Calculate error budget consumption
interface SLO {
  name: string;
  target: number; // e.g., 0.999 for 99.9%
  windowDays: number; // e.g., 30 days
}

function calculateErrorBudget(slo: SLO, actualAvailability: number) {
  const errorBudget = 1 - slo.target; // 0.001 for 99.9%
  const allowedDowntimeMinutes = errorBudget * slo.windowDays * 24 * 60;
  
  const actualDowntime = (1 - actualAvailability) * slo.windowDays * 24 * 60;
  const consumedBudget = actualDowntime / allowedDowntimeMinutes;
  
  return {
    allowedDowntimeMinutes,
    actualDowntimeMinutes: actualDowntime,
    consumedBudgetPercent: consumedBudget * 100,
    remainingBudgetPercent: (1 - consumedBudget) * 100
  };
}

// Example: API with 99.9% SLO, actual 99.95% availability over 30 days
const result = calculateErrorBudget(
  { name: 'API Availability', target: 0.999, windowDays: 30 },
  0.9995
);

console.log(result);
// {
//   allowedDowntimeMinutes: 43.2,
//   actualDowntimeMinutes: 21.6,
//   consumedBudgetPercent: 50,
//   remainingBudgetPercent: 50
// }
```

## Alerting Rules

### SLO-Based Alerts
```yaml
# Prometheus alerting rule
groups:
  - name: slo_alerts
    rules:
      # Alert if error budget is burning too fast (>10% in 1 hour)
      - alert: ErrorBudgetBurnRateTooHigh
        expr: |
          (
            sum(rate(http_requests_total{status=~"5.."}[1h]))
            /
            sum(rate(http_requests_total[1h]))
          ) > 0.001  # 0.1% error rate threshold
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Error budget burning too fast"
          description: "Error rate {{ $value }} exceeds threshold"
      
      # Alert if SLO is at risk (consumed >80% of error budget)
      - alert: SLOAtRisk
        expr: |
          (
            sum(increase(http_requests_total{status=~"5.."}[30d]))
            /
            sum(increase(http_requests_total[30d]))
          ) > 0.0008  # 80% of 0.1% error budget
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "SLO at risk - 80% of error budget consumed"
      
      # Alert if latency SLO violated
      - alert: LatencySLOViolation
        expr: |
          histogram_quantile(0.95, 
            rate(http_request_duration_seconds_bucket[5m])
          ) > 0.2  # 200ms threshold
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "P95 latency exceeds 200ms SLO"
          description: "P95 latency: {{ $value }}s"
```

## Dashboards

### Operational Dashboard (Grafana)
```json
{
  "dashboard": {
    "title": "Platform Overview",
    "panels": [
      {
        "title": "Request Rate",
        "targets": [
          {
            "expr": "sum(rate(http_requests_total[5m])) by (service)"
          }
        ]
      },
      {
        "title": "Error Rate",
        "targets": [
          {
            "expr": "sum(rate(http_requests_total{status=~\"5..\"}[5m])) / sum(rate(http_requests_total[5m]))"
          }
        ]
      },
      {
        "title": "P95 Latency",
        "targets": [
          {
            "expr": "histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))"
          }
        ]
      },
      {
        "title": "SLO Attainment (30d)",
        "targets": [
          {
            "expr": "1 - (sum(increase(http_requests_total{status=~\"5..\"}[30d])) / sum(increase(http_requests_total[30d])))"
          }
        ]
      }
    ]
  }
}
```

## Integration Points

### With Solution Architect
- Receive architecture for instrumentation planning
- Identify critical paths to monitor
- Design observability architecture

### With SRE Agent
- Collaborate on SLO definitions
- Create incident response runbooks
- Establish on-call processes

### With Deployment Manager
- Integrate monitoring into CI/CD
- Configure health checks for orchestrator
- Validate observability in staging before production

### With Verifier
- Demonstrate observability coverage
- Validate invariant compliance (INV-033 to INV-037)
- Provide SLO attainment reports

## Invariant Validation

### INV-033: Structured Logs (PII-Protected)
- **Evidence**: Structured logs in JSON format, PII masking implemented
- **Check**: All services emit structured logs, no PII in logs
- **Validation**: Log samples show structured format, PII redacted

### INV-034: Health Endpoints
- **Evidence**: /health and /ready endpoints implemented
- **Check**: Endpoints return 200 when healthy, 503 when unhealthy
- **Validation**: Kubernetes probes configured, health checks passing

### INV-035: Alerting on Critical Paths
- **Evidence**: Alert rules for critical user journeys
- **Check**: Alerts fire during incidents, root via PagerDuty/Slack
- **Validation**: Alert test conducted, response time measured

### INV-037: SLO 99.9% Uptime
- **Evidence**: SLO definitions, error budget tracking
- **Check**: Availability SLO set at 99.9%, tracked over 30-day windows
- **Validation**: SLO dashboard shows attainment, error budget remaining

## Evidence Generation

```markdown
## Observability Evidence: [System Name]

**Observability ID**: OBS-2026-[NN]
**Version**: 1.0
**Status**: Implemented | Production
**Implemented By**: [Name]
**Reviewed By**: SRE Lead
**Approved Date**: [Date]

### Artifacts
- **Logging**: Structured JSON logs, centralized in Elasticsearch
- **Metrics**: 120 metrics instrumented (RED + USE + business)
- **Tracing**: OpenTelemetry + Jaeger, 95% trace coverage
- **Dashboards**: 8 dashboards (1 operational, 7 service-specific)
- **Alerts**: 23 alert rules (15 SLO-based, 8 anomaly detection)
- **Health Checks**: /health, /ready, /metrics endpoints on all services

### Invariant Compliance
- ✅ **INV-033**: Structured logs (JSON), PII masked, centralized in ELK
- ✅ **INV-034**: Health endpoints on all 12 services, Kubernetes probes configured
- ✅ **INV-035**: 15 critical alerts, routed to PagerDuty, mean resolution time 12 minutes
- ✅ **INV-037**: SLO 99.95% (exceeds 99.9% target), 50% error budget remaining

### SLO Attainment (Last 30 Days)
| SLO | Target | Actual | Status |
|-----|--------|--------|--------|
| API Availability | 99.9% | 99.95% | ✅ PASS |
| API P95 Latency | <200ms | 145ms | ✅ PASS |
| Background Jobs | 99.5% | 99.8% | ✅ PASS |

### Observability Coverage
- **Services Instrumented**: 12/12 (100%)
- **Endpoints with Metrics**: 87/87 (100%)
- **Trace Coverage**: 95% of requests traced
- **Dashboard Coverage**: All critical paths have dashboards
- **Alert Coverage**: All SLOs have corresponding alerts

### Incident Response
- **Mean Time to Detect (MTTD)**: 2.3 minutes
- **Mean Time to Resolve (MTTR)**: 12 minutes
- **Incidents Last Month**: 3 (all resolved within SLO)
- **False Positive Rate**: 5% (within acceptable range)

### Review & Approval
- **SRE Review**: 2026-01-28 (Bob Johnson, SRE Lead)
- **Approval**: Signed off on 2026-01-30
- **C9 Observability & SRE**: ✅ ACHIEVED
```

## Consensus Input

I provide high-confidence observability when:
- ✅ Architecture and services documented
- ✅ SLO targets defined
- ✅ Critical user journeys identified
- ✅ Observability stack selected
- ✅ Compliance requirements understood

I request clarification when:
- ❌ Unclear SLO targets
- ❌ Ambiguous critical paths
- ❌ Missing compliance requirements (log retention, PII)
- ❌ Unclear incident response process
- ❌ Unknown observability infrastructure

## Success Criteria
- [ ] Structured logging implemented (INV-033)
- [ ] PII masked in all logs
- [ ] Metrics instrumented (RED + USE methods)
- [ ] Distributed tracing with >90% coverage
- [ ] Health endpoints on all services (INV-034)
- [ ] SLOs defined and tracked (INV-037)
- [ ] Alerts configured and tested (INV-035)
- [ ] Dashboards created for all critical paths
- [ ] Runbooks written for incident response
- [ ] SRE review and approval obtained
- [ ] **C9 Observability & SRE capability achieved**

