Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
nexpie-grafana-theme
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Registry
Registry
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kornkitt Poolsup
nexpie-grafana-theme
Commits
03b43ab7
Commit
03b43ab7
authored
Sep 27, 2018
by
Daniel Lee
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
stackdriver: wip annotation support
parent
26d9e924
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
165 additions
and
67 deletions
+165
-67
pkg/tsdb/stackdriver/annotation_query.go
+76
-4
pkg/tsdb/stackdriver/annotation_query_test.go
+14
-22
pkg/tsdb/stackdriver/stackdriver.go
+11
-13
public/app/plugins/datasource/stackdriver/annotations_query_ctrl.ts
+32
-0
public/app/plugins/datasource/stackdriver/module.ts
+2
-5
public/app/plugins/datasource/stackdriver/partials/annotations.editor.html
+11
-8
public/app/plugins/datasource/stackdriver/partials/query.editor.html
+2
-1
public/app/plugins/datasource/stackdriver/partials/query.filter.html
+1
-6
public/app/plugins/datasource/stackdriver/plugin.json
+1
-1
public/app/plugins/datasource/stackdriver/query_filter_ctrl.ts
+15
-7
No files found.
pkg/tsdb/stackdriver/annotation_query.go
View file @
03b43ab7
...
...
@@ -2,6 +2,7 @@ package stackdriver
import
(
"context"
"time"
"github.com/grafana/grafana/pkg/tsdb"
)
...
...
@@ -11,14 +12,85 @@ func (e *StackdriverExecutor) executeAnnotationQuery(ctx context.Context, tsdbQu
Results
:
make
(
map
[
string
]
*
tsdb
.
QueryResult
),
}
_
,
err
:=
e
.
buildAnnotationQuery
(
tsdbQuery
)
firstQuery
:=
tsdbQuery
.
Queries
[
0
]
queries
,
err
:=
e
.
buildQueries
(
tsdbQuery
)
if
err
!=
nil
{
return
nil
,
err
}
queryRes
,
resp
,
err
:=
e
.
executeQuery
(
ctx
,
queries
[
0
],
tsdbQuery
)
if
err
!=
nil
{
return
nil
,
err
}
title
:=
firstQuery
.
Model
.
Get
(
"title"
)
.
MustString
()
text
:=
firstQuery
.
Model
.
Get
(
"text"
)
.
MustString
()
tags
:=
firstQuery
.
Model
.
Get
(
"tags"
)
.
MustString
()
err
=
e
.
parseToAnnotations
(
queryRes
,
resp
,
queries
[
0
],
title
,
text
,
tags
)
result
.
Results
[
firstQuery
.
RefId
]
=
queryRes
return
result
,
nil
return
result
,
err
}
func
(
e
*
StackdriverExecutor
)
buildAnnotationQuery
(
tsdbQuery
*
tsdb
.
TsdbQuery
)
(
*
StackdriverQuery
,
error
)
{
return
&
StackdriverQuery
{},
nil
func
(
e
*
StackdriverExecutor
)
parseToAnnotations
(
queryRes
*
tsdb
.
QueryResult
,
data
StackdriverResponse
,
query
*
StackdriverQuery
,
title
string
,
text
string
,
tags
string
)
error
{
annotations
:=
make
([]
map
[
string
]
string
,
0
)
for
_
,
series
:=
range
data
.
TimeSeries
{
// reverse the order to be ascending
for
i
:=
len
(
series
.
Points
)
-
1
;
i
>=
0
;
i
--
{
point
:=
series
.
Points
[
i
]
annotation
:=
make
(
map
[
string
]
string
)
annotation
[
"time"
]
=
point
.
Interval
.
EndTime
.
UTC
()
.
Format
(
time
.
RFC3339
)
annotation
[
"title"
]
=
title
annotation
[
"tags"
]
=
tags
annotation
[
"text"
]
=
text
annotations
=
append
(
annotations
,
annotation
)
}
}
transformAnnotationToTable
(
annotations
,
queryRes
)
return
nil
}
func
transformAnnotationToTable
(
data
[]
map
[
string
]
string
,
result
*
tsdb
.
QueryResult
)
{
table
:=
&
tsdb
.
Table
{
Columns
:
make
([]
tsdb
.
TableColumn
,
4
),
Rows
:
make
([]
tsdb
.
RowValues
,
0
),
}
table
.
Columns
[
0
]
.
Text
=
"time"
table
.
Columns
[
1
]
.
Text
=
"title"
table
.
Columns
[
2
]
.
Text
=
"tags"
table
.
Columns
[
3
]
.
Text
=
"text"
for
_
,
r
:=
range
data
{
values
:=
make
([]
interface
{},
4
)
values
[
0
]
=
r
[
"time"
]
values
[
1
]
=
r
[
"title"
]
values
[
2
]
=
r
[
"tags"
]
values
[
3
]
=
r
[
"text"
]
table
.
Rows
=
append
(
table
.
Rows
,
values
)
}
result
.
Tables
=
append
(
result
.
Tables
,
table
)
result
.
Meta
.
Set
(
"rowCount"
,
len
(
data
))
slog
.
Info
(
"anno"
,
"len"
,
len
(
data
))
}
// func (e *StackdriverExecutor) buildAnnotationQuery(tsdbQuery *tsdb.TsdbQuery) (*StackdriverQuery, error) {
// firstQuery := queryContext.Queries[0]
// metricType := query.Model.Get("metricType").MustString()
// filterParts := query.Model.Get("filters").MustArray()
// filterString := buildFilterString(metricType, filterParts)
// params := url.Values{}
// params.Add("interval.startTime", startTime.UTC().Format(time.RFC3339))
// params.Add("interval.endTime", endTime.UTC().Format(time.RFC3339))
// params.Add("filter", buildFilterString(metricType, filterParts))
// params.Add("view", "FULL")
// return &StackdriverQuery{
// RefID: firstQuery.RefID,
// Params: params,
// Target: "",
// }, nil
// }
pkg/tsdb/stackdriver/annotation_query_test.go
View file @
03b43ab7
package
stackdriver
import
(
"fmt"
"testing"
"time"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/tsdb"
...
...
@@ -14,28 +12,22 @@ import (
func
TestStackdriverAnnotationQuery
(
t
*
testing
.
T
)
{
Convey
(
"Stackdriver Annotation Query Executor"
,
t
,
func
()
{
executor
:=
&
StackdriverExecutor
{}
Convey
(
"Parse queries from frontend and build Stackdriver API queries"
,
func
()
{
fromStart
:=
time
.
Date
(
2018
,
3
,
15
,
13
,
0
,
0
,
0
,
time
.
UTC
)
.
In
(
time
.
Local
)
tsdbQuery
:=
&
tsdb
.
TsdbQuery
{
TimeRange
:
&
tsdb
.
TimeRange
{
From
:
fmt
.
Sprintf
(
"%v"
,
fromStart
.
Unix
()
*
1000
),
To
:
fmt
.
Sprintf
(
"%v"
,
fromStart
.
Add
(
34
*
time
.
Minute
)
.
Unix
()
*
1000
),
},
Queries
:
[]
*
tsdb
.
Query
{
{
Model
:
simplejson
.
NewFromAny
(
map
[
string
]
interface
{}{
"metricType"
:
"a/metric/type"
,
"view"
:
"FULL"
,
"type"
:
"annotationQuery"
,
}),
RefId
:
"annotationQuery"
,
},
},
}
query
,
err
:=
executor
.
buildAnnotationQuery
(
tsdbQuery
)
Convey
(
"When parsing the stackdriver api response"
,
func
()
{
data
,
err
:=
loadTestFile
(
"./test-data/2-series-response-no-agg.json"
)
So
(
err
,
ShouldBeNil
)
So
(
len
(
data
.
TimeSeries
),
ShouldEqual
,
3
)
So
(
query
,
ShouldNotBeNil
)
res
:=
&
tsdb
.
QueryResult
{
Meta
:
simplejson
.
New
(),
RefId
:
"annotationQuery"
}
query
:=
&
StackdriverQuery
{}
err
=
executor
.
parseToAnnotations
(
res
,
data
,
query
,
"atitle"
,
"atext"
,
"atag"
)
So
(
err
,
ShouldBeNil
)
Convey
(
"Should return annotations table"
,
func
()
{
So
(
len
(
res
.
Tables
),
ShouldEqual
,
1
)
So
(
len
(
res
.
Tables
[
0
]
.
Rows
),
ShouldEqual
,
9
)
So
(
res
.
Tables
[
0
]
.
Rows
[
0
][
1
],
ShouldEqual
,
"atitle"
)
So
(
res
.
Tables
[
0
]
.
Rows
[
0
][
3
],
ShouldEqual
,
"atext"
)
})
})
})
}
pkg/tsdb/stackdriver/stackdriver.go
View file @
03b43ab7
...
...
@@ -93,10 +93,14 @@ func (e *StackdriverExecutor) executeTimeSeriesQuery(ctx context.Context, tsdbQu
}
for
_
,
query
:=
range
queries
{
queryRes
,
err
:=
e
.
executeQuery
(
ctx
,
query
,
tsdbQuery
)
queryRes
,
resp
,
err
:=
e
.
executeQuery
(
ctx
,
query
,
tsdbQuery
)
if
err
!=
nil
{
return
nil
,
err
}
err
=
e
.
parseResponse
(
queryRes
,
resp
,
query
)
if
err
!=
nil
{
queryRes
.
Error
=
err
}
result
.
Results
[
query
.
RefID
]
=
queryRes
}
...
...
@@ -219,13 +223,13 @@ func setAggParams(params *url.Values, query *tsdb.Query, durationSeconds int) {
}
}
func
(
e
*
StackdriverExecutor
)
executeQuery
(
ctx
context
.
Context
,
query
*
StackdriverQuery
,
tsdbQuery
*
tsdb
.
TsdbQuery
)
(
*
tsdb
.
QueryResult
,
error
)
{
func
(
e
*
StackdriverExecutor
)
executeQuery
(
ctx
context
.
Context
,
query
*
StackdriverQuery
,
tsdbQuery
*
tsdb
.
TsdbQuery
)
(
*
tsdb
.
QueryResult
,
StackdriverResponse
,
error
)
{
queryResult
:=
&
tsdb
.
QueryResult
{
Meta
:
simplejson
.
New
(),
RefId
:
query
.
RefID
}
req
,
err
:=
e
.
createRequest
(
ctx
,
e
.
dsInfo
)
if
err
!=
nil
{
queryResult
.
Error
=
err
return
queryResult
,
nil
return
queryResult
,
StackdriverResponse
{},
nil
}
req
.
URL
.
RawQuery
=
query
.
Params
.
Encode
()
...
...
@@ -257,22 +261,16 @@ func (e *StackdriverExecutor) executeQuery(ctx context.Context, query *Stackdriv
res
,
err
:=
ctxhttp
.
Do
(
ctx
,
e
.
httpClient
,
req
)
if
err
!=
nil
{
queryResult
.
Error
=
err
return
queryResult
,
nil
return
queryResult
,
StackdriverResponse
{},
nil
}
data
,
err
:=
e
.
unmarshalResponse
(
res
)
if
err
!=
nil
{
queryResult
.
Error
=
err
return
queryResult
,
nil
}
err
=
e
.
parseResponse
(
queryResult
,
data
,
query
)
if
err
!=
nil
{
queryResult
.
Error
=
err
return
queryResult
,
nil
return
queryResult
,
StackdriverResponse
{},
nil
}
return
queryResult
,
nil
return
queryResult
,
data
,
nil
}
func
(
e
*
StackdriverExecutor
)
unmarshalResponse
(
res
*
http
.
Response
)
(
StackdriverResponse
,
error
)
{
...
...
@@ -429,7 +427,7 @@ func (e *StackdriverExecutor) createRequest(ctx context.Context, dsInfo *models.
req
,
err
:=
http
.
NewRequest
(
http
.
MethodGet
,
"https://monitoring.googleapis.com/"
,
nil
)
if
err
!=
nil
{
slog
.
Info
(
"Failed to create request"
,
"error"
,
err
)
slog
.
Error
(
"Failed to create request"
,
"error"
,
err
)
return
nil
,
fmt
.
Errorf
(
"Failed to create request. error: %v"
,
err
)
}
...
...
public/app/plugins/datasource/stackdriver/annotations_query_ctrl.ts
0 → 100644
View file @
03b43ab7
import
_
from
'lodash'
;
import
'./query_filter_ctrl'
;
export
class
StackdriverAnnotationsQueryCtrl
{
static
templateUrl
=
'partials/annotations.editor.html'
;
annotation
:
any
;
datasource
:
any
;
defaultDropdownValue
=
'Select Metric'
;
defaultServiceValue
=
'All Services'
;
defaults
=
{
project
:
{
id
:
'default'
,
name
:
'loading project...'
,
},
metricType
:
this
.
defaultDropdownValue
,
metricService
:
this
.
defaultServiceValue
,
metric
:
''
,
filters
:
[],
metricKind
:
''
,
valueType
:
''
,
};
/** @ngInject */
constructor
()
{
this
.
annotation
.
target
=
this
.
annotation
.
target
||
{};
this
.
annotation
.
target
.
refId
=
'annotationQuery'
;
_
.
defaultsDeep
(
this
.
annotation
.
target
,
this
.
defaults
);
}
}
public/app/plugins/datasource/stackdriver/module.ts
View file @
03b43ab7
import
StackdriverDatasource
from
'./datasource'
;
import
{
StackdriverQueryCtrl
}
from
'./query_ctrl'
;
import
{
StackdriverConfigCtrl
}
from
'./config_ctrl'
;
// class AnnotationsQueryCtrl {
// static templateUrl = 'partials/annotations.editor.html';
// }
import
{
StackdriverAnnotationsQueryCtrl
}
from
'./annotations_query_ctrl'
;
export
{
StackdriverDatasource
as
Datasource
,
StackdriverQueryCtrl
as
QueryCtrl
,
StackdriverConfigCtrl
as
ConfigCtrl
,
//
AnnotationsQueryCtrl,
StackdriverAnnotationsQueryCtrl
as
AnnotationsQueryCtrl
,
};
public/app/plugins/datasource/stackdriver/partials/annotations.editor.html
View file @
03b43ab7
<div
class=
"gf-form-group"
>
<stackdriver-filter
target=
"ctrl.annotation.target"
refresh=
"ctrl.refresh()"
datasource=
"ctrl.datasource"
default-dropdown-value=
"ctrl.defaultDropdownValue"
default-service-value=
"ctrl.defaultServiceValue"
hide-group-bys=
"true"
></stackdriver-filter>
<div
class=
"gf-form-inline"
>
<div
class=
"gf-form"
>
<span
class=
"gf-form-label
width-12"
>
Graphite query
</span>
<input
type=
"text"
class=
"gf-form-input
"
ng-model=
'ctrl.annotation.target'
placeholder=
"Example: statsd.application.counters.*.count"
></input
>
<span
class=
"gf-form-label
query-keyword width-9"
>
Title
</span>
<input
type=
"text"
class=
"gf-form-input
width-20"
ng-model=
"ctrl.annotation.target.title"
/
>
</div>
<h5
class=
"section-heading"
>
Or
</h5>
<div
class=
"gf-form"
>
<span
class=
"gf-form-label width-12"
>
Graphite events tags
</span>
<input
type=
"text"
class=
"gf-form-input"
ng-model=
'ctrl.annotation.tags'
placeholder=
"Example: event_tag_name"
></input>
<span
class=
"gf-form-label query-keyword width-9"
>
Text
</span>
<input
type=
"text"
class=
"gf-form-input width-20"
ng-model=
"ctrl.annotation.target.text"
/>
</div>
<div
class=
"gf-form gf-form--grow"
>
<div
class=
"gf-form-label gf-form-label--grow"
></div>
</div>
</div>
public/app/plugins/datasource/stackdriver/partials/query.editor.html
View file @
03b43ab7
<query-editor-row
query-ctrl=
"ctrl"
has-text-edit-mode=
"false"
>
<stackdriver-filter
target=
"ctrl.target"
refresh=
"ctrl.refresh()"
datasource=
"ctrl.datasource"
default-dropdown-value=
"ctrl.defaultDropdownValue"
default-service-value=
"ctrl.defaultServiceValue"
></stackdriver-filter>
<stackdriver-filter
target=
"ctrl.target"
refresh=
"ctrl.refresh()"
datasource=
"ctrl.datasource"
default-dropdown-value=
"ctrl.defaultDropdownValue"
default-service-value=
"ctrl.defaultServiceValue"
></stackdriver-filter>
<stackdriver-aggregation
target=
"ctrl.target"
alignment-period=
"ctrl.lastQueryMeta.alignmentPeriod"
refresh=
"ctrl.refresh()"
></stackdriver-aggregation>
<div
class=
"gf-form-inline"
>
<div
class=
"gf-form"
>
...
...
public/app/plugins/datasource/stackdriver/partials/query.filter.html
View file @
03b43ab7
...
...
@@ -4,11 +4,6 @@
<gf-form-dropdown
model=
"ctrl.service"
get-options=
"ctrl.services"
class=
"min-width-20"
disabled
type=
"text"
allow-custom=
"true"
lookup-text=
"true"
css-class=
"min-width-12"
on-change=
"ctrl.onServiceChange(ctrl.service)"
></gf-form-dropdown>
</div>
<div
class=
"gf-form gf-form--grow"
>
<div
class=
"gf-form-label gf-form-label--grow"
></div>
</div>
</div>
<div
class=
"gf-form-inline"
>
<div
class=
"gf-form"
>
<span
class=
"gf-form-label width-9"
>
Metric
</span>
<gf-form-dropdown
model=
"ctrl.metricType"
get-options=
"ctrl.metrics"
class=
"min-width-20"
disabled
type=
"text"
...
...
@@ -29,7 +24,7 @@
<div
class=
"gf-form-label gf-form-label--grow"
></div>
</div>
</div>
<div
class=
"gf-form-inline"
>
<div
class=
"gf-form-inline"
ng-hide=
"ctrl.$scope.hideGroupBys"
>
<div
class=
"gf-form"
>
<span
class=
"gf-form-label query-keyword width-9"
>
Group By
</span>
<div
class=
"gf-form"
ng-repeat=
"segment in ctrl.groupBySegments"
>
...
...
public/app/plugins/datasource/stackdriver/plugin.json
View file @
03b43ab7
...
...
@@ -4,7 +4,7 @@
"id"
:
"stackdriver"
,
"metrics"
:
true
,
"alerting"
:
true
,
"annotations"
:
fals
e
,
"annotations"
:
tru
e
,
"state"
:
"beta"
,
"queryOptions"
:
{
"maxDataPoints"
:
true
,
...
...
public/app/plugins/datasource/stackdriver/query_filter_ctrl.ts
View file @
03b43ab7
...
...
@@ -16,6 +16,7 @@ export class StackdriverFilter {
refresh
:
'&'
,
defaultDropdownValue
:
'<'
,
defaultServiceValue
:
'<'
,
hideGroupBys
:
'<'
,
},
};
}
...
...
@@ -54,15 +55,18 @@ export class StackdriverFilterCtrl {
.
then
(
this
.
loadMetricDescriptors
.
bind
(
this
))
.
then
(
this
.
getLabels
.
bind
(
this
));
this
.
initSegments
();
this
.
initSegments
(
$scope
.
hideGroupBys
);
}
initSegments
()
{
this
.
groupBySegments
=
this
.
target
.
aggregation
.
groupBys
.
map
(
groupBy
=>
{
return
this
.
uiSegmentSrv
.
getSegmentForValue
(
groupBy
);
});
initSegments
(
hideGroupBys
:
boolean
)
{
if
(
!
hideGroupBys
)
{
this
.
groupBySegments
=
this
.
target
.
aggregation
.
groupBys
.
map
(
groupBy
=>
{
return
this
.
uiSegmentSrv
.
getSegmentForValue
(
groupBy
);
});
this
.
ensurePlusButton
(
this
.
groupBySegments
);
}
this
.
removeSegment
=
this
.
uiSegmentSrv
.
newSegment
({
fake
:
true
,
value
:
'-- remove group by --'
});
this
.
ensurePlusButton
(
this
.
groupBySegments
);
this
.
filterSegments
=
new
FilterSegments
(
this
.
uiSegmentSrv
,
...
...
@@ -142,7 +146,11 @@ export class StackdriverFilterCtrl {
this
.
resourceLabels
=
data
.
results
[
this
.
target
.
refId
].
meta
.
resourceLabels
;
resolve
();
}
catch
(
error
)
{
console
.
log
(
error
.
data
.
message
);
if
(
error
.
data
&&
error
.
data
.
message
)
{
console
.
log
(
error
.
data
.
message
);
}
else
{
console
.
log
(
error
);
}
appEvents
.
emit
(
'alert-error'
,
[
'Error'
,
'Error loading metric labels for '
+
this
.
target
.
metricType
]);
resolve
();
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment