How to derive average value from strings

New to Loki, but having trouble finding an answer to what I’m trying to do in the docs:

I’m logging CPU pressure from my application and would like to show the average pressure over a period of time, say 15m, as a gauge. CPU pressure is being logged as 1 of 4 possible values: "nominal", "fair", "serious", or "critical" in a JSON object in my logs. A sample log that reports CPU pressure looks like this:

{
  "extra": {
    "data": {
      "state": "fair",
      "time": 1697147863116.569
    }
  },
  "message": "CPU pressure changed"
}

How can I then take a group of these logs over a specified range like 15m and calculate an average value to display in a gauge? For example, if nominal = 1, fair = 2, serious = 3, and critical = 4, and I have 2 fair logs, 4 nominal logs, and 1 critical log, then the average value would be ~1.7 out of 4 which I would like to display in a gauge.

Can this be achieved in a query, or is it something that must be done in Grafana, or in the logs themselves? Thanks for your help!

I don’t know how the data is collected, but if it can come in as some sort of usage percentage it would be a lot easier. But if that’s not possible, you can do if/else statement with line_format or label_format, like so:

| json | label_format state=`{{ if eq .extra_data_state "fair" }}3{{ else if eq .extra_data_state "serious" }}5{{end}}`

You can then use other metrics function such as avg or sum to aggregate the number.

1 Like

Thanks, this got me in the right direction. The query I ended up using to display a gauge:

avg_over_time(json | message = `CPU pressure changed` | label_format pressureLevel=`{{ if eq .extra_data_state "nominal" }}0{{ else if eq .extra_data_state "fair" }}0.25{{ else if eq .extra_data_state "serious" }}0.5{{ else if eq .extra_data_state "critical" }}0.75{{ else }}1{{end}}` | unwrap pressureLevel [$__range]) by (message)
2 Likes