mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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:
@@ -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 |
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
|
|||||||
@@ -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: "",
|
||||||
}, {
|
}, {
|
||||||
|
|||||||
Reference in New Issue
Block a user