TheNiceGuy
TheNiceGuy

Reputation: 3730

Grafana - InfluxDB 2 - Label/Alias data

I am in the processing of migrating my panels from using the SQL syntax (from InfluxDB version 1.X) to the new influx syntax (InfluxDB version 2).

There is an issue with the labels of the data. It includes the attributes that I used to filter it. For example, if I select data from a range that contains 2 days, it splits the data up. See the screenshot below:

enter image description here

This completely messes the chart up. The base code looks like this:

from(bucket: "main")
  |> range(start: v.timeRangeStart, stop:v.timeRangeStop)
  |> filter(fn: (r) =>
      r._measurement == "POWER" and
      r._field == "value" and
      r.device == "living_room"
  )
  |> aggregateWindow(every: v.windowPeriod, fn: sum)

It should obviously just be "POWER" and "CURRENT".

I tried a dozen of different approaches, but cannot come up with a working solution.

For example, if I do:

from(bucket: "main")
  |> range(start: v.timeRangeStart, stop:v.timeRangeStop)
  |> filter(fn: (r) =>
      r._measurement == "POWER" and
      r._field == "value" and
      r.device == "living_room"
  )
  |> aggregateWindow(every: v.windowPeriod, fn: sum)
  |> map(fn: (r) => ({ POWER: r._value }))

it says "Data does not have a time field".

I also tried using

from(bucket: "main")
  |> range(start: v.timeRangeStart, stop:v.timeRangeStop)
  |> filter(fn: (r) =>
      r._measurement == "POWER" and
      r._field == "value" and
      r.device == "living_room"
  )
  |> aggregateWindow(every: v.windowPeriod, fn: sum)
  |> yield(name: "POWER")

that does not work either. I tried many other things without success.

How can I fix this?

Upvotes: 20

Views: 20393

Answers (7)

Sebastian Kollmar
Sebastian Kollmar

Reputation: 111

Grafana can solve this issue, too. You can use the "property override" function with regex to override the label.

You can find information to regex in grafana here: https://grafana.com/docs/grafana/latest/dashboards/variables/add-template-variables/#filter-variables-with-regex

A solution for your label could be something like this:

/(POWER)/

(depending on your version of grafana. Tested on version 8.1.1)

Upvotes: 2

Espinosa
Espinosa

Reputation: 2613

In case you struggle with JVM metrics/readings from Micrometer library, and want to display results in InfluxDB/Grafana with Flux query, this post might help you.

This is how looks output of a basic query (for JVM heap):

from(bucket: "bucket123")
  |> range(start: v.timeRangeStart, stop:v.timeRangeStop)
  |> filter(fn: (r) =>
    r._measurement == "jvm_memory_used" and
    r.env == "HOME" and
    r.area == "heap"
  )

enter image description here

We have 3 basic key series here with very horribly looking default names:

  • value {area="heap", env="HOME", id="G1 Eden Space", metric_type="gauge"}
  • value {area="heap", env="HOME", id="G1 Old Gen", metric_type="gauge"}
  • value {area="heap", env="HOME", id="G1 Survivor Space", metric_type="gauge"}

Let's improve this by adding a special mapping function:

from(bucket: "bucket123")
  |> range(start: v.timeRangeStart, stop:v.timeRangeStop)
  |> filter(fn: (r) =>
    r._measurement == "jvm_memory_used" and
    r.env == "HOME" and
    r.area == "heap"
  )
  |> map(fn: (r) => ({ _value:r._value, _time:r._time, _field:r.id }))

enter image description here

We still have the 3 basic key series but now with better looking names in the graph legend and as table columns:

  • G1 Eden Space
  • G1 Old Gen
  • G1 Survivor Space

Basically, what the mapping does is to drop all tags from every measurement and rename the main measurement field with value of tag "id".

We can drop all tags because we have already filtered data using those tags, we don't need them in the output (graph or table).

Upvotes: 0

user21926616
user21926616

Reputation: 1

Thanks for your input - I was pulling my hair out with the same issue!! The Grafana Override is great solution until you start to get cleaver with dashboard variables and then the wheels fall off. With your help above i finally cracked it. I hope this helps others. My solution has 3 parts:-

  1. Drop unrequired columns
    drop(columns: ["Tag1", "master", "Tag2","sensor","Tag3 etc"])
  2. Make the dynamic values that are causing issues static:
    |> map(fn: (r) => ({ r with TheTagThatKeepChanging:"ThisNeverChanges" }))
  3. Set up the overrides in Grafana to give meaningful name and then SAVE the dashboard and reopen before you start changing any variable to dynamically update the query.

Upvotes: 0

Marky0
Marky0

Reputation: 2084

I found that the critical thing is to make sure that the final table parsed to grafana only has columns with the data you want to plot. All Flux functions will add in columns "_start" and "_stop" which will appear in the the grafana label. So the best way to clean up the table is to rename the column to the label you want to appear in Grafana, and then use the keep function to delete unused columns. This is an example for plotting just one series "My_data" but can be extended to keep multiple series/labels.

from(bucket: "main")
    |> range(start: v.timeRangeStart , stop: v.timeRangeStop )
    |> filter(fn: (r) => r["entity_id"] == "My_data" )
    |> filter(fn: (r) => r["_field"] == "value")
    |> rename(columns: {_value: "My_data"})         //rename _value column to the name you want to appear in grafana
    |> keep(columns : ["_time","My_data"])          //delete all columns in table other than the series you want to plot

Upvotes: 3

kdrapel
kdrapel

Reputation: 140

I had a similar issue where I wanted to apply a Regex to extract part of the serie name.This post helped me a lot, here's my snippet in case it helps someone else. The idea is just to create an additional column that contains the final label and use it to have a clean displayed name. Note that you can skip the extra column (and the additional map) by inlining the regex.replaceAllString directly within the line where the _field is set. I kept it like this for readability.

import "regexp"

from(bucket: "MYBUCKET")
  |> range(start: v.timeRangeStart, stop: v.timeRangeStop)
  |> filter(fn: (r) => r["_measurement"] =~ /This_Is.*EndOfMyMeasurement$/  )   
  |> filter(fn: (r) => r["_field"] == "value")
  |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)  
  |> map(fn: (r) => ({ r with humanReadable: regexp.replaceAllString(r: /.*This_(.*)_Something_(.*)_(.*)_EndOfMyMeasurement/, v: r["_measurement"], t: "$1 $2 (something $3)") }))
  |> map(fn: (r) => ({ _value:r._value, _time:r._time, _field:r.humanReadable }))
  |> yield(name: "x")

Upvotes: 0

ffisc
ffisc

Reputation: 392

A bit similar to Sebastian Kollmar's suggestion, but I'm not sure if this is exactly what he meant - a colleague of mine came up with this:

figure1

With few or no changes, this will probably achieve what you were looking for.

Edit: my original interpretation of the question was that the goal was simply to get rid of the text within brackets in the legend. If the goal is more fundamentally to change how data is grouped, see my comment below

Upvotes: 10

TheNiceGuy
TheNiceGuy

Reputation: 3730

After hours of trial and error, I was able to produce a working solution. I imagine that other users may stumble upon the same issue, I will therefore not delete the question and instead provide my solution.

I basically had to map the required fields and tags and assign the desired label, instead of just mapping the value that should be displayed (because then the date/time data is missing).

The solution looks like this:

from(bucket: "main")
  |> range(start: v.timeRangeStart, stop:v.timeRangeStop)
  |> filter(fn: (r) =>
      r._measurement == "POWER" and
      r._field == "value" and
      r.device == "living_room"
      )
  |> aggregateWindow(every: v.windowPeriod, fn: max)
  |> map(fn: (r) => ({ _value:r._value, _time:r._time, _field:"Power (W)" }))

Power (W) is the label/alias that is going to be used.

I wish that Influx would provide an easier way to alias the desired field. The current approach is not very intuitive.

Upvotes: 25

Related Questions