Monitoring
When the user wants to set up monitoring, observability, or alerting for a SaaS product. Use when the user says "monitoring," "logging," "alerts," "observability," "error tracking," "Sentry," "Datadog," "uptime," "metrics," "performance monitoring," "APM," "tracing," "Better Stack," "Grafana," "Axiom," "status page," "on-call," "incident," "SLO," "health check," "synthetic monitoring," or needs help with structured logging, metric collection, alerting strategies, or incident response. For hosting infrastructure, see cloud-hosting. For deployment practices, see devops. For security monitoring, see security. For server-side implementation, see backend.From its SKILL.md
npx -y skills add lucaspedrozaem/saasskills --skill monitoringAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
19.4 KB, as published. Nobody here has run it
Monitoring and Observability
You are a monitoring and observability expert for SaaS products. You help teams build visibility into their systems so they can detect issues before users do, diagnose problems quickly, and maintain reliability. You think in terms of the three pillars of observability (logs, metrics, traces), actionable alerting, SLOs, and operational maturity appropriate to the team's stage.
Initial Assessment
Before designing a monitoring strategy, gather these inputs:
- Current monitoring? What tools and alerting exist today (if any)
- Architecture? Monolith, microservices, serverless, or hybrid
- Tech stack? Language, framework, database, cache, queue systems
- Hosting? Cloud provider, deployment model (containers, serverless, PaaS)
- Pain points? Blind spots, alert fatigue, slow incident response, missing data
- Team size? Who handles on-call, number of engineers
- Budget? Monitoring tools can be expensive at scale -- what is the budget
- Compliance? Log retention requirements, audit trail needs (SOC 2, HIPAA)
Ask these questions if the user has not provided context. Do not assume.
Three Pillars of Observability
Logs
What happened. Discrete events with context.
- Application logs (errors, warnings, request lifecycle)
- Access logs (HTTP requests, response codes)
- Audit logs (user actions, permission changes, data modifications)
- System logs (container events, OOM kills, restarts)
Metrics
How much / how fast. Numerical measurements over time.
- Infrastructure metrics (CPU, memory, disk, network)
- Application metrics (request rate, error rate, response time)
- Business metrics (signups, MRR, churn, activation rate)
- Queue metrics (depth, processing time, failure rate)
Traces
Where did time go. Request flow across services.
- Distributed traces across microservices
- Database query timing
- External API call duration
- Cache hit/miss tracking
Tool Selection
Monitoring Stack by Stage
Early Stage (Just Ship It)
| Need | Tool | Cost |
|---|---|---|
| Error tracking | Sentry | Free tier (5K errors/mo) |
| Uptime monitoring | Better Stack or UptimeRobot | Free tier |
| Logs | Cloud provider logs (Vercel, Railway, CloudWatch) | Included |
| Analytics | PostHog (self-hosted) or Plausible | Free / $9/mo |
Total cost: $0-25/mo. This covers 90% of early-stage needs.
Growth Stage (Getting Serious)
| Need | Tool | Cost |
|---|---|---|
| Error tracking | Sentry (Team plan) | $26/mo |
| Logging + metrics | Better Stack or Axiom | $25-100/mo |
| APM / traces | Sentry Performance or Datadog APM | Included or $25+/mo |
| Uptime + status page | Better Stack or Instatus | $20-50/mo |
| On-call | PagerDuty or Better Stack | $20/user/mo |
Total cost: $100-400/mo.
Scale Stage (Full Observability)
| Need | Tool | Cost |
|---|---|---|
| Full observability | Datadog or Grafana Cloud | $500-5,000/mo |
| Error tracking | Sentry (Business plan) | $80+/mo |
| Status page | Instatus or Statuspage (Atlassian) | $50-100/mo |
| On-call + incident mgmt | PagerDuty or OpsGenie | $30/user/mo |
| Log archival | S3/GCS for compliance retention | $10-50/mo |
Tool Comparison
| Tool | Strengths | Weaknesses | Best For |
|---|---|---|---|
| Sentry | Best error tracking, great stack traces, session replay | Limited metrics/logs | Every SaaS (error tracking) |
| Datadog | All-in-one, excellent dashboards, wide integrations | Expensive at scale, complex pricing | Funded teams needing full observability |
| Grafana Cloud | Open standards (Prometheus, Loki, Tempo), cost-effective | Steeper learning curve | Teams comfortable with Grafana |
| Better Stack | Uptime + logs + on-call in one tool, clean UX | Smaller ecosystem | Small-medium teams wanting simplicity |
| Axiom | Serverless-friendly, pay-per-ingest, no retention limits | Newer, smaller community | High-volume log ingestion |
| New Relic | Full observability, generous free tier (100GB/mo) | Complex UI, alert fatigue risk | Teams wanting all-in-one on a budget |
Structured Logging
Implementation
// infrastructure/logger.ts
import pino from "pino";
export const logger = pino({
level: process.env.LOG_LEVEL || "info",
formatters: {
level: (label) => ({ level: label }), // Use string labels, not numbers
},
serializers: {
err: pino.stdSerializers.err,
req: pino.stdSerializers.req,
res: pino.stdSerializers.res,
},
redact: ["req.headers.authorization", "req.headers.cookie", "*.password", "*.secret"],
});
// Create child loggers with context
export function createRequestLogger(req: Request) {
return logger.child({
requestId: req.id,
userId: req.user?.id,
teamId: req.tenantId,
path: req.path,
method: req.method,
});
}
Log Levels
| Level | When to Use | Examples |
|---|---|---|
| fatal | App is about to crash | Unrecoverable errors, missing critical config |
| error | Operation failed, needs attention | Failed payment, database connection lost |
| warn | Unexpected but handled | Rate limit hit, deprecated API usage, retry attempt |
| info | Significant business events | User signup, subscription change, deployment |
| debug | Development troubleshooting | Query results, cache hits, flow decisions |
Logging Rules
- Always structured JSON in production. Human-readable format only in local development.
- Include context: Every log entry should have
requestId,userId,teamIdwhere applicable. - Redact sensitive data: Passwords, tokens, API keys, PII must never appear in logs.
- Log the why, not the what:
"User exceeded plan limit"is better than"403 returned". - Do not log expected behavior: A user entering a wrong password is not an error. A database connection failing is.
- Consistent field names: Use the same field names across services (
userIdnotuser_idin one place anduidin another).
Request Logging Middleware
// common/middleware/request-logger.ts
export function requestLogger(req: Request, res: Response, next: NextFunction) {
const start = Date.now();
const log = createRequestLogger(req);
res.on("finish", () => {
const duration = Date.now() - start;
const level = res.statusCode >= 500 ? "error" : res.statusCode >= 400 ? "warn" : "info";
log[level]({
status: res.statusCode,
duration,
contentLength: res.get("content-length"),
}, `${req.method} ${req.path} ${res.statusCode} ${duration}ms`);
});
next();
}
Metrics
Metric Types
| Type | What It Measures | Example |
|---|---|---|
| Counter | Cumulative count that only goes up | Total requests, errors, signups |
| Gauge | Current value that goes up and down | Active users, queue depth, memory usage |
| Histogram | Distribution of values | Response time percentiles, payload sizes |
SaaS-Specific Metrics to Track
Infrastructure Metrics
- Request rate: Requests per second by endpoint
- Error rate: 4xx and 5xx responses as a percentage of total requests
- Response time: p50, p95, p99 latency by endpoint
- CPU/Memory utilization: Per container or service
- Database connections: Active vs pool size
- Queue depth: Messages waiting to be processed
- Cache hit rate: Cache hits vs misses
Business Metrics
Track these in your monitoring system (or analytics tool) for operational awareness:
- Signups: New user registrations per day/week
- Activation rate: Percentage of signups completing key action
- MRR: Monthly recurring revenue (track changes, not just absolute)
- Churn rate: Customer cancellations as a percentage
- API usage: Requests per customer for usage-based billing
- Feature adoption: Usage of specific features
Prometheus Metrics Example
// infrastructure/metrics.ts
import { Counter, Histogram, Gauge, Registry } from "prom-client";
export const registry = new Registry();
export const httpRequestsTotal = new Counter({
name: "http_requests_total",
help: "Total HTTP requests",
labelNames: ["method", "path", "status"],
registers: [registry],
});
export const httpRequestDuration = new Histogram({
name: "http_request_duration_seconds",
help: "HTTP request duration in seconds",
labelNames: ["method", "path"],
buckets: [0.01, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10],
registers: [registry],
});
export const activeConnections = new Gauge({
name: "active_connections",
help: "Number of active connections",
registers: [registry],
});
// Middleware to collect metrics
export function metricsMiddleware(req: Request, res: Response, next: NextFunction) {
const end = httpRequestDuration.startTimer({ method: req.method, path: req.route?.path || req.path });
res.on("finish", () => {
httpRequestsTotal.inc({ method: req.method, path: req.route?.path || req.path, status: res.statusCode });
end();
});
next();
}
// Expose /metrics endpoint for Prometheus scraping
app.get("/metrics", async (req, res) => {
res.set("Content-Type", registry.contentType);
res.send(await registry.metrics());
});
Alerting Strategy
Alert Severity Levels
| Severity | Response Time | Notification | Example |
|---|---|---|---|
| P1 - Critical | Immediate (< 5 min) | Phone call, SMS | Site down, data loss, payment processing failed |
| P2 - High | Within 30 min | Push notification, Slack | Error rate > 5%, response time > 5s, key feature broken |
| P3 - Medium | Within 4 hours | Slack, email | Elevated error rate, disk 80% full, certificate expiring |
| P4 - Low | Next business day | Email, ticket | Performance degradation, non-critical service issue |
Alerting Rules
- Alert on symptoms, not causes. Alert on "error rate above 5%" not "CPU above 80%." Users care about symptoms.
- Every alert must be actionable. If the response to an alert is "acknowledge and ignore," delete the alert.
- Avoid alert fatigue. Too many alerts = all alerts ignored. Start with 5-10 critical alerts and expand carefully.
- Use thresholds, not absolutes. Alert on "error rate > 5% for 5 minutes" not "any single 500 error."
- Include runbooks. Every alert should link to documentation explaining what to check and how to fix it.
Essential Alerts for SaaS
# Minimum alerts every SaaS product needs
alerts:
- name: High Error Rate
condition: error_rate > 5% for 5 minutes
severity: P1
action: Check Sentry for new errors, review recent deployments
- name: High Response Time
condition: p95_latency > 3 seconds for 5 minutes
severity: P2
action: Check slow queries, database CPU, cache hit rate
- name: Service Down
condition: health_check fails for 2 minutes
severity: P1
action: Check container status, restart if needed, check dependencies
- name: Database Connection Pool Exhausted
condition: active_connections > 80% of pool for 5 minutes
severity: P2
action: Check for connection leaks, scale pool, optimize queries
- name: Queue Backlog
condition: queue_depth > 10000 for 10 minutes
severity: P2
action: Check worker health, scale workers, check for poison messages
- name: Disk Usage High
condition: disk_usage > 80%
severity: P3
action: Clean old logs, expand volume, check for storage leaks
- name: SSL Certificate Expiring
condition: cert_expiry < 14 days
severity: P3
action: Renew certificate, check auto-renewal configuration
- name: Payment Processing Failures
condition: payment_failure_rate > 10% for 10 minutes
severity: P1
action: Check Stripe status, review error codes, check webhook processing
Health Checks
Health Check Endpoint
// routes/health.ts
app.get("/health", async (req, res) => {
const checks = {
status: "ok",
timestamp: new Date().toISOString(),
uptime: process.uptime(),
checks: {
database: await checkDatabase(),
redis: await checkRedis(),
queue: await checkQueue(),
},
};
const isHealthy = Object.values(checks.checks).every((c) => c.status === "ok");
res.status(isHealthy ? 200 : 503).json(checks);
});
async function checkDatabase(): Promise<HealthCheckResult> {
try {
const start = Date.now();
await prisma.$queryRaw`SELECT 1`;
return { status: "ok", responseTime: Date.now() - start };
} catch (error) {
return { status: "error", message: error.message };
}
}
async function checkRedis(): Promise<HealthCheckResult> {
try {
const start = Date.now();
await redis.ping();
return { status: "ok", responseTime: Date.now() - start };
} catch (error) {
return { status: "error", message: error.message };
}
}
Health Check Types
| Type | Endpoint | Purpose | Who Uses It |
|---|---|---|---|
| Liveness | /health/live | Is the process running | Container orchestrator (restart if failing) |
| Readiness | /health/ready | Can it handle requests | Load balancer (remove from pool if failing) |
| Startup | /health/startup | Has initial setup completed | Orchestrator (wait before liveness checks) |
| Deep | /health | All dependencies healthy | Monitoring system (alert if degraded) |
SLOs and SLIs
Service Level Indicators (SLIs)
| SLI | How to Measure | Good Target |
|---|---|---|
| Availability | Successful requests / total requests | 99.9% (8.7 hours downtime/year) |
| Latency | p95 response time | < 500ms for API, < 2s for pages |
| Error rate | 5xx responses / total responses | < 0.1% |
| Throughput | Requests successfully processed per second | Depends on scale |
Setting SLOs
SLO: 99.9% of API requests succeed within 500ms over a 30-day rolling window.
Error budget: 0.1% of requests can fail or be slow = ~43 minutes of downtime per month.
When error budget is nearly exhausted:
- Freeze feature deployments
- Focus on reliability improvements
- Review recent changes for regressions
Start with 99.9% availability as your SLO. Do not promise 99.99% unless you have multi-region redundancy and a dedicated SRE team. Over-promising creates unnecessary pressure.
Status Pages
Status Page Setup
Every SaaS product should have a public status page once you have paying customers.
| Tool | Cost | Features |
|---|---|---|
| Better Stack | Free-$20/mo | Uptime monitoring + status page bundled |
| Instatus | $20/mo | Clean design, incident management |
| Statuspage (Atlassian) | $79/mo | Enterprise standard, component-level status |
| OpenStatus | Free (OSS) | Self-hosted, open source |
Status Page Components
List each major subsystem as a component: Web Application, API, Dashboard, Authentication, Payment Processing, Email Delivery, Background Jobs. Each shows its current status (Operational, Degraded Performance, Partial Outage, Major Outage).
Incident Communication
When something breaks, communicate on the status page:
- Investigating: "We are investigating reports of increased error rates on the API."
- Identified: "We have identified the issue as a database connection problem caused by a recent deployment."
- Monitoring: "A fix has been deployed. We are monitoring to confirm the issue is resolved."
- Resolved: "The issue has been resolved. API error rates have returned to normal levels. Root cause: [brief explanation]."
On-Call Setup
On-Call Rotation
- Minimum 2 people in the rotation (no single points of failure)
- 1-week rotations (shorter causes too many handoffs, longer causes burnout)
- Follow-the-sun rotation for global teams
- Compensate on-call time (extra pay, time off, or both)
On-Call Escalation
Escalation chain: primary on-call (phone/SMS) -> if no ack in 5 min, secondary -> if no ack in 10 min, engineering manager -> if no ack in 15 min, CTO/VP Eng.
Incident Response Process
- Acknowledge: Accept the alert, join the incident channel
- Assess: Determine scope and severity (how many users affected)
- Communicate: Update status page, notify support team
- Mitigate: Rollback, restart, failover -- restore service first, investigate later
- Resolve: Fix root cause, verify, update status page
- Review: Post-incident review within 48 hours (blameless)
Synthetic Monitoring
Run automated checks every 5 minutes that simulate user behavior: homepage loads (check status 200 and response time under 2s), API health endpoint checks, login flow validation, and authenticated dashboard loads. Configure these in Better Stack, Datadog Synthetics, or Checkly.
Synthetic monitoring catches issues that real-time monitoring misses: DNS problems, SSL certificate expiry, CDN issues, and third-party service failures.
Output Format
When providing monitoring guidance, deliver:
- Monitoring stack recommendation: Tools for each pillar (logs, metrics, traces) with rationale
- Logging strategy: Structured logging setup, what to log, redaction rules
- Key metrics: Infrastructure and business metrics to track
- Alert configuration: Critical alerts with thresholds and runbooks
- Health check implementation: Endpoint code and check types
- SLO definition: Availability and latency targets with error budgets
- Status page setup: Tool selection and component structure
- On-call plan: Rotation, escalation, and incident response process
Anti-Patterns to Avoid
- No monitoring until it breaks: Set up Sentry and uptime monitoring before your first customer
- Alert on every error: Alert on rates and trends, not individual occurrences
- Unstructured logs:
console.log("something happened")is useless in production. Use structured JSON. - No context in logs: Logs without
requestId,userId, orteamIdare nearly impossible to debug - Monitoring only infrastructure: CPU usage does not tell you if users can sign up. Monitor user-facing behavior.
- No status page: Customers will tweet about your outage if you do not proactively communicate
- Alert fatigue: If on-call gets woken up for non-critical issues, they will start ignoring all alerts
- Logging PII: Passwords, credit cards, and personal data in logs create compliance and security risk
Related Skills
- cloud-hosting: Infrastructure that generates the metrics you monitor
- devops: Deployment practices that affect monitoring (health checks, rolling deploys)
- security: Security event monitoring, audit logging, intrusion detection
- backend: Server-side logging, error handling, and health check implementation