Skip to content

Commit

Permalink
redis: auto-completion and syntax highlighting
Browse files Browse the repository at this point in the history
  • Loading branch information
andreasgerstmayr committed Sep 22, 2020
1 parent dcf5ff4 commit 88f6d07
Show file tree
Hide file tree
Showing 15 changed files with 265 additions and 96 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ allow_loading_unsigned_plugins = pcp-redis-datasource

Restart Grafana server, and check the logs if the plugin loaded successfully.

### Deprecated features
- **redis**: Using `label_values(metric, label)` in a Grafana variable query is deprecated due to performance reasons. `label_values(label)` is still supported.

## 2.0.2 (2020-02-25)

- **vector, redis**: remove autocompletion cache (PCP metrics can be added and removed dynamically)
Expand Down
3 changes: 3 additions & 0 deletions docs/_static/custom.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.wy-table-responsive table td {
white-space: normal;
}
6 changes: 6 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']

# These paths are either relative to html_static_path
# or fully qualified paths (eg. https://...)
html_css_files = [
'custom.css',
]

# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
Expand Down
21 changes: 10 additions & 11 deletions docs/datasources/redis.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,13 @@ Query Functions
---------------
The following functions are available for dashboard variables of type *Query*:

=============================== ============================= =======================
Function Description Example
=============================== ============================= =======================
``metrics([pattern])`` | returns all metrics ``metrics(disk.*)``
| matching a glob pattern
| (if no pattern is defined,
| all metrics are returned)
``label_values(metric, label)`` | returns all label values ``label_values(kernel.all.uptime, hostname)``
| for the specified label
| of the specified metric
=============================== ============================= =======================
=========================== ==================================================== ==========================
Function Description Example
=========================== ==================================================== ==========================
``metrics([pattern])`` returns all metrics matching a glob pattern ``metrics(disk.*)``
(if no pattern is defined, all metrics are returned)

``label_names([pattern])`` returns all label names matching a glob pattern ``label_names(host*)``
(if no pattern is defined, all metrics are returned)
``label_values(label)`` returns all label values for the specified label ``label_values(hostname)``
=========================== ==================================================== ==========================
2 changes: 1 addition & 1 deletion pkg/datasources/redis/api/pmseries/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type MetricsResponseItem struct {
Name string `json:"name"`
}

type MetricNameMatchesResponse []string
type MetricNamesResponse []string

type DescsResponseItem struct {
Series string `json:"series"`
Expand Down
16 changes: 9 additions & 7 deletions pkg/datasources/redis/api/pmseries/pmseries.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ type API interface {
Ping() (GenericSuccessResponse, error)
Query(expr string) (QueryResponse, error)
Metrics(series []string) ([]MetricsResponseItem, error)
MetricNameMatches(match string) (MetricNameMatchesResponse, error)
MetricNames(pattern string) (MetricNamesResponse, error)
Descs(series []string) ([]DescsResponseItem, error)
Instances(series []string) ([]InstancesResponseItem, error)
Labels(series []string) ([]LabelsResponseItem, error)
LabelNames() (LabelNamesResponse, error)
LabelNames(pattern string) (LabelNamesResponse, error)
LabelValues(labelNames []string) (LabelValuesResponse, error)
Values(series []string, start int64, finish int64, interval int64) ([]ValuesResponseItem, error)
}
Expand Down Expand Up @@ -118,12 +118,12 @@ func (api *pmseriesAPI) Metrics(series []string) ([]MetricsResponseItem, error)
return resp, err
}

func (api *pmseriesAPI) MetricNameMatches(match string) (MetricNameMatchesResponse, error) {
var resp MetricNameMatchesResponse
func (api *pmseriesAPI) MetricNames(pattern string) (MetricNamesResponse, error) {
var resp MetricNamesResponse
err := api.doRequest(
fmt.Sprintf("%s/series/metrics", api.URL),
url.Values{
"match": []string{match},
"match": []string{pattern},
},
&resp,
)
Expand Down Expand Up @@ -166,11 +166,13 @@ func (api *pmseriesAPI) Labels(series []string) ([]LabelsResponseItem, error) {
return resp, err
}

func (api *pmseriesAPI) LabelNames() (LabelNamesResponse, error) {
func (api *pmseriesAPI) LabelNames(pattern string) (LabelNamesResponse, error) {
var resp LabelNamesResponse
err := api.doRequest(
fmt.Sprintf("%s/series/labels", api.URL),
url.Values{},
url.Values{
"match": []string{pattern},
},
&resp,
)
return resp, err
Expand Down
29 changes: 0 additions & 29 deletions pkg/datasources/redis/resource/adhoc.go

This file was deleted.

46 changes: 37 additions & 9 deletions pkg/datasources/redis/resource/metric_find_value.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
package resource

import (
"fmt"
"regexp"

"github.com/grafana/grafana-plugin-sdk-go/backend/log"
)

var metricNamesRegex = regexp.MustCompile(`^metrics\(\s*([a-zA-Z0-9._*]*)\s*\)$`)
var labelValuesRegex = regexp.MustCompile(`^label_values\(\s*([a-zA-Z][a-zA-Z0-9._]*)\s*\)$`)
var metricNamesRegex = regexp.MustCompile(`^metrics\(\s*([\w.*]*)\s*\)$`)
var labelNamesRegex = regexp.MustCompile(`^label_names\(\s*([\w.]*)\s*\)$`)
var labelValuesRegex = regexp.MustCompile(`^label_values\(\s*([\w.]+)\s*\)$`)
var labelValuesForMetricRegex = regexp.MustCompile(`^label_values\(\s*([a-zA-Z][a-zA-Z0-9._]*)\s*,\s*([a-zA-Z][a-zA-Z0-9._]*)\s*\)$`)

func (rs *Service) getMetricNames(pattern string) ([]MetricFindValue, error) {
if pattern == "" {
pattern = "*"
}

namesResponse, err := rs.pmseriesAPI.MetricNameMatches(pattern)
namesResponse, err := rs.pmseriesAPI.MetricNames(pattern)
if err != nil {
return nil, err
}
Expand All @@ -27,6 +25,32 @@ func (rs *Service) getMetricNames(pattern string) ([]MetricFindValue, error) {
return metricFindValues, nil
}

func (rs *Service) getLabelNames(pattern string) ([]MetricFindValue, error) {
labelNamesResponse, err := rs.pmseriesAPI.LabelNames(pattern)
if err != nil {
return nil, err
}

ret := []MetricFindValue{}
for _, name := range labelNamesResponse {
ret = append(ret, MetricFindValue{name})
}
return ret, nil
}

func (rs *Service) getLabelValues(labelName string) ([]MetricFindValue, error) {
labelValuesResponse, err := rs.pmseriesAPI.LabelValues([]string{labelName})
if err != nil {
return nil, err
}

ret := []MetricFindValue{}
for _, value := range labelValuesResponse[labelName] {
ret = append(ret, MetricFindValue{fmt.Sprintf("%v", value)})
}
return ret, nil
}

func (rs *Service) metricFindQuery(query string) ([]MetricFindValue, error) {
log.DefaultLogger.Debug("metricFindQuery", "query", query)

Expand All @@ -35,15 +59,19 @@ func (rs *Service) metricFindQuery(query string) ([]MetricFindValue, error) {
return rs.getMetricNames(metricNamesQuery[1])
}

labelNamesQuery := labelNamesRegex.FindStringSubmatch(query)
if len(labelNamesQuery) == 2 {
return rs.getLabelNames(labelNamesQuery[1])
}

labelValuesQuery := labelValuesRegex.FindStringSubmatch(query)
if len(labelValuesQuery) == 2 {
return rs.getLabelValues(labelValuesQuery[1])
}

// deprecated
labelValuesForMetricQuery := labelValuesForMetricRegex.FindStringSubmatch(query)
log.DefaultLogger.Debug("metricFindQuery", "labelValuesForMetricQuery", labelValuesForMetricQuery)

log.DefaultLogger.Info("Using deprecated query label_values(metric, label)", "query", query)
if len(labelValuesForMetricQuery) == 3 {
return rs.getLabelValues(labelValuesForMetricQuery[2])
}
Expand Down
8 changes: 0 additions & 8 deletions pkg/datasources/redis/resource/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,6 @@ func (rs *Service) CallResource(method string, queryParams url.Values) (interfac
return nil, fmt.Errorf("Invalid query passed to metricFindQuery")
}
return rs.metricFindQuery(query[0])
case "getLabelNames":
return rs.getLabelNames()
case "getLabelValues":
labelName, ok := queryParams["name"]
if !ok || len(labelName) != 1 {
return nil, fmt.Errorf("Invalid query passed to getLabelValues")
}
return rs.getLabelValues(labelName[0])
default:
return nil, fmt.Errorf("Unknown method %s", method)
}
Expand Down
14 changes: 14 additions & 0 deletions src/datasources/redis/components/PmseriesLang.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"functions": [
{
"name": "rate",
"doc": "calculates the rate",
"version": "5.2.2"
},
{
"name": "max",
"doc": "calculates the maximum",
"version": "5.2.2"
}
]
}
Loading

0 comments on commit 88f6d07

Please sign in to comment.