Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to do multi graph time series on Grafana with Kusto

Well, I want to do this: https://grafana.com/docs/grafana/v9.0/basics/timeseries-dimensions/, but on Kusto.

The problem is that I don't know where I'm failing, the unique point is that I have the following warning:

Detected long formatted time series but failed to convert from long frame: long series must be sorted ascending by time to be converted.

The point is that my query returns the following:

...

let test = datatable (Timestamp: datetime, Id: string, Value: dynamic)
[
  datetime(2022-11-09 11:39:25), "machineA", "True",
  datetime(2022-11-09 11:39:30), "machineA", "True",
  datetime(2022-11-09 11:39:35), "machineA", "False",
  datetime(2022-11-09 11:39:36), "machineA", "False",
  datetime(2022-11-09 11:40:03), "machineA", "True",
  datetime(2022-11-09 11:40:03), "machineA", "True",
  datetime(2022-11-09 11:40:04), "machineA", "True",
  datetime(2022-11-09 11:40:05), "machineA", "True",
  datetime(2022-11-09 11:40:25), "machineA", "False",
  datetime(2022-11-09 11:40:25), "machineA", "False",
  datetime(2022-11-09 11:40:26), "machineA", "False",
  datetime(2022-11-09 11:40:27), "machineA", "False",
  datetime(2022-11-09 11:40:37), "machineA", "True",
  datetime(2022-11-09 11:40:47), "machineA", "False",
  datetime(2022-11-09 11:40:57), "machineA", "True",
  datetime(2022-11-09 11:40:59), "machineA", "True",
  datetime(2022-11-09 11:40:25), "machineB", "True",
  datetime(2022-11-09 11:40:30), "machineB", "True",
  datetime(2022-11-09 11:40:35), "machineB", "False",
  datetime(2022-11-09 11:40:36), "machineB", "False",
  datetime(2022-11-09 11:41:03), "machineB", "True",
  datetime(2022-11-09 11:41:03), "machineB", "True",
  datetime(2022-11-09 11:41:04), "machineB", "True",
  datetime(2022-11-09 11:41:05), "machineB", "True",
  datetime(2022-11-09 11:41:25), "machineB", "False",
  datetime(2022-11-09 11:41:25), "machineB", "False",
  datetime(2022-11-09 11:41:26), "machineB", "False",
  datetime(2022-11-09 11:41:27), "machineB", "False",
  datetime(2022-11-09 11:41:37), "machineB", "True",
  datetime(2022-11-09 11:41:47), "machineB", "False",
  datetime(2022-11-09 11:41:57), "machineB", "True",
  datetime(2022-11-09 11:41:59), "machineB", "True",
  datetime(2022-11-09 11:42:25), "machineC", "True",
  datetime(2022-11-09 11:42:30), "machineC", "True",
  datetime(2022-11-09 11:42:35), "machineC", "False",
  datetime(2022-11-09 11:42:36), "machineC", "False",
  datetime(2022-11-09 11:43:03), "machineC", "True",
  datetime(2022-11-09 11:43:03), "machineC", "True",
  datetime(2022-11-09 11:43:04), "machineC", "True",
  datetime(2022-11-09 11:43:05), "machineC", "True",
  datetime(2022-11-09 11:43:25), "machineC", "False",
  datetime(2022-11-09 11:43:25), "machineC", "False",
  datetime(2022-11-09 11:43:26), "machineC", "False",
  datetime(2022-11-09 11:43:27), "machineC", "False",
  datetime(2022-11-09 11:43:37), "machineC", "True",
  datetime(2022-11-09 11:43:47), "machineC", "False",
  datetime(2022-11-09 11:43:57), "machineC", "False",
  datetime(2022-11-09 11:43:59), "machineC", "False",
];
let tiemposCicloBruto = test
    | where Timestamp > ago(100d)
    | partition hint.strategy=native by Id
    (
        order by Timestamp asc // ordenamos ascendentemente
        | extend prev_Timestamp = prev(Timestamp) // extendemos la fecha previa
        | extend prev_Value = prev(Value) // extendemos el valor previo
        | extend duration = 
        iif( // Condicion ternaria
            prev_Value == "True" and Value == "False" // Si anteriormente estaba en funcion y el valor actual es parado, cuenta como tiempo de ciclo
            or prev_Value == "True" and Value == "True", // Si el valor anterior era funcionando y el actual tambien, la maquina sigue funcionando
            Timestamp - prev_Timestamp, // Para ese caso restamos la diferencia de tiempo
            time(null) // Para el caso contrario, devolvemos nulo
        )
        | project Id, Timestamp, duration, Value, prev_Value
    );
tiemposCicloBruto // La consulta para 1d completo tarda entre 1-1.5s
| where isnotnull(duration)
| partition hint.strategy=native by Id ( // partimos por Id
    order by Timestamp asc // debe ser siempre ascendente si no pierde la logica
    | scan declare (y:timespan=time(null), x:timespan=time(null)) with ( // declaramos el scan
        step s1: true => // declaramos el paso
        x=iif(s1.Value == "True" and Value == "True", iif(isnull(s1.x), duration, s1.x)+s1.duration, time(null)), // si tenemos varios True-True consecutivos, sumamos la duracion anterior a la actual, asignandola a X
        y=iif(s1.Value=="False" and Value=="False", duration, // si tenemos el caso de que es False-False, partimos de la duracion
                iif(s1.Value=="True" and Value=="False", s1.x+duration, time(null))); // si tenemos que la maquina estaba funcionando y para, sumamos las duraciones consecutivas de mientras que estaba funcionando
    )
    | extend next_Id=next(Id)
    | extend tiempoCiclo=iif(isempty(next_Id), duration, iif(isnull(y) and prev_Value == "True" and Value=="False", duration+prev(duration), iif(isnotnull(y), y, time(null)))) / 1s // y para aquellos cambios de maquina o para aquellos donde no hubiera valor por casuistica, asignamos la duracion o la duracion+duracion previa
    | where isnotnull(tiempoCiclo) // filtramos
    | project-away prev_Value, x, y, duration, Value, next_Id
)

But I cannot see those machine groupings on my KQL Grafana Time series graph:

...

At least, it should show as much as machines in my environment:

enter image description here

like image 549
z3nth10n Avatar asked Sep 04 '25 01:09

z3nth10n


2 Answers

The answer is contained in your question:

Detected long formatted time series but failed to convert from long frame: long series must be sorted ascending by time to be converted.

You need to add sorting at the end of your query. It is as easy as this.

...
| order by Timestamp asc

Also make sure to select "Time series" in "Format as" drop-down.

enter image description here

like image 190
greatvovan Avatar answered Sep 07 '25 18:09

greatvovan


Generally I found that Grafana expects multiple series to be distinct columns rather than one discriminator column. One option would be to use the pivot plugin.

Adding

| evaluate pivot(Id, max(tiempoCiclo))

to the end of your query yields the following dataset:

pivot data set

which results in the following grafana graph:

enter image description here

like image 21
ChrisWue Avatar answered Sep 07 '25 17:09

ChrisWue