Skip to content

Commit 8370068

Browse files
authored
Merge pull request #114 from scalyr/DSET-2220
DSET-2220: Better handling of query options
2 parents 8300f69 + 9a09be8 commit 8370068

File tree

6 files changed

+108
-17
lines changed

6 files changed

+108
-17
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## 3.1.1
4+
5+
- Bugfix around use of query options (max data points & interval)
6+
37
## 3.1.0
48

59
- Bumped Golang version to 1.20

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "sentinelone-dataset-datasource",
3-
"version": "3.1.0",
3+
"version": "3.1.1",
44
"description": "Scalyr Observability Platform",
55
"scripts": {
66
"build": "webpack -c ./.config/webpack/webpack.config.ts --env production",

pkg/plugin/client.go

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,21 @@ type FacetRequest struct {
2323
Field string `json:"field"`
2424
}
2525

26-
type DataSetClient struct {
26+
type DataSetClient interface {
27+
DoLRQRequest(ctx context.Context, req LRQRequest) (*LRQResult, error)
28+
DoFacetValuesRequest(ctx context.Context, req FacetQuery) (*LRQResult, error)
29+
DoTopFacetRequest(ctx context.Context, req TopFacetRequest) (*LRQResult, error)
30+
DoFacetRequest(ctx context.Context, req FacetRequest) (int, error)
31+
}
32+
33+
type dataSetClient struct {
2734
dataSetUrl string
2835
apiKey string
2936
netClient *http.Client
3037
rateLimiter *rate.Limiter
3138
}
3239

33-
func NewDataSetClient(dataSetUrl string, apiKey string) *DataSetClient {
40+
func NewDataSetClient(dataSetUrl string, apiKey string) DataSetClient {
3441
// Consider using the backend.httpclient package provided by the Grafana SDK.
3542
// This would allow a per-instance configurable timeout, rather than the hardcoded value here.
3643
netClient := &http.Client{
@@ -41,16 +48,16 @@ func NewDataSetClient(dataSetUrl string, apiKey string) *DataSetClient {
4148
// Consult with Grafana support about this, potentially there's a simplier option.
4249
rateLimiter := rate.NewLimiter(100*rate.Every(1*time.Minute), 100) // 100 requests / minute
4350

44-
return &DataSetClient{
51+
return &dataSetClient{
4552
dataSetUrl: dataSetUrl,
4653
apiKey: apiKey,
4754
netClient: netClient,
4855
rateLimiter: rateLimiter,
4956
}
5057
}
5158

52-
func (d *DataSetClient) newRequest(method, url string, body io.Reader) (*http.Request, error) {
53-
const VERSION = "3.1.0"
59+
func (d *dataSetClient) newRequest(method, url string, body io.Reader) (*http.Request, error) {
60+
const VERSION = "3.1.1"
5461

5562
if err := d.rateLimiter.Wait(context.Background()); err != nil {
5663
log.DefaultLogger.Error("error applying rate limiter", "err", err)
@@ -72,7 +79,7 @@ func (d *DataSetClient) newRequest(method, url string, body io.Reader) (*http.Re
7279
return request, nil
7380
}
7481

75-
func (d *DataSetClient) doPingRequest(ctx context.Context, req interface{}) (*LRQResult, error) {
82+
func (d *dataSetClient) doPingRequest(ctx context.Context, req interface{}) (*LRQResult, error) {
7683
// Long-Running Query (LRQ) api usage:
7784
// - An initial POST request is made containing the standard/power query
7885
// - Its response may or may not contain the results
@@ -206,19 +213,19 @@ loop:
206213
return &respBody, nil
207214
}
208215

209-
func (d *DataSetClient) DoLRQRequest(ctx context.Context, req LRQRequest) (*LRQResult, error) {
216+
func (d *dataSetClient) DoLRQRequest(ctx context.Context, req LRQRequest) (*LRQResult, error) {
210217
return d.doPingRequest(ctx, req)
211218
}
212219

213-
func (d *DataSetClient) DoFacetValuesRequest(ctx context.Context, req FacetQuery) (*LRQResult, error) {
220+
func (d *dataSetClient) DoFacetValuesRequest(ctx context.Context, req FacetQuery) (*LRQResult, error) {
214221
return d.doPingRequest(ctx, req)
215222
}
216223

217-
func (d *DataSetClient) DoTopFacetRequest(ctx context.Context, req TopFacetRequest) (*LRQResult, error) {
224+
func (d *dataSetClient) DoTopFacetRequest(ctx context.Context, req TopFacetRequest) (*LRQResult, error) {
218225
return d.doPingRequest(ctx, req)
219226
}
220227

221-
func (d *DataSetClient) DoFacetRequest(ctx context.Context, req FacetRequest) (int, error) {
228+
func (d *dataSetClient) DoFacetRequest(ctx context.Context, req FacetRequest) (int, error) {
222229
body, err := json.Marshal(req)
223230
if err != nil {
224231
log.DefaultLogger.Error("error marshalling request to DataSet", "err", err)

pkg/plugin/plugin.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func NewDataSetDatasource(settings backend.DataSourceInstanceSettings) (instance
3535
}
3636

3737
type DataSetDatasource struct {
38-
dataSetClient *DataSetClient
38+
dataSetClient DataSetClient
3939
}
4040

4141
// Dispose here tells plugin SDK that plugin wants to clean up resources when a new instance
@@ -96,7 +96,10 @@ func (d *DataSetDatasource) query(ctx context.Context, query backend.DataQuery)
9696

9797
// Setting the LRQ api's autoAlign would override the data points requested by the user (via query options).
9898
// The query options support explicitly specifying data points (MaxDataPoints) or implicitly via time range and interval.
99-
slices := query.MaxDataPoints
99+
slices := int64(query.TimeRange.Duration() / query.Interval)
100+
if slices > query.MaxDataPoints {
101+
slices = query.MaxDataPoints
102+
}
100103
if slices > 10000 {
101104
slices = 10000
102105
}

pkg/plugin/plugin_test.go

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ func TestLiveQueryDataPQ(t *testing.T) {
9999

100100
dataResp := resp.Responses[refId]
101101
if dataResp.Error != nil {
102-
t.Error(err)
102+
t.Error(dataResp.Error)
103103
}
104104

105105
fields := dataResp.Frames[0].Fields
@@ -128,6 +128,7 @@ func TestLiveQueryDataPlot(t *testing.T) {
128128
From: time.Now().Add(-4 * time.Hour),
129129
To: time.Now(),
130130
},
131+
Interval: 1 * time.Minute,
131132
MaxDataPoints: 1000,
132133
JSON: []byte(`{"expression":"count(severity != 3)","queryType":"Standard","breakDownFacetValue":"severity"}`),
133134
},
@@ -144,7 +145,7 @@ func TestLiveQueryDataPlot(t *testing.T) {
144145

145146
dataResp := resp.Responses[refId]
146147
if dataResp.Error != nil {
147-
t.Error(err)
148+
t.Error(dataResp.Error)
148149
}
149150

150151
fields := dataResp.Frames[0].Fields
@@ -158,3 +159,79 @@ func TestLiveQueryDataPlot(t *testing.T) {
158159
}
159160
}
160161
}
162+
163+
type dataSetClientMock struct {
164+
lastLRQRequest LRQRequest
165+
}
166+
167+
func (d *dataSetClientMock) DoLRQRequest(ctx context.Context, req LRQRequest) (*LRQResult, error) {
168+
d.lastLRQRequest = req
169+
return &LRQResult{Data: []byte("{}")}, nil
170+
}
171+
172+
func (d *dataSetClientMock) DoFacetValuesRequest(ctx context.Context, req FacetQuery) (*LRQResult, error) {
173+
return &LRQResult{Data: []byte("{}")}, nil
174+
}
175+
176+
func (d *dataSetClientMock) DoTopFacetRequest(ctx context.Context, req TopFacetRequest) (*LRQResult, error) {
177+
return &LRQResult{Data: []byte("{}")}, nil
178+
}
179+
180+
func (d *dataSetClientMock) DoFacetRequest(ctx context.Context, req FacetRequest) (int, error) {
181+
return 0, nil
182+
}
183+
184+
func TestQueryDataOptions(t *testing.T) {
185+
var clientMock dataSetClientMock
186+
datasource := DataSetDatasource{dataSetClient: &clientMock}
187+
188+
queryDataSlices := func(interval time.Duration, maxDataPoints int64) int64 {
189+
refId := "A"
190+
resp, err := datasource.QueryData(
191+
context.Background(),
192+
&backend.QueryDataRequest{
193+
Queries: []backend.DataQuery{
194+
{
195+
RefID: refId,
196+
TimeRange: backend.TimeRange{
197+
From: time.Now().Add(-4 * time.Hour),
198+
To: time.Now(),
199+
},
200+
Interval: interval,
201+
MaxDataPoints: maxDataPoints,
202+
JSON: []byte(`{"expression":"count(severity != 3)","queryType":"Standard"}`),
203+
},
204+
},
205+
},
206+
)
207+
if err != nil {
208+
t.Error(err)
209+
}
210+
211+
if len(resp.Responses) != 1 {
212+
t.Fatal("QueryData must return a response")
213+
}
214+
215+
if err := resp.Responses[refId].Error; err != nil {
216+
t.Error(err)
217+
}
218+
219+
return clientMock.lastLRQRequest.Plot.Slices
220+
}
221+
222+
if queryDataSlices(1*time.Minute, 1000) != 240 {
223+
t.Error("unexpected slice count")
224+
}
225+
if queryDataSlices(15*time.Second, 1000) != 960 {
226+
t.Error("unexpected slice count")
227+
}
228+
if queryDataSlices(10*time.Second, 1000) != 1000 {
229+
t.Error("unexpected slice count")
230+
}
231+
if queryDataSlices(10*time.Second, 2000) != 1440 {
232+
t.Error("unexpected slice count")
233+
}
234+
if queryDataSlices(1*time.Second, 14400) != 10000 {
235+
t.Error("unexpected slice count")
236+
}
237+
}

src/plugin.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@
4343
"path": "img/DatasetConfig.png"
4444
}
4545
],
46-
"version": "3.1.0",
47-
"updated": "2023-03-22"
46+
"version": "3.1.1",
47+
"updated": "2023-03-31"
4848
},
4949
"dependencies": {
5050
"grafanaDependency": ">=8.2.0",

0 commit comments

Comments
 (0)