Monitoring Expert
Observability and performance specialist implementing comprehensive monitoring, alerting, tracing, and performance testing systems.
Core Workflow
- Assess — Identify what needs monitoring (SLIs, critical paths, business metrics)
- Instrument — Add logging, metrics, and traces to the application (see examples below)
- Collect — Configure aggregation and storage (Prometheus scrape, log shipper, OTLP endpoint); verify data arrives before proceeding
- Visualize — Build dashboards using RED (Rate/Errors/Duration) or USE (Utilization/Saturation/Errors) methods
- Alert — Define threshold and anomaly alerts on critical paths; validate no false-positive flood before shipping
Quick-Start Examples
Structured Logging (Node.js / Pino)
import pino from 'pino';
const logger = pino({ level: 'info' });
// Good — structured fields, includes correlation ID
logger.info({ requestId: req.id, userId: req.user.id, durationMs: elapsed }, 'order.created');
// Bad — string interpolation, no correlation
console.log(`Order created for user ${userId}`);
Prometheus Metrics (Node.js)
import { Counter, Histogram, register } from 'prom-client';
const httpRequests = new Counter({
name: 'http_requests_total',
help: 'Total HTTP requests',
labelNames: ['method', 'route', 'status'],
});
const httpDuration = new Histogram({
name: 'http_request_duration_seconds',
help: 'HTTP request latency',
labelNames: ['method', 'route'],
buckets: [0.05, 0.1, 0.3, 0.5, 1, 2, 5],
});
// Instrument a route
app.use((req, res, next) => {
const end = httpDuration.startTimer({ method: req.method, route: req.path });
res.on('finish', () => {
httpRequests.inc({ method: req.method, route: req.path, status: res.statusCode });
end();
});
next();
});
// Expose scrape endpoint
app.get('/metrics', async (req, res) => {
res.set('Content-Type', register.contentType);
res.end(await register.metrics());
});
OpenTelemetry Tracing (Node.js)
import { NodeSDK } from '@opentelemetry/sdk-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { trace } from '@opentelemetry/api';
const sdk = new NodeSDK({
traceExporter: new OTLPTraceExporter({ url: 'http://jaeger:4318/v1/traces' }),
});
sdk.start();
// Manual span around a critical operation
const tracer = trace.getTracer('order-service');
async function processOrder(orderId) {
const span = tracer.startSpan('order.process');
span.setAttribute('order.id', orderId);
try {
const result = await db.saveOrder(orderId);
span.setStatus({ code: SpanStatusCode.OK });
return result;
} catch (err) {
span.recordException(err);
span.setStatus({ code: SpanStatusCode.ERROR });
throw err;
} finally {
span.end();
}
}
Prometheus Alerting Rule
groups:
- name: api.rules
rules:
- alert: HighErrorRate
expr: |
rate(http_requests_total{status=~"5.."}[5m])
/ rate(http_requests_total[5m]) > 0.05
for: 2m
labels:
severity: critical
annotations:
summary: "Error rate above 5% on {{ $labels.route }}"
k6 Load Test
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
stages: [
{ duration: '1m', target: 50 }, // ramp up
{ duration: '5m', target: 50 }, // sustained load
{ duration: '1m', target: 0 }, // ramp down
],
thresholds: {
http_req_duration: ['p(95)<500'], // 95th percentile < 500 ms
http_req_failed: ['rate<0.01'], // error rate < 1%
},
};
export default function () {
const res = http.get('https://api.example.com/orders');
check(res, { 'status is 200': (r) => r.status === 200 });
sleep(1);
}
Reference Guide
Load detailed guidance based on context:
| Topic |
Reference |
Load When |
| Logging |
references/structured-logging.md |
Pino, JSON logging |
| Metrics |
references/prometheus-metrics.md |
Counter, Histogram, Gauge |
| Tracing |
references/opentelemetry.md |
OpenTelemetry, spans |
| Alerting |
references/alerting-rules.md |
Prometheus alerts |
| Dashboards |
references/dashboards.md |
RED/USE method, Grafana |
| Performance Testing |
references/performance-testing.md |
Load testing, k6, Artillery, benchmarks |
| Profiling |
references/application-profiling.md |
CPU/memory profiling, bottlenecks |
| Capacity Planning |
references/capacity-planning.md |
Scaling, forecasting, budgets |
Constraints
MUST DO
- Use structured logging (JSON)
- Include request IDs for correlation
- Set up alerts for critical paths
- Monitor business metrics, not just technical
- Use appropriate metric types (counter/gauge/histogram)
- Implement health check endpoints
MUST NOT DO
- Log sensitive data (passwords, tokens, PII)
- Alert on every error (alert fatigue)
- Use string interpolation in logs (use structured fields)
- Skip correlation IDs in distributed systems
1---2name: monitoring-expert3description: Configures monitoring systems, implements structured logging pipelines, creates Prometheus/Grafana dashboards, defines alerting rules, and instruments distributed tracing. Implements Prometheus/Grafana stacks, conducts load testing, performs application profiling, and plans infrastructure capacity. Use when setting up application monitoring, adding observability to services, debugging production issues with logs/metrics/traces, running load tests with k6 or Artillery, profiling CPU/memory bottlenecks, or forecasting capacity needs.4license: MIT5---67# Monitoring Expert89Observability and performance specialist implementing comprehensive monitoring, alerting, tracing, and performance testing systems.1011## Core Workflow12131. **Assess** — Identify what needs monitoring (SLIs, critical paths, business metrics)142. **Instrument** — Add logging, metrics, and traces to the application (see examples below)153. **Collect** — Configure aggregation and storage (Prometheus scrape, log shipper, OTLP endpoint); verify data arrives before proceeding164. **Visualize** — Build dashboards using RED (Rate/Errors/Duration) or USE (Utilization/Saturation/Errors) methods175. **Alert** — Define threshold and anomaly alerts on critical paths; validate no false-positive flood before shipping1819## Quick-Start Examples2021### Structured Logging (Node.js / Pino)22```js23import pino from 'pino';2425const logger = pino({ level: 'info' });2627// Good — structured fields, includes correlation ID28logger.info({ requestId: req.id, userId: req.user.id, durationMs: elapsed }, 'order.created');2930// Bad — string interpolation, no correlation31console.log(`Order created for user ${userId}`);32```3334### Prometheus Metrics (Node.js)35```js36import { Counter, Histogram, register } from 'prom-client';3738const httpRequests = new Counter({39 name: 'http_requests_total',40 help: 'Total HTTP requests',41 labelNames: ['method', 'route', 'status'],42});4344const httpDuration = new Histogram({45 name: 'http_request_duration_seconds',46 help: 'HTTP request latency',47 labelNames: ['method', 'route'],48 buckets: [0.05, 0.1, 0.3, 0.5, 1, 2, 5],49});5051// Instrument a route52app.use((req, res, next) => {53 const end = httpDuration.startTimer({ method: req.method, route: req.path });54 res.on('finish', () => {55 httpRequests.inc({ method: req.method, route: req.path, status: res.statusCode });56 end();57 });58 next();59});6061// Expose scrape endpoint62app.get('/metrics', async (req, res) => {63 res.set('Content-Type', register.contentType);64 res.end(await register.metrics());65});66```6768### OpenTelemetry Tracing (Node.js)69```js70import { NodeSDK } from '@opentelemetry/sdk-node';71import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';72import { trace } from '@opentelemetry/api';7374const sdk = new NodeSDK({75 traceExporter: new OTLPTraceExporter({ url: 'http://jaeger:4318/v1/traces' }),76});77sdk.start();7879// Manual span around a critical operation80const tracer = trace.getTracer('order-service');81async function processOrder(orderId) {82 const span = tracer.startSpan('order.process');83 span.setAttribute('order.id', orderId);84 try {85 const result = await db.saveOrder(orderId);86 span.setStatus({ code: SpanStatusCode.OK });87 return result;88 } catch (err) {89 span.recordException(err);90 span.setStatus({ code: SpanStatusCode.ERROR });91 throw err;92 } finally {93 span.end();94 }95}96```9798### Prometheus Alerting Rule99```yaml100groups:101 - name: api.rules102 rules:103 - alert: HighErrorRate104 expr: |105 rate(http_requests_total{status=~"5.."}[5m])106 / rate(http_requests_total[5m]) > 0.05107 for: 2m108 labels:109 severity: critical110 annotations:111 summary: "Error rate above 5% on {{ $labels.route }}"112```113114### k6 Load Test115```js116import http from 'k6/http';117import { check, sleep } from 'k6';118119export const options = {120 stages: [121 { duration: '1m', target: 50 }, // ramp up122 { duration: '5m', target: 50 }, // sustained load123 { duration: '1m', target: 0 }, // ramp down124 ],125 thresholds: {126 http_req_duration: ['p(95)<500'], // 95th percentile < 500 ms127 http_req_failed: ['rate<0.01'], // error rate < 1%128 },129};130131export default function () {132 const res = http.get('https://api.example.com/orders');133 check(res, { 'status is 200': (r) => r.status === 200 });134 sleep(1);135}136```137138## Reference Guide139140Load detailed guidance based on context:141142| Topic | Reference | Load When |143|-------|-----------|-----------|144| Logging | `references/structured-logging.md` | Pino, JSON logging |145| Metrics | `references/prometheus-metrics.md` | Counter, Histogram, Gauge |146| Tracing | `references/opentelemetry.md` | OpenTelemetry, spans |147| Alerting | `references/alerting-rules.md` | Prometheus alerts |148| Dashboards | `references/dashboards.md` | RED/USE method, Grafana |149| Performance Testing | `references/performance-testing.md` | Load testing, k6, Artillery, benchmarks |150| Profiling | `references/application-profiling.md` | CPU/memory profiling, bottlenecks |151| Capacity Planning | `references/capacity-planning.md` | Scaling, forecasting, budgets |152153## Constraints154155### MUST DO156- Use structured logging (JSON)157- Include request IDs for correlation158- Set up alerts for critical paths159- Monitor business metrics, not just technical160- Use appropriate metric types (counter/gauge/histogram)161- Implement health check endpoints162163### MUST NOT DO164- Log sensitive data (passwords, tokens, PII)165- Alert on every error (alert fatigue)166- Use string interpolation in logs (use structured fields)167- Skip correlation IDs in distributed systems