Dash0 acquires Polar Signals

Last updated: September 8, 2026

What Is Real-Time Monitoring?

Real-time monitoring means the delay between something happening in production and you being able to see and act on it is short enough to matter. The load-bearing words are "short enough," because nothing in a telemetry pipeline is instant. Every stage between the event and your screen buffers, batches, or waits for a timer, and those waits add up.

So the question worth asking about your setup isn't whether it's real time. It's how many seconds behind reality you are, and which stage is spending them. Most teams have never measured this, and the number tends to surprise people: a stock OpenTelemetry and Prometheus configuration can sit four to six minutes behind an event with nothing misconfigured and no component failing. The defaults just stack.

This article walks the delay stage by stage, explains why logs, traces, and metrics arrive on completely different schedules, and covers the timestamp behavior that makes pipelines look faster or slower than they are.

The latency budget of a monitoring pipeline

Treat "real time" as a budget you spend on the path from event to human. In a default OpenTelemetry setup, it goes roughly like this.

StageDefault delayWhat controls it
In-process buffering5s spans, 1s logs, 60s metricsOTEL_BSP_SCHEDULE_DELAY, OTEL_BLRP_SCHEDULE_DELAY, OTEL_METRIC_EXPORT_INTERVAL
Collector batching200msbatch processor timeout
Export and backend ingestmilliseconds to secondsnetwork, compression, write path
Query freshness0 to your refresh intervaldashboard refresh, PromQL lookback
Alert evaluation60sevaluation_interval
Grace period before firingwhatever you setfor
Notification grouping30sAlertmanager group_wait

The in-process numbers come from the SDK specs: the batch span processor flushes every 5 seconds by default in batches of up to 512 spans, the batch log record processor flushes every second, and the periodic metric reader exports every 60 seconds. The Collector's batch processor sends after 200ms or 8192 items, whichever comes first. Prometheus defaults both scrape_interval and evaluation_interval to one minute, and if you're collecting Prometheus metrics through the Collector instead, the receiver's scrape interval takes that slot in the budget.

Now put a real incident through it. Your checkout service starts throwing 500s at 14:00:05. The error counter sits in the SDK until the next 60-second export, so it leaves the process at 14:01:00. It reaches the backend a second later. The check rule evaluates on the minute, so 14:02:00 is the first evaluation that sees a full bad window. You set for: 2m to avoid paging on noise, so it fires at 14:04:00. Alertmanager holds it for group_wait, and the page lands around 14:04:30.

Four and a half minutes, with every component behaving exactly as documented. The 60-second metric export interval is the largest single item on that list and the one almost nobody touches. If you want to cut your mean time to detection, that's the first knob, not the dashboard refresh rate.

Logs, traces, and metrics are not equally fast

The three signals have different latency profiles, and the differences are structural rather than a matter of configuration.

Logs are the quickest thing you have. A one-second default flush means a log line is usually queryable within a couple of seconds of being written. That's why live tailing is what people actually reach for when they're mid-incident, even in shops that spent a year building metric dashboards.

Traces are late by design, and they're latest for the requests you care about most. A span only enters the export queue when it ends. A request that hangs for 30 seconds contributes nothing for 30 seconds, and the root span ends last, so a complete distributed trace is only assemblable after the slowest operation in it finishes. Your pathologically slow requests are the ones you'll see last.

Metrics are the slowest by default and also the most likely to look broken while they're catching up. One export per minute, combined with OTLP's cumulative temporality default, means a rate() over a [1m] range often has only a single data point in the window and returns nothing at all. This is the range alignment problem: your query needs at least two samples, so with 60-second exports you need a two-minute window or $__rate_interval before a rate is computable.

Notice that this ordering is the inverse of how most people build their front page. Metrics get the hero dashboard, logs get buried three clicks deep, and logs are the signal that arrives first.

What you're actually buying with lower latency

Real-time monitoring serves two jobs that want different things from the budget.

Detection is the alerting path, and its budget is properly measured in minutes. Some delay here is not a defect, it's judgment: a check that fires on one bad evaluation will page someone for a garbage collection pause. A grace period buys you signal quality with time, and that's usually the right trade. Related work like anomaly detection and availability monitoring sits on the same path and inherits the same budget. Synthetic monitoring is the one exception worth knowing about, since you set the check frequency directly and the detection interval is whatever you chose rather than something you have to reconstruct.

Diagnosis is different. Once you're in the incident, you're watching a stream, shipping a fix, and watching whether it landed. The feedback loop is a human, so seconds are the unit and staleness is actively misleading. Deploying a rollback and staring at a chart that won't update for another 90 seconds is how people conclude the rollback didn't work and start making things worse.

Which is why a one-second dashboard refresh sitting on top of a five-minute pipeline is theatre. It repaints the same stale number 60 times a minute. Fix the pipeline first, and then let the cadence follow the data rather than a number you picked: Dash0's adaptive auto-refresh paces each view to its own resolution, so a high-resolution chart keeps up while an hour-wide one updates calmly.

Common pitfalls

Event time and ingest time are different clocks. Telemetry carries the timestamp of when it happened, but it arrives whenever the pipeline delivers it. If your most recent chart bucket always dips, that's almost never traffic falling off a cliff. It's the bucket still filling with data that hasn't arrived yet. Truncate or offset the incomplete window instead of re-explaining it to a different stakeholder every week.

Widening the range selector can raise your evaluation floor. The instinct when an alert is noisy is to look back further, changing [5m] to [1h] or [6h]. Each evaluation then scans more data, and managed backends put a floor under how often you can afford to run it. Dash0's check rule limits are explicit about the trade: a query window of 1h 10m or less can evaluate every minute, but past that the minimum interval moves to 5 minutes, then 10 minutes above 8h 10m, and an hour above 24h 10m. The edit you made to quiet an alert can multiply your detection latency by five. Check the floor before you widen the window, and use a grace period instead when what you really want is "sustained, not spiky."

Push-based metrics flatline instead of disappearing. Prometheus answers an instant query by looking back up to five minutes for the last sample, and stamps that value with the query time. When a scrape target vanishes, Prometheus writes staleness markers so the series drops out immediately. Data arriving by OTLP or remote write gets no such marker, so a crashed emitter holds its last healthy value for five minutes and the dashboard renders it as current. This is Prometheus behavior specifically, and other backends handle staleness for pushed metrics differently. Spend ten minutes finding out how yours does: stop an emitter in staging and watch what the chart actually does. Either way, alert on absence explicitly rather than trusting a green number.

Disabling batching to "make it real time." Switching to a simple span processor, or setting the scheduled delay to zero, means one network round trip per span. You'll pay for it in main-thread time, and under load the export queue fills and starts dropping spans, so you get less data with more overhead. Dropping the span delay to one second and the metric interval to 15 seconds captures most of the available win. The batch processor guide covers the tuning in detail.

Measuring the pipeline with the pipeline. If you want to know how far behind you are, compute the difference between event timestamp and ingest timestamp at arrival and track it as its own metric. Don't infer it from a dashboard subject to the same delay you're trying to measure, and don't take a vendor's "real time" claim at face value. It usually describes their ingest hop, which is one row in the table above.

Final thoughts

Real-time monitoring is a latency budget, not a product feature. The useful skill is knowing your number and where it's spent: in-process buffering, batching, ingest, query freshness, evaluation interval, grace period, notification grouping. Once you can name the number, the tuning decisions get obvious, and so do the places where a little delay is buying you something worth having. This is also where the line between monitoring and observability shows up in practice, since a fast pipeline you can't ask new questions of just gets you to the wrong conclusion sooner.

Dash0 is OpenTelemetry-native, so application telemetry arrives over OTLP push rather than being scraped on a schedule you have to reason about. Where the Kubernetes operator scrapes Prometheus endpoints, that stage is a fixed one-minute interval, or five minutes with the prometheus.io/scrape-slow annotation, and the frequency isn't configurable, so it belongs in your budget as a known constant rather than a knob. Alerting builds on the Prometheus model, with grace periods expressed as multipliers of the evaluation interval, so the detection latency you're accepting is written down rather than inferred. Logs, metrics, traces, and Web Events land in one place, which means the Log Explorer you're watching during an incident and the trace behind it are the same query surface. If you'd rather have active problems come to you, Agent0's Live Insights refreshes its view of what's currently going wrong every 60 seconds.

Start a free trial and check your own event-to-alert latency. No credit card required.

Authors