I am using Grafana v10.4.1. I use the PostgreSQL datasource.
I am using it to connect to our build system’s database (buildbot).
This contains information about build results.
I am using a query like this
SELECT
builders.name as builder_name,
TO_TIMESTAMP(builds.complete_at) as complete_time,
builds.results
FROM
builds
INNER JOIN builders ON builds.builderid = builders.id
I then transform it into a multi-frame time series and visualize it as a state timeline.
This is what it looks like. I know the message is because the complete_at is outside the grafana dashboard time range. However I want to also see build’s last state that are outside this time range so this is intentional.
What would be the solution here?
You need to add a WHERE clause to filter the data for the current time range.
This is the answer that you typically get in these cases. But it doesn’t always fix the issue in all cases.
The state timeline only draws from data points it receives. If a builder’s last result happened before your dashboard’s time range starts, there’s no point for it to draw from, hence “Data outside time range.”
Fix: → inject a synthetic point at the start of the range for each builder, carrying forward its last known result. Use UNION ALL → one branch gets the last row per builder before the range starts, the other is your normal in-range query →
sql
SELECT * FROM (
SELECT DISTINCT ON (builders.name)
builders.name AS builder_name,
TO_TIMESTAMP($__unixEpochFrom() + 1) AS complete_time,
builds.results
FROM builds
INNER JOIN builders ON builds.builderid = builders.id
WHERE builds.complete_at < $__unixEpochFrom()
ORDER BY builders.name, builds.complete_at DESC
) AS last_known
UNION ALL
SELECT
builders.name AS builder_name,
TO_TIMESTAMP(builds.complete_at) AS complete_time,
builds.results
FROM builds
INNER JOIN builders ON builds.builderid = builders.id
WHERE builds.complete_at >= $__unixEpochFrom()
AND builds.complete_at <= $__unixEpochTo()
ORDER BY builder_name, complete_time
Two things that matter →
+ 1 on $__unixEpochFrom() → pinning the synthetic timestamp exactly on the boundary still gets flagged as “outside” the range by the panel; nudging it one second inside fixes it.
Apply the “Prepare time series → Multi-frame time series” transform to the query result → without it, the state timeline won’t split the flat SQL output into one series per builder.
Builders with no prior build at all correctly still show a gap, since there’s genuinely nothing to carry forward.