Monitoring application performance with OpenTelemetry means instrumenting your services to emit traces, metrics and logs over OTLP, so you can measure latency, errors and throughput per endpoint and trace a slow request to the exact call that caused it, without a proprietary APM agent..
Monitoring application performance with OpenTelemetry means instrumenting your services to emit traces, metrics and logs over OTLP, so you can measure latency, errors and throughput per endpoint and trace a slow request to the exact call that caused it, without a proprietary APM agent.
Application performance monitoring comes down to a small set of request-centric signals plus the traces behind them. Per endpoint, you want latency (as p95/p99, not averages), error rate and throughput, the RED method. Underneath, distributed traces show where a request spent its time across services and downstream calls, and runtime metrics (garbage collection, event-loop lag, thread pools, depending on the language) explain latency the application code alone does not. Together these answer not just whether an app is slow, but which request and which call is responsible.
Where classic APM used a proprietary per-language agent, OpenTelemetry gives you open auto-instrumentation for most languages that produces the same traces and metrics with little or no code change. The OpenTelemetry Collector is the workhorse here: it receives telemetry over OTLP and exports it to your backend, so instrumentation stays vendor-neutral and portable. You instrument the service, the Collector receives the OTLP data, and the same telemetry can go to any backend, so you own the data and avoid lock-in. The span is the unit of APM: every request becomes a trace, and every downstream call a child span you can measure.
The signals that explain almost every application-performance incident:
| Signal | Source | What it tells you / watch for |
|---|---|---|
http.server.request.duration | HTTP instrumentation | Per-endpoint latency histogram; track p95/p99 by route, the headline APM signal. |
error rate (5xx by route) | HTTP instrumentation | Failed requests per endpoint; the direct measure of things going wrong. |
request rate / throughput | HTTP instrumentation | Requests per second, the load context for latency and errors. |
db.client.operation.duration | DB instrumentation | Database query latency; if it dominates a request, the fix is in the query, not the app. |
downstream span duration | client instrumentation | Latency of downstream service and API calls inside a request; usually where a slow request's time goes. |
runtime health (GC, event loop, threads) | runtime instrumentation | Language-runtime signals that explain latency the code does not, GC pauses, event-loop lag, thread-pool starvation. |
An APM dashboard should let you decide in seconds whether a latency problem is in your code, a dependency, or the runtime. Row one is request health: p95/p99 latency by endpoint and error rate by endpoint. Row two is dependencies: latency of downstream calls and database queries, grouped by target, so a slow dependency is obvious. Row three is the runtime and the trace view: GC or event-loop health, and a service map derived from traces so you can follow a slow request across services.
# p99 latency by endpoint (find the slow route, not "the app")
histogram_quantile(0.99, http.server.request.duration) by (http.route)
# error rate by endpoint
sum(rate(http_server_requests{status=~"5.."}[5m])) by (http.route)
/ sum(rate(http_server_requests[5m])) by (http.route)
# database time as a share of request time (spot DB-bound endpoints)
sum(db.client.operation.duration) by (http.route) / sum(http.server.request.duration) by (http.route)
One endpoint's p99 rises and its trace shows a specific downstream span, a query or an API call, accounting for the added time while the app code itself is fast. The fix is in the dependency; the trace makes that unambiguous rather than leaving you to guess.
An endpoint is slow and its trace contains many near-identical database spans, one per item in a collection. Database time dominates. The fix is eager loading or a single batched query, and only the trace makes the pattern obvious.
Latency spikes with no matching change in request logic, because the runtime is the cause, GC pauses in a JVM or .NET service, event-loop lag in Node.js, thread-pool starvation. Overlaying runtime metrics on the latency histogram distinguishes this from a slow dependency.
Reasonable starting thresholds to tune to your SLOs:
| Condition | Signal | Meaning |
|---|---|---|
| 5xx rate by endpoint > 2% for 5m | errors | An endpoint is failing, not just slow. |
| p99 latency > SLO for 10m | latency | Sustained latency regression on an endpoint. |
| DB time / request > 0.6 for 10m | database | Requests dominated by database work. |
| GC or event-loop time > 10% of wall time | runtime | The runtime is hurting latency. |
Ops Singularity's TelemetryOps pillar ingests this OpenTelemetry APM data natively, and Sentinel AI resolves the incidents it reveals, a slow endpoint, an N+1 query, a failing dependency, a runtime problem, through governed Action Tickets validated by Sherlock. Explore TelemetryOps and ServiceOps.
OpenTelemetry replaces the proprietary APM agent and produces the traces and metrics APM needs; you still send that telemetry to a backend for storage, dashboards and analysis. It removes the lock-in, not the need for a backend.
Per-endpoint latency percentiles (p95/p99) alongside error rate. Averages hide the slow tail that users actually feel, which is why APM watches percentiles.
Bring a real incident. We will show you Sentinel investigate, act and verify end to end, with every action reversible and audited.