ApiaryActive
Try: pause · settings · learn · wipe
← Community / Reading Room
OS
databases · 14 min read

Observability Stack for Databases

In the next few thousand words we’ll move beyond vague “monitor your DB” advice. You’ll learn the concrete data model that Prometheus scrapes from popular…

Observability is the nervous system of any data‑driven service. When the heartbeat of a database falters, the whole ecosystem—applications, users, and even the AI agents that depend on it—feels the tremor. In the same way that a beekeeper watches hive temperature, humidity, and forager traffic to keep colonies thriving, engineers must monitor, trace, and log every pulse of their data stores. This pillar page walks you through the complete observability stack for databases, weaving together metrics, tracing, and logging with the three open‑source workhorses that dominate the modern monitoring landscape: Prometheus, Grafana, and OpenTelemetry.

In the next few thousand words we’ll move beyond vague “monitor your DB” advice. You’ll learn the concrete data model that Prometheus scrapes from popular exporters, see how OpenTelemetry turns a SQL query into a distributed trace, discover the structured‑log formats that make root‑cause analysis a breeze, and explore how Grafana dashboards turn raw numbers into the kind of visual story a beekeeper would use to spot a failing queen. Along the way we’ll sprinkle in real‑world numbers, code snippets, and even a few parallels to bee colonies and self‑governing AI agents—because the principles of feedback, redundancy, and resilience are universal.


1. Foundations of Observability

Observability is often summarized by the three pillars: metrics, logs, and traces. While each pillar can stand alone, true insight emerges when they are correlated. Think of a hive: temperature sensors (metrics) tell you the environment is stable, but a sudden spike in dead bees (logs) combined with a pattern of foragers failing to return (traces) reveals a deeper problem like pesticide exposure.

PillarWhat it capturesTypical storageQuery language
MetricsNumeric time‑series (counters, gauges, histograms)TSDB (e.g., Prometheus)PromQL
LogsImmutable, timestamped events (structured JSON, key/value)Log aggregation (Loki, Elasticsearch)Lucene / LogQL
TracesEnd‑to‑end request spans across servicesTrace back‑ends (Jaeger, Tempo)Span queries, ServiceGraph

1.1 Why databases need all three

  1. Metrics reveal what is happening: query latency, connection pool size, cache hit ratio.
  2. Logs tell why something happened: “deadlock detected on table users” with stack‑trace.
  3. Traces show how the request travelled: from API gateway → service → DB driver → query execution.

A single metric spike—say, postgresql_backends_active rising from 20 to 80—might be harmless during a traffic surge, but when paired with error logs and a trace that shows a lock wait chain, the story becomes a critical lock contention issue.

1.2 The role of standards

Standards such as the OpenMetrics format for metrics, OpenTelemetry for tracing and logging, and OTLP (OpenTelemetry Protocol) for data transport ensure that every component—from a tiny SQLite instance on a Raspberry Pi to a massive CockroachDB cluster—speaks the same language. This interoperability is the backbone of the stack we’ll build.


2. Metrics: Prometheus for Databases

Prometheus has become the de‑facto standard for collecting numeric time‑series from cloud‑native workloads. Its pull‑based model, built‑in service discovery, and powerful query language (PromQL) make it ideal for databases that expose exporters.

2.1 Exporters and the data model

An exporter is a thin HTTP server that translates internal DB statistics into the OpenMetrics exposition format. Popular exporters include:

DatabaseExporterTypical scrape intervalKey metrics
PostgreSQLpostgres_exporter15 s (default)pg_stat_activity_count, pg_up, pg_locks_deadlocked_total
MySQLmysqld_exporter15 smysql_global_status_threads_connected, mysql_global_status_innodb_row_lock_time
MongoDBmongodb_exporter30 smongodb_up, mongodb_op_counters_insert_total
Redisredis_exporter10 sredis_connected_clients, redis_commands_processed_total

Example: The postgres_exporter exposes a gauge pg_stat_activity_count that counts active sessions. A typical PromQL query to detect a sudden surge is:

increase(pg_stat_activity_count[5m]) > 100

If this query fires, you might see a corresponding spike in pg_locks_deadlocked_total, indicating a possible deadlock.

2.2 Scaling to thousands of series

A single PostgreSQL instance can expose ~200 metrics; a high‑traffic cluster with multiple nodes can easily exceed 5 000 series. Prometheus can comfortably handle ~10 000 active series per instance with < 2 GB RAM, but when you cross 100 000 series you’ll need federation or remote‑write to a long‑term storage (e.g., Thanos, Cortex).

Rule of thumb: If your scrape target exceeds 200 k samples per second (≈ 15 s interval × 13 333 series), consider sharding scrape jobs.

2.3 Alerting on metric anomalies

Prometheus Alertmanager lets you define thresholds and silence windows. A simple deadlock alert:

- alert: PostgresDeadlockDetected
  expr: pg_locks_deadlocked_total > 0
  for: 1m
  labels:
    severity: critical
  annotations:
    summary: "Deadlock in PostgreSQL instance {{ $labels.instance }}"
    description: "Deadlock count increased to {{ $value }}. Check logs for lock details."

When this fires, the alert is routed to a PagerDuty or Slack channel, where an on‑call engineer can jump straight to the correlated logs and traces.


3. Tracing: OpenTelemetry and Database Spans

Metrics tell you that something is wrong; traces tell you where in the request path the problem originates. OpenTelemetry provides a unified SDK for instrumenting database drivers, enabling you to capture end‑to‑end latency, query text, and error codes.

3.1 Instrumenting popular drivers

LanguageLibraryExample instrumentation
Gogo.opentelemetry.io/otel + go-sql-driver/mysqlotelsql.NewDriver(mysqlDriver)
Javaopentelemetry-java-instrumentationDataSource ds = new OpenTelemetryDataSource(originalDs);
Pythonopentelemetry-instrumentation-psycopg2psycopg2.connect(..., **otel_kwargs)
Node.js@opentelemetry/instrumentation-pgregisterInstrumentations({pg: {enabled: true}})

These wrappers automatically create a span for each query execution. The span includes attributes such as:

  • db.system – e.g., postgresql, mysql
  • db.statement – the sanitized SQL (or a hash if you enable privacy)
  • db.operationSELECT, INSERT, etc.
  • net.peer.name – host name of the DB server
  • net.peer.port – port number

3.2 Sampling and performance impact

Tracing every query in a high‑throughput service can add overhead. OpenTelemetry supports probabilistic sampling (e.g., 1 % of requests) and head-based sampling based on request latency. In a benchmark on a 10 k QPS PostgreSQL workload, a 0.5 % trace sampling rate added < 2 ms per request latency, well within typical SLA budgets.

3.3 Correlating traces with metrics

Because both metrics and traces use the same timestamp source (Unix epoch), you can overlay them in Grafana. For example, you could display the 99th‑percentile query latency from Prometheus (histogram_quantile(0.99, rate(pg_stat_activity_duration_seconds_bucket[5m]))) alongside a trace heatmap that highlights the longest spans. When a latency spike appears, you can drill down into the trace view to see the exact query text and lock wait chain.

3.4 Exporting traces to a backend

OpenTelemetry Collector can receive OTLP over gRPC or HTTP and forward to multiple back‑ends. A typical pipeline:

receivers:
  otlp:
    protocols:
      grpc:
      http:
exporters:
  jaeger:
    endpoint: jaeger:14250
  prometheus:
    endpoint: "0.0.0.0:9090"
service:
  pipelines:
    traces:
      receivers: [otlp]
      exporters: [jaeger]
    metrics:
      receivers: [otlp]
      exporters: [prometheus]

This single collector instance can handle both traces and metrics, simplifying deployment and ensuring consistent sampling policies across data types.


4. Logging: Structured Logs and Centralized Pipelines

Logs are the raw narrative of what the database engine did. Modern observability pipelines treat logs as first‑class citizens, storing them in a searchable, low‑latency store such as Grafana Loki or ElasticSearch.

4.1 Structured log formats

Instead of free‑form text, emit logs as JSON with well‑defined fields:

{
  "timestamp":"2026-06-10T14:23:57.123Z",
  "level":"ERROR",
  "db":"postgres",
  "host":"db01.internal",
  "message":"deadlock detected",
  "query":"UPDATE orders SET status='shipped' WHERE id=12345",
  "pid":3421,
  "duration_ms":87
}

Structured logs enable precise filtering ({db="postgres", level="ERROR", host="db01.internal"}) and automatic correlation with metrics (e.g., join on pid or duration_ms).

4.2 Log shipping with Fluent Bit

A lightweight agent like Fluent Bit can tail log files and forward them to Loki:

[INPUT]
    Name tail
    Path /var/log/postgresql/*.log
    Parser json
    Tag postgres

[OUTPUT]
    Name loki
    Match *
    Url http://loki:3100/api/prom/push
    BatchWait 1
    BatchSize 102400

The same agent can also ship audit logs (e.g., PostgreSQL log_statement = 'all') which are essential for security compliance.

4.3 Log‑based alerting

Grafana Loki integrates with Alertmanager via LogQL queries. An alert for repeated deadlock messages:

{job="postgres", level="ERROR"} |~ "deadlock detected"
|= count_over_time(5m) > 5

When this fires, the alert includes a snippet of the offending queries, allowing rapid triage.

4.4 Retention and cost considerations

Log volume can be massive: a busy PostgreSQL node can generate ~5 GB of logs per day. Loki’s compression (gzip + chunked storage) reduces this to ~1 GB. Retention policies of 30 days for error logs and 7 days for info/debug logs balance compliance with cost.


5. Correlating Signals: Building the Unified View

Having metrics, traces, and logs in isolation is useful, but the real power emerges when you correlate them. Grafana’s Unified Alerting and Explore features let you pivot from a metric spike to the exact log lines and trace spans that caused it.

5.1 The “trace ID” bridge

OpenTelemetry automatically propagates a trace ID across service boundaries. When you enable log correlation in the SDK, each log entry receives a trace_id attribute. In Grafana Explore you can search:

{db="postgres"} | json | trace_id="4a1f..."

The result shows the exact span that generated the log, linking the narrative to the latency graph.

5.2 Using Grafana’s Log Panel with Prometheus Variables

Create a dashboard variable instance that pulls from pg_up:

label_values(pg_up, instance)

Then embed a LogQL query that uses this variable:

{job="postgres", instance="$instance"} |~ "error"

Now a single click on a metric panel (e.g., a high pg_stat_activity_count) can drive the log panel to the relevant instance, mirroring the way a beekeeper might focus on a specific hive after noticing an unusual temperature rise.

5.3 Example: Diagnosing a Slow Query

  1. Metric: increase(pg_stat_activity_duration_seconds_sum[5m]) / increase(pg_stat_activity_duration_seconds_count[5m]) shows average query latency rising to 2.3 s (baseline 0.4 s).
  2. Trace: In Jaeger, the longest span for the same time window is a SELECT on orders that takes 2.1 s. The span attributes reveal db.statement="SELECT … FROM orders WHERE status='pending'".
  3. Log: Loki query filtered by the trace ID shows an error: deadlock detected with pid=3421.

The combined view tells you the slow query is blocked by a deadlock, prompting you to examine lock tables and adjust the transaction isolation level.


6. Visualization and Alerting with Grafana

Grafana is the glue that turns raw observability data into actionable insight. Its rich panel types—time series, heatmaps, tables, and the newer Trace panel—let you design dashboards that feel as natural as a beekeeper’s hive map.

6.1 Core dashboard components

PanelTypical queryInsight
Time‑Seriesrate(pg_stat_activity_count[5m])Active connections over time
Heatmaphistogram_quantile(0.95, rate(pg_stat_activity_duration_seconds_bucket[5m]))Latency distribution
Tablepg_locks_deadlocked_totalList of deadlocks
Tracetrace_id variable from OpenTelemetryEnd‑to‑end request flow
Logs`{job="postgres", instance="$instance"}json`Real‑time error stream

6.2 Alerting pipelines

Grafana’s built‑in alerting can send notifications to OpsGenie, Microsoft Teams, or BeeConservancy Slack channels. Example alert rule for connection saturation:

for: 2m
expr: pg_stat_activity_count > 150
annotations:
  summary: "High DB connections on {{ $labels.instance }}"
  runbook: "https://apiary.org/runbooks/db-connection-saturation"

The runbook link points to a dedicated page (e.g., [[db-connection-saturation]]) that outlines mitigation steps: scaling the connection pool, enabling connection throttling, or adding read replicas.

6.3 Dashboard for multi‑tenant environments

When you host many customer databases, a tenant‑aware dashboard can slice metrics by customer_id label. Prometheus can scrape exporters that expose a tenant label, and Grafana variables can filter across tenants, ensuring you never lose sight of a single client’s health—just as a beekeeper monitors each hive separately.


7. Real‑World Case Studies

7.1 PostgreSQL on Kubernetes

A SaaS platform migrated its PostgreSQL clusters to a statefulset on GKE. By deploying postgres_exporter as a sidecar and configuring the OpenTelemetry Collector as a DaemonSet, they achieved:

MetricBaselineAfter observability
Avg query latency350 ms210 ms (after fixing lock contention)
Deadlocks per day120
Alert mean‑time‑to‑acknowledge (MTTA)45 min7 min

The key was the correlation of pg_locks_deadlocked_total spikes with trace spans that revealed a “batch update” job holding exclusive locks for > 30 s. The team rewrote the job to use SELECT … FOR UPDATE SKIP LOCKED, eliminating the deadlocks.

7.2 MySQL in a Microservices Architecture

An e‑commerce site ran 30 microservices, each using a dedicated MySQL schema. By instrumenting the Go MySQL driver with OpenTelemetry, they collected ~2 M spans per day and observed a 15 % increase in latency during flash‑sale events. The trace data showed that a newly added “recommendation” service opened a connection pool of 200 per pod, exhausting the MySQL max_connections limit (default 151). Scaling the pool down to 50 and adding a connection‑pooler (ProxySQL) reduced the error rate from 0.8 % to 0.02 %.

7.3 MongoDB for IoT Sensor Data

A wildlife‑tracking project stored GPS pings from thousands of sensor‑tagged bees. The MongoDB cluster generated ~1 GB of logs per day. By shipping logs to Loki with a 30‑day retention, they could quickly locate “write concern timeout” messages that coincided with network storms. Correlating these logs with Prometheus metric mongodb_mongod_up (which dropped to 0 for 2‑minute windows) helped the team tune the replica set’s write concern from majority to w:2, improving durability without sacrificing availability.


8. Scaling Observability in Cloud‑Native Environments

Observability itself can become a performance bottleneck if not sized correctly.

8.1 Horizontal scaling of Prometheus

Prometheus does not natively shard; you must run multiple instances and use federation or a remote‑write backend. For a fleet of 200 databases each exposing 300 metrics, a single Prometheus instance would ingest ≈ 6 M samples per minute. The recommended pattern is:

  1. Local Prometheus per node (scrapes only its exporters).
  2. Central Prometheus that scrapes the local instances via federation (/federate).
  3. Thanos or Cortex for long‑term storage and global query.

8.2 Collector resource planning

OpenTelemetry Collector can be run in gateway mode (single point) or agent mode (sidecar). In high‑throughput environments, the agent mode offloads processing to the same node as the application, keeping network traffic low. Benchmarks show that a collector with 2 CPU and 4 GB RAM can process ≈ 10 k spans/s and ≈ 30 k metrics/s with < 5 % CPU overhead.

8.3 Cost‑effective log storage

Loki’s microservices architecture lets you scale ingesters independently from the query front‑end. By configuring a ring with 3 ingester replicas and a compactor that runs nightly, you can keep storage costs under $0.02 per GB on S3, while still supporting ~200 k log entries per second.


9. Lessons from Ecology: Bees, AI Agents, and Feedback Loops

Observability is, at its core, about feedback—detecting a change, interpreting it, and acting. In nature, honeybees maintain colony health through a continuous loop of temperature regulation, forager communication, and queen pheromone signaling. Similarly, an AI agent that manages a database cluster can use observability data as its sensory input.

  • Redundancy: Bees keep multiple foragers checking the same flower; databases keep multiple replicas. Observability must therefore expose both individual and aggregate signals.
  • Self‑governance: A self‑organizing AI agent could ingest Prometheus alerts, query relevant traces, and automatically adjust configuration (e.g., scaling connection pools). This mirrors how a queen bee modulates pheromone levels to balance brood production.
  • Early warning: Just as a sudden drop in hive temperature predicts a colony collapse, a subtle rise in pg_stat_bgwriter_checkpoint_write_time_seconds_total can foreshadow I/O saturation.

By framing observability as a bio‑feedback system, engineers can design monitoring that is resilient, adaptive, and, importantly, humane—recognizing that behind every metric lies a living service that must be cared for.


10. Best Practices and Checklist

AreaChecklist ItemWhy it matters
MetricsUse the official exporter for your DB (e.g., postgres_exporter).Guarantees correct metric names and labels.
Set scrape interval based on volatility (e.g., 15 s for fast‑changing counters).Avoids missing short spikes.
Enable recording rules for common aggregates (e.g., pg_cpu_seconds_total).Reduces query complexity and storage.
TracingInstrument all database drivers with OpenTelemetry.Gives end‑to‑end visibility.
Apply sampling (≤ 1 % for high‑throughput services).Controls overhead.
Propagate trace_id into logs.Enables cross‑signal correlation.
LoggingEmit structured JSON with key fields (db, query, duration_ms).Facilitates filtering and analytics.
Ship logs via Fluent Bit to Loki with compression.Keeps storage costs low.
Define log‑based alerts for error patterns (deadlock, out of memory).Provides immediate notification.
VisualizationBuild tenant‑aware dashboards using Grafana variables.Prevents “one size fits all” blindness.
Include a runbook link in every alert.Reduces MTTA.
ScalingDeploy multiple Prometheus instances with federation.Handles large metric volumes.
Use remote‑write to Thanos/Cortex for long‑term storage.Retains historical context.
Separate collector agents per node.Minimizes network overhead.
GovernanceEnforce privacy scrubbing for db.statement (hash or truncate).Meets GDPR/PCI compliance.
Review retention policies quarterly.Controls cost and data bloat.

Why it matters

A database that silently degrades can cripple applications, stall AI agents, and—if the data underpins environmental monitoring—obscure the very signals we need to protect bees and other pollinators. By weaving together metrics, traces, and logs with Prometheus, Grafana, and OpenTelemetry, you gain a holistic, real‑time view that not only spots problems faster but also empowers automated remediation. The result is a healthier data ecosystem, more reliable services, and a stronger foundation for the AI‑driven conservation work that Apiary champions. In short: observability is the lifeline that keeps our digital hives humming.

Frequently asked
What is Observability Stack for Databases about?
In the next few thousand words we’ll move beyond vague “monitor your DB” advice. You’ll learn the concrete data model that Prometheus scrapes from popular…
What should you know about 1. Foundations of Observability?
Observability is often summarized by the three pillars: metrics , logs , and traces . While each pillar can stand alone, true insight emerges when they are correlated. Think of a hive: temperature sensors (metrics) tell you the environment is stable, but a sudden spike in dead bees (logs) combined with a pattern of…
What should you know about 1.1 Why databases need all three?
A single metric spike—say, postgresql_backends_active rising from 20 to 80—might be harmless during a traffic surge, but when paired with error logs and a trace that shows a lock wait chain, the story becomes a critical lock contention issue.
What should you know about 1.2 The role of standards?
Standards such as the OpenMetrics format for metrics, OpenTelemetry for tracing and logging, and OTLP (OpenTelemetry Protocol) for data transport ensure that every component—from a tiny SQLite instance on a Raspberry Pi to a massive CockroachDB cluster—speaks the same language. This interoperability is the backbone…
What should you know about 2. Metrics: Prometheus for Databases?
Prometheus has become the de‑facto standard for collecting numeric time‑series from cloud‑native workloads. Its pull‑based model, built‑in service discovery, and powerful query language (PromQL) make it ideal for databases that expose exporters .
References & sources
  1. Apiary Reading RoomOpen, cited knowledge base — funded to keep bee & practical research free.
From the Apiary Reading Room. Opinion & editorial — not financial advice. We don't overclaim.
More from the Reading Room