graphLink and tableLink template functions (#41369)

* graphLink and tableLink functions, docs updated

* Code review changes

* extract query struct outside of graphLink and tableLink functions

* Fix docs

* Update docs/sources/alerting/unified-alerting/alerting-rules/alert-annotation-label.md

Co-authored-by: Jean-Philippe Quéméner <JohnnyQQQQ@users.noreply.github.com>

* Update docs/sources/alerting/unified-alerting/alerting-rules/alert-annotation-label.md

Co-authored-by: Jean-Philippe Quéméner <JohnnyQQQQ@users.noreply.github.com>

* Update docs/sources/alerting/unified-alerting/alerting-rules/alert-annotation-label.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Update docs/sources/alerting/unified-alerting/alerting-rules/alert-annotation-label.md

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Fix linting errors

Co-authored-by: Jean-Philippe Quéméner <JohnnyQQQQ@users.noreply.github.com>
Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>
This commit is contained in:
Santiago
2021-11-10 10:36:03 -03:00
committed by GitHub
parent 0d4533ae74
commit a45e4ff73f
3 changed files with 80 additions and 34 deletions

View File

@@ -33,28 +33,28 @@ The following template variables are available when expanding annotations and la
The following template functions are available when expanding annotations and labels. The following template functions are available when expanding annotations and labels.
| Name | Argument | Return | Description | | Name | Argument | Return | Description |
| ------------------ | -------------------------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | | ------------------ | ------------------------------------------------------------ | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| humanize | number or string | string | Converts a number to a more readable format, using metric prefixes. | | humanize | number or string | string | Converts a number to a more readable format, using metric prefixes. |
| humanize1024 | number or string | string | Like humanize, but uses 1024 as the base rather than 1000. | | humanize1024 | number or string | string | Like humanize, but uses 1024 as the base rather than 1000. |
| humanizeDuration | number or string | string | Converts a duration in seconds to a more readable format. | | humanizeDuration | number or string | string | Converts a duration in seconds to a more readable format. |
| humanizePercentage | number or string | string | Converts a ratio value to a fraction of 100. | | humanizePercentage | number or string | string | Converts a ratio value to a fraction of 100. |
| humanizeTimestamp | number or string | string | Converts a Unix timestamp in seconds to a more readable format. | | humanizeTimestamp | number or string | string | Converts a Unix timestamp in seconds to a more readable format. |
| title | string | string | strings.Title, capitalises first character of each word. | | title | string | string | strings.Title, capitalises first character of each word. |
| toUpper | string | string | strings.ToUpper, converts all characters to upper case. | | toUpper | string | string | strings.ToUpper, converts all characters to upper case. |
| toLower | string | string | strings.ToLower, converts all characters to lower case. | | toLower | string | string | strings.ToLower, converts all characters to lower case. |
| match | pattern, text | boolean | regexp.MatchString Tests for a unanchored regexp match. | | match | pattern, text | boolean | regexp.MatchString Tests for a unanchored regexp match. |
| reReplaceAll | pattern, replacement, text | string | Regexp.ReplaceAllString Regexp substitution, unanchored. | | reReplaceAll | pattern, replacement, text | string | Regexp.ReplaceAllString Regexp substitution, unanchored. |
| graphLink | expr | string | Not supported | | graphLink | string - JSON Object with `"expr"` and `"datasource"` fields | string | Returns the path to graphical view in [Explore](https://grafana.com/docs/grafana/latest/explore/) for the given expression and data source. |
| tableLink | expr | string | Not supported | | tableLink | string- JSON Object with `"expr"` and `"datasource"` fields | string | Returns the path to tabular view in [Explore](https://grafana.com/docs/grafana/latest/explore/) for the given expression and data source. |
| args | []interface{} | map[string]interface{} | Converts a list of objects to a map with keys, for example, arg0, arg1. Use this function to pass multiple arguments to templates. | | args | []interface{} | map[string]interface{} | Converts a list of objects to a map with keys, for example, arg0, arg1. Use this function to pass multiple arguments to templates. |
| externalURL | nothing | string | Returns a string representing the external URL. | | externalURL | nothing | string | Returns a string representing the external URL. |
| pathPrefix | nothing | string | Returns the path of the external URL. | | pathPrefix | nothing | string | Returns the path of the external URL. |
| tmpl | string, []interface{} | nothing | Not supported | | tmpl | string, []interface{} | nothing | Not supported |
| safeHtml | string | string | Not supported | | safeHtml | string | string | Not supported |
| query | query string | []sample | Not supported | | query | query string | []sample | Not supported |
| first | []sample | sample | Not supported | | first | []sample | sample | Not supported |
| label | label, sample | string | Not supported | | label | label, sample | string | Not supported |
| strvalue | []sample | string | Not supported | | strvalue | []sample | string | Not supported |
| value | sample | float64 | Not supported | | value | sample | float64 | Not supported |
| sortByLabel | label, []samples | []sample | Not supported | | sortByLabel | label, []samples | []sample | Not supported |

View File

@@ -2,6 +2,8 @@ package state
import ( import (
"context" "context"
"encoding/json"
"fmt"
"math" "math"
"net/url" "net/url"
"strconv" "strconv"
@@ -56,16 +58,13 @@ func expandTemplate(name, text string, labels map[string]string, alertInstance e
) )
expander.Funcs(text_template.FuncMap{ expander.Funcs(text_template.FuncMap{
// These three functions are no-ops for now. "graphLink": graphLink,
"tableLink": tableLink,
// This function is a no-op for now.
"strvalue": func(value templateCaptureValue) string { "strvalue": func(value templateCaptureValue) string {
return "" return ""
}, },
"graphLink": func() string {
return ""
},
"tableLink": func() string {
return ""
},
}) })
return expander.Expand() return expander.Expand()
@@ -87,3 +86,34 @@ func newTemplateCaptureValues(values map[string]eval.NumberValueCapture) map[str
} }
return m return m
} }
type query struct {
Datasource string `json:"datasource"`
Expr string `json:"expr"`
}
func graphLink(rawQuery string) string {
var q query
if err := json.Unmarshal([]byte(rawQuery), &q); err != nil {
return ""
}
escapedExpression := url.QueryEscape(q.Expr)
escapedDatasource := url.QueryEscape(q.Datasource)
return fmt.Sprintf(
`/explore?left=["now-1h","now",%[1]q,{"datasource":%[1]q,"expr":%q,"instant":false,"range":true}]`, escapedDatasource, escapedExpression)
}
func tableLink(rawQuery string) string {
var q query
if err := json.Unmarshal([]byte(rawQuery), &q); err != nil {
return ""
}
escapedExpression := url.QueryEscape(q.Expr)
escapedDatasource := url.QueryEscape(q.Datasource)
return fmt.Sprintf(
`/explore?left=["now-1h","now",%[1]q,{"datasource":%[1]q,"expr":%q,"instant":true,"range":false}]`, escapedDatasource, escapedExpression)
}

View File

@@ -355,11 +355,27 @@ func TestExpandTemplate(t *testing.T) {
text: "{{ query \"metric{instance='a'}\" | first | label \"instance\" }}", text: "{{ query \"metric{instance='a'}\" | first | label \"instance\" }}",
expected: "", expected: "",
}, { }, {
name: "check that graphLink returns an empty string", name: "graphLink",
text: `{{ graphLink "{\"expr\": \"up\", \"datasource\": \"gdev-prometheus\"}" }}`,
expected: `/explore?left=["now-1h","now","gdev-prometheus",{"datasource":"gdev-prometheus","expr":"up","instant":false,"range":true}]`,
}, {
name: "graphLink should escape both the expression and the datasource",
text: `{{ graphLink "{\"expr\": \"process_open_fds > 0\", \"datasource\": \"gdev prometheus\"}" }}`,
expected: `/explore?left=["now-1h","now","gdev+prometheus",{"datasource":"gdev+prometheus","expr":"process_open_fds+%3E+0","instant":false,"range":true}]`,
}, {
name: "check that graphLink returns an empty string when the query is not formatted correctly",
text: "{{ graphLink \"up\" }}", text: "{{ graphLink \"up\" }}",
expected: "", expected: "",
}, { }, {
name: "check that tableLink returns an empty string", name: "tableLink",
text: `{{ tableLink "{\"expr\": \"up\", \"datasource\": \"gdev-prometheus\"}" }}`,
expected: `/explore?left=["now-1h","now","gdev-prometheus",{"datasource":"gdev-prometheus","expr":"up","instant":true,"range":false}]`,
}, {
name: "tableLink should escape both the expression and the datasource",
text: `{{ tableLink "{\"expr\": \"process_open_fds > 0\", \"datasource\": \"gdev prometheus\"}" }}`,
expected: `/explore?left=["now-1h","now","gdev+prometheus",{"datasource":"gdev+prometheus","expr":"process_open_fds+%3E+0","instant":true,"range":false}]`,
}, {
name: "check that tableLink returns an empty string when the query is not formatted correctly",
text: "{{ tableLink \"up\" }}", text: "{{ tableLink \"up\" }}",
expected: "", expected: "",
}, { }, {