grafana / influxdb-flux-datasource

Grafana datasource plugin for Flux (InfluxDB)
Apache License 2.0
51 stars 21 forks source link

Howto add alias? #42

Open andig opened 5 years ago

andig commented 5 years ago

Wondering how I could alias a query to make it visually more appealing, i.e. rename data value title=HcStarts type=workinghourstotal uuid=dcbb3a00-c45a-11e6-9917-dba8816dc812 to HcStarts?

andig commented 5 years ago

This is also a commity question, see https://community.grafana.com/t/no-alias-by-when-using-flux/15575

andig commented 5 years ago

A further problem with not having aliases is that you cannot style different queries on the same measurement differently as they will appear as the same query in the visualisation editor. Feedback would be welcome.

paregupt commented 5 years ago

I am stuck due to this while integrating flux in Grafana dashboard. Looking for a way to make it work.

HogeBlekker commented 4 years ago

Yes, same issue here!

mdb5108 commented 4 years ago

I was able to work around this by renaming the columns that the flux plugin does put in the legend for a series. Assuming that what you are changing the "title" of the series to will be unique across the series, this will not cause any issue. If this is not the case though, it will merge the data as the "title" acts as a key.

The trick is to remove all the columns except the necessary ones, replacing the specilal _field column which is displayed by whatever unique string you want. In @andig case it would be r.title. This is done in the map. Note that naming each part isn't necessary, just easier to show what I'm doing.

FinalOutput = ["_field", "_time", "_value"]

RawSeries = from(bucket: "telegraf")
    |> range($range)
    |> filter(fn: (r) => r._measurement='wtv' and r._field='wtvValue')

NamedSeries = RawSeries
    |> map(fn: (r) => ({_value:r._value, _time:r._time, _field:r.title}))
    |> keep(columns:FinalOutput)

NamedSeries |> yield()
jwblaney commented 4 years ago

+1 on this issue. Can't really have a customer-facing dashboard with current label format.

leovin commented 4 years ago

https://github.com/grafana/influxdb-flux-datasource/blob/master/src/response_parser.ts#L30

Changing alias to measurement name only should be trivial, but I wonder what was the reason for such format ... "_measurement + _field + tag keys/values"

Especially given const alias = getNameFromRecord(series[0]); https://github.com/grafana/influxdb-flux-datasource/blob/master/src/response_parser.ts#L187

brettlg commented 4 years ago

I was able to work around this by renaming the columns that the flux plugin does put in the legend for a series. Assuming that what you are changing the "title" of the series to will be unique across the series, this will not cause any issue. If this is not the case though, it will merge the data as the "title" acts as a key.

The trick is to remove all the columns except the necessary ones, replacing the specilal _field column which is displayed by whatever unique string you want. In @andig case it would be r.title. This is done in the map. Note that naming each part isn't necessary, just easier to show what I'm doing.

FinalOutput = ["_field", "_time", "_value"]

RawSeries = from(bucket: "telegraf")
    |> range($range)
    |> filter(fn: (r) => r._measurement='wtv' and r._field='wtvValue')

NamedSeries = RawSeries
    |> map(fn: (r) => ({_value:r._value, _time:r._time, _field:r.title}))
    |> keep(columns:FinalOutput)

NamedSeries |> yield()

@ mdb5108

Hi,

Your solution is kinda getting me in the right direction. I am wanting to use flux and grafana to graph rainfall. I'm also wanting to do timeshift and overlay several days with the appropriate legend. It seems I must use flux or another DB to do timeshifting. Your solution has got me a little closer to the end goal but unfortunately, I am not fluent enough to get the DB to answer the questions I want to ask . Instead of FinalOutput = ["_field", "_time", "_value"] with _value = r.title I would like to have _value = eg Today, yesterday, this week. I would appreciate any help you could offer. Thanks Brett

mdb5108 commented 4 years ago

@brettlg

It's been awhile since I've looked at this, and I haven't tested this code, but I suspect you could do something like this. Using the time manipulation documented here: https://docs.influxdata.com/flux/v0.50/guides/manipulate-timestamps/. Note that I offset in the range to get the data, and then reset it back in the map function so that the timeshift is overlayed on top of the normal range.

import "experimental"

FinalOutput = ["_field", "_time", "_value"]

createNormal = (table=<-, fnTimeSkew, postfix) =>
    table
    |> filter(fn: (r) => r._measurement='wtv' and r._field='wtvValue')
    |> map(fn: (r) => ({_value:r._value, _time:fnTimeSkew(r._time), _field:r.title+postfix}))
    |> keep(columns:FinalOutput)

createTimelapse = (table=<-, start, stop, offset, offsetString) =>
    table
    |> range(start: experimental.addDuration(d: offset, from:start)
             stop:  experimental.addDuration(d: offset, from:stop))
    |> createNormal(fnTimeSkew: (t) => (experiment.addDuration(d: offset, to: t)), offsetString)

normal = from(bucket: "telegraf")
    |> createNormal(fnTimeSkew: (t) => t, "")
weekOff = from(bucket: "telegraf")
    |> createTimelapse($range, offset:7d, "7d")
dayOff = from(bucket: "telegraf")
    |> createTimelapse($range, offset:1d, "1d")

union(tables: [normal, weekOff, dayOff])
    |> yield()
brettlg commented 4 years ago

Hi, Thanks for your time looking at this for me, very much appreciated.

Below is the query I am using in Grafana that give me the one day graph I am wanting. I am using the latest addon versions of both Grafana and Influxdb in the latest release of homeassistant.

from(bucket: "homeassistant/autogen") |> range($range) |> filter(fn: (r) => r.entity_id == "rain_guage" and r._field == "value" ) |> aggregateWindow(every: 30m, fn:mean)

Based on that I have modified your example to the following removing "+postfix". I am assuming that what is in quotes at the end of |> createTimelapse($range, offset:1d, "7d") ie "7d" is what should appear in the legend. I am only getting an error message "time info: undefined".

import "experimental" FinalOutput = ["_field", "_time", "_value"] createNormal = (table=<-, fnTimeSkew, ) => table |> filter(fn: (r) => r.entity_id='rain_guage' and r._field='value') |> map(fn: (r) => ({_value:r._value, _time:fnTimeSkew(r._time), _field:r.title})) |> keep(columns:FinalOutput) createTimelapse = (table=<-, start, stop, offset, offsetString) => table |> range(start: experimental.addDuration(d: offset, from:start) stop: experimental.addDuration(d: offset, from:stop)) |> createNormal(fnTimeSkew: (t) => (experiment.addDuration(d: offset, to: t)), offsetString) normal = from(bucket: "homeassistant/autogen") |> createNormal(fnTimeSkew: (t) => t, "") weekOff = from(bucket: "homeassistant/autogen") |> createTimelapse($range, offset:1d, "7d") union(tables: [normal, weekOff]) |> yield()

Getting closer I think but still scratching my head.

Once again your help is much appreciated. I have a long way to go to become as proficient at this as I would like too.

mdb5108 commented 4 years ago

Unfortunately I'm not sure. What I will say is that I was not confident that $range = "start: , stop: " which this solution depends on. You may look into that further. The error should give you a line and column that it is on though I think. That will help too. Another thing is that I don't know how reliable the experimental namespace actually is, and for all I know it requires some other things to work.

Also, you have a lot of syntax errors in the code that you pointed. createNormal has an extra comma after fnTimeSkew, createTimelapse still takes in a offsetString and passes it to createNormal even though createNormal no longer has that parameter, the creation of the normal table still calls createNormal with an empty string although it no longer takes the parameter, in the weekOff call to createTimelapse you pass on offset of 1 day but you then pass the string 7d (for 7 days) which you should probably not pass at all and rename the table to dayOff.

meersjo commented 4 years ago

I was able to work around this by renaming the columns that the flux plugin does put in the legend for a series. Assuming that what you are changing the "title" of the series to will be unique across the series, this will not cause any issue. If this is not the case though, it will merge the data as the "title" acts as a key.

I was able to fix it a little simpler than using map() - using set() at the very end of the pipe works just as well:

  |> set(key: "_field", value: "mem_total")

In fact, I had some trouble with map() in a graph with multiple queries (might be my own fault, but I couldn't figure it out); set() worked instantly.

M0rdecay commented 4 years ago

+1 to this request. The solution proposed in the commentary works partially, since it does not cover situations when an alias needs to be set based on several tags.

UPD. The solution described above does not work with the Stat panel. The name _field is not perceived as a unique series identifier for grouping.

helotpl commented 4 years ago

+1 here as well. Only sensible solution is to delete columns from result such as _measurement and replace name for _field (with map). A simple alias column could change whole behavior so this field is only one presented on graph.

kwaaak commented 4 years ago

@brettlg I am using Flux to show the current temperature and yesterday's temperature in the same graph. Thanks to @mdb5108 for the code.

Maybe you can rework it to display your rain data. The data comes from a luftdaten.info station with a BME280 sensor.

FinalOutput = ["_field", "_time", "_value"]

RawSeries = from(bucket: "luftdaten")
  |> range(start: -48h, stop: -24h)
  |> timeShift(duration: 24h)
  |> filter(fn: (r) =>
      r._measurement == "feinstaub" and
      r._field == "BME280_temperature"
      )

NamedSeries = RawSeries
  |> map(fn: (r) => ({_value:r._value, _time:r._time, _field:"Gestrige Außentemperatur"}))
  |> keep(columns:FinalOutput)

NamedSeries |> yield()

image

dvdl16 commented 4 years ago

I tried the mapping and column deletion approach, but I get "Metric request error":

Object
status:500
statusText:"Internal Server Error"
data:Object
message:"Metric request error"
isHandled:true
message:"Metric request error"

This is my query (that works fine in InfluxDB Data Explorer):

FinalOutput = ["_field", "_time", "_value"]

RawSeries = from(bucket: "Bucket")
    |> range(start: -48h, stop: -24h)
    |> filter(fn: (r) =>
        r._measurement == "ble_sensor" and
        r._field == "temperature" and
        r.ble_id == "XX:XX:XX:XX:XX:XX"
    )

NamedSeries = RawSeries
    |> map(fn: (r) => ({_value:r._value, _time:r._time, _field:"My Temperature"}))
    |> keep(columns:FinalOutput)

NamedSeries |> yield()

The reason I want to have an alias is to avoid this resizing behavior on mobile, caused by the long title being generated by adding all tags:

Grafana issue
dvdl16 commented 4 years ago

The workaround defined above works for me in Grafana v7.1.0 (8101355285), with the new integrated InfluxDB data source