Reputation: 3730
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:
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
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
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"
)
We have 3 basic key series here with very horribly looking default names:
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 }))
We still have the 3 basic key series but now with better looking names in the graph legend and as table columns:
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
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:-
drop(columns: ["Tag1", "master", "Tag2","sensor","Tag3 etc"])
|> map(fn: (r) => ({ r with TheTagThatKeepChanging:"ThisNeverChanges" }))
Upvotes: 0
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
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
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:
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
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