Prometheus & Grafana vs Loki & Tempo for PHP observability

By · Published on · 8 min read

Green and red bars with trend lines and numeric axis on a dark background
Metrics chart illustrating an observability stacks comparison Photo: Rafael Minguet Delgado / Pexels

This comparison of Prometheus+Grafana and Loki+Tempo focuses on PHP applications that prefer to avoid SaaS. I explain where each stack excels, how to instrument PHP for metrics, logs and traces, typical operational costs, and when it makes sense to combine everything in Grafana. The goal is to provide practical guidance for production use, without magic promises.

Overview: two complementary stacks

Prometheus+Grafana covers metrics and alerts using scraped endpoints. It’s ideal for time-series data like CPU usage, latencies and error counts.

Loki+Tempo focuses on logging and distributed tracing. Loki indexes labels and stores logs efficiently. Tempo stores and queries traces. Both integrate into Grafana.

For PHP, the question isn’t just “which is better?” but “what to measure now” and “how to correlate events” without relying on SaaS.

PHP scenarios: web, workers and queues

In a PHP monolith (Laravel, Symfony or Slim), you want HTTP latency metrics, error counts per route, PHP-FPM and database usage. Structured logs help diagnose issues.

In queue workers, track jobs processed, failures by type and job duration. Logs with correlation IDs let you trace a request through the whole chain.

Traces show the timeline for complex requests, external calls and bottlenecks. The decision is about priority and data budget.

  • Prometheus: latencies, counters, histograms and actionable alerts.
  • Loki: application and Nginx logs in JSON, fast label-based search.
  • Tempo: traces with context and detailed spans for pinpointing bottlenecks.

Architecture, storage and maintenance

Prometheus is a local TSDB using pull scraping. It’s simple to start with and reliable for metrics. For longer retention, use fast disks or remote_write.

Loki uses a lightweight index over labels and stores logs in chunks. Cost depends on volume and label cardinality. You control retention per stream.

Tempo accepts traces via OTLP and can use object storage. Retention depends on sampling. Tracing without sampling becomes expensive quickly.

  • Prometheus: simple, but sensitive to high label cardinality.
  • Loki: efficient, but poor labeling can explode indexes and costs.
  • Tempo: requires sampling strategy and service-level limits.

Installation and operation with Docker Compose

Both stacks work well with Docker Compose. The minimum path is to isolate components and volumes, expose internal ports and put Grafana on top.

For metrics, Prometheus scrapes exporters and the app /metrics endpoint. For logs, Promtail or Fluent Bit send data to Loki. For tracing, the OpenTelemetry SDK sends OTLP to Tempo.

Want a step-by-step for metrics? See the Prometheus and Grafana guide with Docker Compose.

  • Basic components: Grafana, Prometheus, Loki, Tempo, Promtail/Fluent Bit, exporters.
  • Expose /metrics in the PHP app or use PHP-FPM and Nginx exporters.
  • Optional: OpenTelemetry Collector to standardize and route data.

Instrumentation in PHP: metrics, logs and traces

Metrics: use a Prometheus client library to expose counters, gauges and histograms. Expose /metrics on the app. For short-lived jobs consider Pushgateway.

Useful exporters: PHP-FPM exporter, Nginx exporter and node_exporter on the host. They cover infrastructure and the web server without changing the app.

Logs: write JSON with stable labels (app, environment, service). Configure Promtail to collect files and send to Loki. Use a correlation ID per request.

Traces: use the OpenTelemetry SDK for PHP. Send spans via OTLP to Tempo. Instrument HTTP middleware and database drivers to reveal bottlenecks.

  • Standardize metric and label names.
  • Correlate log entries with trace_id and request_id.
  • Document cardinality and retention limits per service.

Queries and dashboards in Grafana

PromQL is powerful for rates, percentiles and alerts. Build SLOs and service-level dashboards.

LogQL lets you filter by labels and search patterns in logs. Combine with parsers to extract fields from JSON.

Tempo integrates directly into Grafana. Investigate spans, dependencies and operation latencies. Correlate: from a metric to the logs, and from the log to the trace in a few clicks.

  • PromQL: rate(), histogram_quantile(), increase().
  • LogQL: {app="php"} |= "error" | json.
  • Traces: visualize the span tree and layer-by-layer latencies.

Comparative table: practical criteria

Side-by-side summary to decide with clarity. Remember: you can combine the stacks under Grafana and evolve in stages.

Criterion Prometheus + Grafana Loki + Tempo (+ Grafana)
Primary purpose Metrics and alerts Logs and tracing
Collection in PHP Endpoint /metrics with a Prometheus client library JSON logs via Promtail; traces via OpenTelemetry
Ingestion Pull (scrape) and optional Pushgateway Push (Promtail / OTLP)
Query language PromQL LogQL for logs; UI/TraceQL for traces
Default storage Local TSDB; optional remote_write Logs in chunks with lightweight indexes; traces in object storage
Deployment curve Quick to get started Requires log standardization and tracing instrumentation
Scalability Good with controlled labels Good with disciplined labeling and sampling
When it shines SLOs, capacity planning and deterministic alerts Deep debugging, reproducing failures and root cause analysis
Common limitations High cardinality degrades the TSDB Unbounded log and trace volume can explode costs

When to choose and when to combine

Only metrics? Prometheus will quickly solve SLOs and alerts. Need to investigate hard incidents? Add Loki for useful logs. Bottlenecks between services? Add Tempo with OpenTelemetry.

For small teams, an incremental approach works: start with essential metrics and structured logs. Enable tracing selectively in the most critical areas. Review retention and sampling monthly.

  • Start simple, measure what matters and evolve.
  • Define SLOs with Prometheus before opening the logs “firehose”.
  • Enable tracing with targeted sampling for errors or high latency.

Best practices and common pitfalls

Prometheus labels: keep cardinality under control. Avoid using unique IDs as labels. High cardinality degrades performance and RAM consumption.

Logs: write clean, stable JSON. Do not log sensitive data. Separate levels, standardize fields and create retention pipelines.

Tracing: configure sampling by route, status code and errors. Without sampling, volume grows fast. Document storage costs and rotation policies.

  • Name metrics with clear prefixes (e.g. http_, db_).
  • Apply per-stream log limits and quotas per service.
  • Monitor Prometheus, Loki and Tempo themselves from Grafana.
  • Automate volume backups and test restores.

Next steps and site references

Want to start with metrics? Follow the Prometheus and Grafana guide with Docker Compose. To correlate everything in PHP, dive deeper into OpenTelemetry and JSON logs with correlation.

If you’re still evaluating alternatives, see the PHP observability tools comparison that includes OpenTelemetry and commercial APMs.

Frequently asked questions

Can I use Prometheus and Loki+Tempo together in the same Grafana?

Yes. Grafana supports multiple data sources. You can query metrics with PromQL, logs with LogQL and traces from Tempo. The real value comes from correlation: start from a latency metric, open logs for that window and, if needed, jump to the matching trace.

How do I correlate logs, metrics and traces in PHP?

Propagate a request_id and trace_id from the HTTP entry point. Include these fields as controlled labels in metrics, in JSON logs and in OpenTelemetry spans. In Grafana use links and variables to navigate from metric panels to logs and from a log entry to the trace.

Do I need OpenTelemetry to use Tempo?

Tempo speaks OTLP, so the recommended path in PHP is to instrument with the OpenTelemetry SDK. It sends standardized spans and attributes to Tempo. Integrations exist for HTTP, database and queue clients. Configure sampling to balance detail and volume.

What if my PHP jobs are short-lived and exit quickly?

For metrics, use Prometheus Pushgateway so the job can push metrics before exiting. For logs, write JSON to files and let Promtail collect them. For tracing, emit short spans and ensure the process flushes spans on shutdown to avoid losing events.

Where should I store data in production?

It depends on volume, retention and budget. Prometheus can run on fast local disks with backups. Loki and Tempo work well with object storage. Define policies per environment and service, and regularly review storage use and compaction needs.

Need help designing an open-source observability stack for PHP?

Describe your scenario, priorities and constraints. We can evaluate the right mix of metrics, logs and tracing, and create an incremental deployment plan.

Talk about PHP observability

See also