This repository has been archived by the owner on Jul 18, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdoc.go
137 lines (100 loc) · 5.21 KB
/
doc.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/*
Package simplejson provides a Go implementation for Grafana's SimpleJSON datasource: https://grafana.com/grafana/plugins/grafana-simple-json-datasource
# Overview
A simplejson server supports one or more handlers. Each handler can support multiple query targets,which can be either timeseries or table query.
A handler may support tag key/value pairs, which can be passed to the query to adapt its behaviour (e.g. filtering what data should be returned)
through 'ad hoc filters'. Finally, a handler can support annotations, i.e. a set of timestamps with associated text.
# Server
simplejson.New() creates a SimpleJSON server. The server is implemented as an http router, compatible with net/http:
handlers := map[string]simplejson.Handler{
"A": &handler{},
"B": &handler{table: true},
}
r := simplejson.New(handlers, simplejson.WithHTTPServerOption{Option: httpserver.WithPort{Port: 8080}})
_ = http.ListenAndServe(":8080", r)
This starts a server, listening on port 8080, with one target "my-target", served by myHandler.
# Handler
A handler serves incoming requests from Grafana, e.g. queries, requests for annotations or tag.
The Handler interface contains all functions a handler needs to implement. It contains only one function (Endpoints).
This function returns the Grafana SimpleJSON endpoints that the handler supports. Those can be:
- Query() implements the /query endpoint. handles both timeserie & table responses
- Annotations() implements the /annotation endpoint
- TagKeys() implements the /tag-keys endpoint
- TagValues() implements the /tag-values endpoint
Here's an example of a handler that supports timeseries queries:
type myHandler struct {
}
func (handler myHandler) Endpoints() simplejson.Endpoints {
return simplejson.Endpoints{
Query: handler.Query
}
}
func (handler *myHandler) Query(ctx context.Context, target string, target *simplejson.QueryArgs) (response *simplejson.QueryResponse, err error) {
// build response
return
}
# Queries
SimpleJSON supports two types of query responses: timeseries responses and table responses.
Timeseries queries return values as a list of timestamp/value tuples. Here's an example of a timeseries query handler:
func (handler *myHandler) Query(_ context.Context, _ string, _ query.QueryArgs) (response *simplejson.TimeSeriesResponse, err error) {
response = &query.TimeSeriesResponse{
Name: "A",
DataPoints: []simplejson.DataPoint{
{Timestamp: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC), Value: 100},
{Timestamp: time.Date(2020, 1, 1, 0, 1, 0, 0, time.UTC), Value: 101},
{Timestamp: time.Date(2020, 1, 1, 0, 2, 0, 0, time.UTC), Value: 103},
},
}
return
}
Table Queries, on the other hand, return data organized in columns and rows. Each column needs to have the same number of rows:
func (handler *myHandler) TableQuery(_ context.Context, _ string, _ query.QueryArgs) (response *simplejson.TableResponse, err error) {
response = &simplejson.TableResponse{
Columns: []simplejson.Column{
{ Text: "Time", Data: query.TimeColumn{time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC), time.Date(2020, 1, 1, 0, 1, 0, 0, time.UTC)} },
{ Text: "Label", Data: query.StringColumn{"foo", "bar"}},
{ Text: "Series A", Data: query.NumberColumn{42, 43}},
{ Text: "Series B", Data: query.NumberColumn{64.5, 100.0}},
},
}
return
}
# Annotations
The /annotations endpoint returns Annotations:
func (h *handler) Annotations(_ simplejson.QueryRequest) (annotations []simplejson.Annotation, err error) {
annotations = []simplejson.Annotation{
{
Time: time.Now().Add(-5 * time.Minute),
Title: "foo",
Text: "bar",
Tags: []string{"A", "B"},
},
}
return
}
NOTE: this is only called when using the SimpleJSON datasource. simPod/GrafanaJsonDatasource does not use the /annotations endpoint.
Instead, it will call a regular /query and allows to configure its response as annotations instead.
# Tags
The /tag-keys and /tag-values endpoints return supported keys and key values respectively for your data source.
A Grafana dashboard can then be confirmed to show those keys and its possible values as a filter.
The following sets up a key & key value handler:
func (h *handler) TagKeys(_ context.Context) (keys []string) {
return []string{"some-key"}
}
func (h *handler) TagValues(_ context.Context, key string) (values []string, err error) {
if key != "some-key" {
return nil, fmt.Errorf("invalid key: %s", key)
}
return []string{"A", "B", "C"}, nil
}
When the dashboard performs a query with a tag selected, that tag & value will be added in the request's AdHocFilters.
# Metrics
When provided with the WithQueryMetrics option, simplejson exports two Prometheus metrics for performance analytics:
simplejson_query_duration_seconds: duration of query requests by target, in seconds
simplejson_query_failed_count: number of failed query requests
The underlying http router uses [PrometheusMetrics], which exports its own set of metrics. See WithHTTPMetrics for details.
# Other topics
For information on query arguments and tags, refer to the documentation for those data structures.
[PrometheusMetrics]: https://pkg.go.dev/github.com/clambin/go-common/httpserver/middleware
*/
package simplejson