From 18e4271abdabaa111feabf656d3f1bc0f8bf0355 Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Fri, 1 Jun 2018 10:34:57 +0200 Subject: [PATCH 01/34] added span with folder title that is shown for recently and starred, created a new class for folder title --- public/app/core/components/search/search_results.html | 2 +- public/sass/components/_search.scss | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/public/app/core/components/search/search_results.html b/public/app/core/components/search/search_results.html index 7435f8d0b7e..9f266ed3a6b 100644 --- a/public/app/core/components/search/search_results.html +++ b/public/app/core/components/search/search_results.html @@ -33,7 +33,7 @@ -
{{::item.title}}
+
{{::item.title}} {{::item.folderTitle}}
diff --git a/public/sass/components/_search.scss b/public/sass/components/_search.scss index 8338a5d72ae..b00168505fa 100644 --- a/public/sass/components/_search.scss +++ b/public/sass/components/_search.scss @@ -208,6 +208,12 @@ color: $list-item-link-color; } +.search-item__body-folder-title { + color: $text-color-weak; + font-style: italic; + padding-left: 0.25rem; +} + .search-item__icon { padding: 5px; flex: 0 0 auto; From 83a73327cfb42ed5a3bea73497a5b4c7303a020e Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Fri, 1 Jun 2018 15:16:22 +0200 Subject: [PATCH 02/34] removed italic --- public/sass/components/_search.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/public/sass/components/_search.scss b/public/sass/components/_search.scss index b00168505fa..3b6c1fbcce6 100644 --- a/public/sass/components/_search.scss +++ b/public/sass/components/_search.scss @@ -210,7 +210,6 @@ .search-item__body-folder-title { color: $text-color-weak; - font-style: italic; padding-left: 0.25rem; } From 8419cc05531a8db0bd3d3ce0a809096189ab3f33 Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Mon, 4 Jun 2018 13:32:19 +0200 Subject: [PATCH 03/34] made folder text smaller --- public/sass/components/_search.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/public/sass/components/_search.scss b/public/sass/components/_search.scss index 3b6c1fbcce6..e2e3336db05 100644 --- a/public/sass/components/_search.scss +++ b/public/sass/components/_search.scss @@ -211,6 +211,7 @@ .search-item__body-folder-title { color: $text-color-weak; padding-left: 0.25rem; + font-size: $font-size-xs; } .search-item__icon { From c4308fedea8ee48973d39284e60562db1228fe6b Mon Sep 17 00:00:00 2001 From: Josh Dadak Date: Wed, 25 Jul 2018 14:02:36 +0100 Subject: [PATCH 04/34] Update Configuration.md Perhaps not worded as best it could be, however it would be good to include some information here about the importance of having your Grafana SERVER_ROOT_URL being the same URL listed in your Return URLs in Azure Application. Otherwise Azure Active Directory Auth will not work correctly resulting in an error page being displayed. --- docs/sources/installation/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/installation/configuration.md b/docs/sources/installation/configuration.md index 2a799b044b3..8eee32bd616 100644 --- a/docs/sources/installation/configuration.md +++ b/docs/sources/installation/configuration.md @@ -629,7 +629,7 @@ allowed_organizations = team_ids = allowed_organizations = ``` - +Note: It's important to ensure that the SERVER_ROOT_URL in Grafana is set in your Azure Application Return URLs
## [auth.basic] From 87745e6e447f0f4acfd01d9d0984a03477c88c76 Mon Sep 17 00:00:00 2001 From: David Kaltschmidt Date: Fri, 10 Aug 2018 16:41:21 +0200 Subject: [PATCH 05/34] Explore: label selector for logging - query all available label keys for logs - query all values for each key - build cascader options with label values by key - lots of temporarily added conditions to reuse the promquery field --- public/app/containers/Explore/Explore.tsx | 1 + .../app/containers/Explore/PromQueryField.tsx | 82 +++++++++++++++++-- public/app/containers/Explore/QueryRows.tsx | 3 +- 3 files changed, 77 insertions(+), 9 deletions(-) diff --git a/public/app/containers/Explore/Explore.tsx b/public/app/containers/Explore/Explore.tsx index 9620ac4f91b..bd52cd5ba05 100644 --- a/public/app/containers/Explore/Explore.tsx +++ b/public/app/containers/Explore/Explore.tsx @@ -564,6 +564,7 @@ export class Explore extends React.Component { onClickHintFix={this.onModifyQueries} onExecuteQuery={this.onSubmit} onRemoveQueryRow={this.onRemoveQueryRow} + supportsLogs={supportsLogs} />
{supportsGraph ? ( diff --git a/public/app/containers/Explore/PromQueryField.tsx b/public/app/containers/Explore/PromQueryField.tsx index 1b3ff33971d..ee9496fb024 100644 --- a/public/app/containers/Explore/PromQueryField.tsx +++ b/public/app/containers/Explore/PromQueryField.tsx @@ -137,12 +137,14 @@ interface PromQueryFieldProps { onQueryChange?: (value: string, override?: boolean) => void; portalPrefix?: string; request?: (url: string) => any; + supportsLogs?: boolean; // To be removed after Logging gets its own query field } interface PromQueryFieldState { histogramMetrics: string[]; labelKeys: { [index: string]: string[] }; // metric -> [labelKey,...] labelValues: { [index: string]: { [index: string]: string[] } }; // metric -> labelKey -> [labelValue,...] + logLabelOptions: any[]; metrics: string[]; metricsByPrefix: CascaderOption[]; } @@ -171,16 +173,41 @@ class PromQueryField extends React.Component { + let query; + if (selectedOptions.length === 1) { + if (selectedOptions[0].children.length === 0) { + query = selectedOptions[0].value; + } else { + // Ignore click on group + return; + } + } else { + const key = selectedOptions[0].value; + const value = selectedOptions[1].value; + query = `{${key}="${value}"}`; + } + this.onChangeQuery(query, true); + }; + onChangeMetrics = (values: string[], selectedOptions: CascaderOption[]) => { let query; if (selectedOptions.length === 1) { @@ -380,7 +407,8 @@ class PromQueryField extends React.Component this.fetchLabelValues(key))); @@ -409,6 +437,38 @@ class PromQueryField extends React.Component ({ label: value, value })), + }); + } + const labelValues = { [EMPTY_SELECTOR]: labelValuesByKey }; + this.setState({ labelKeys: labelKeysBySelector, labelValues, logLabelOptions }); + } catch (e) { + console.error(e); + } + } + async fetchLabelValues(key: string) { const url = `/api/v1/label/${key}/values`; try { @@ -463,8 +523,8 @@ class PromQueryField extends React.Component ({ label: hm, value: hm })); const metricsOptions = [ { label: 'Histograms', value: HISTOGRAM_GROUP, children: histogramOptions }, @@ -474,9 +534,15 @@ class PromQueryField extends React.Component
- - - + {supportsLogs ? ( + + + + ) : ( + + + + )}
diff --git a/public/app/containers/Explore/QueryRows.tsx b/public/app/containers/Explore/QueryRows.tsx index a7d91d59033..51adfa81c68 100644 --- a/public/app/containers/Explore/QueryRows.tsx +++ b/public/app/containers/Explore/QueryRows.tsx @@ -44,7 +44,7 @@ class QueryRow extends PureComponent { }; render() { - const { edited, history, query, queryError, queryHint, request } = this.props; + const { edited, history, query, queryError, queryHint, request, supportsLogs } = this.props; return (
@@ -58,6 +58,7 @@ class QueryRow extends PureComponent { onPressEnter={this.onPressEnter} onQueryChange={this.onChangeQuery} request={request} + supportsLogs={supportsLogs} />
From 953bdc4dc063c85ac00e0e8536f1565e1c236144 Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Tue, 11 Sep 2018 14:53:38 +0200 Subject: [PATCH 06/34] put folder name under dashboard name, tweaked aliginments in search results --- public/app/core/components/search/search_results.html | 3 ++- public/sass/components/_search.scss | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/public/app/core/components/search/search_results.html b/public/app/core/components/search/search_results.html index 9f266ed3a6b..45258ded652 100644 --- a/public/app/core/components/search/search_results.html +++ b/public/app/core/components/search/search_results.html @@ -33,7 +33,8 @@ -
{{::item.title}} {{::item.folderTitle}}
+
{{::item.title}}
+ {{::item.folderTitle}}
diff --git a/public/sass/components/_search.scss b/public/sass/components/_search.scss index 1589cc1e52c..b1211bcbdee 100644 --- a/public/sass/components/_search.scss +++ b/public/sass/components/_search.scss @@ -210,18 +210,20 @@ .search-item__body-title { color: $list-item-link-color; + line-height: 14px; } .search-item__body-folder-title { color: $text-color-weak; - padding-left: 0.25rem; font-size: $font-size-xs; + line-height: 11px; } .search-item__icon { padding: 5px; flex: 0 0 auto; font-size: 19px; + line-height: 22px; padding: 5px 2px 5px 10px; } From f25538744d850ad29798587d3f10ff6546eecc40 Mon Sep 17 00:00:00 2001 From: David Kaltschmidt Date: Wed, 19 Sep 2018 12:01:02 +0200 Subject: [PATCH 07/34] Explore: Fix label suggestions for recording rules - parsing of recording rules failed for label suggestor - added ':' to parsing routine --- public/app/containers/Explore/utils/prometheus.test.ts | 3 +++ public/app/containers/Explore/utils/prometheus.ts | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/public/app/containers/Explore/utils/prometheus.test.ts b/public/app/containers/Explore/utils/prometheus.test.ts index d12d28c6bc9..4e84deaa7e8 100644 --- a/public/app/containers/Explore/utils/prometheus.test.ts +++ b/public/app/containers/Explore/utils/prometheus.test.ts @@ -57,5 +57,8 @@ describe('parseSelector()', () => { parsed = parseSelector('baz{foo="bar"}', 12); expect(parsed.selector).toBe('{__name__="baz",foo="bar"}'); + + parsed = parseSelector('bar:metric:1m{}', 14); + expect(parsed.selector).toBe('{__name__="bar:metric:1m"}'); }); }); diff --git a/public/app/containers/Explore/utils/prometheus.ts b/public/app/containers/Explore/utils/prometheus.ts index 19129976282..8c41b94d684 100644 --- a/public/app/containers/Explore/utils/prometheus.ts +++ b/public/app/containers/Explore/utils/prometheus.ts @@ -32,7 +32,7 @@ const labelRegexp = /\b\w+="[^"\n]*?"/g; export function parseSelector(query: string, cursorOffset = 1): { labelKeys: any[]; selector: string } { if (!query.match(selectorRegexp)) { // Special matcher for metrics - if (query.match(/^\w+$/)) { + if (query.match(/^[A-Za-z:][\w:]*$/)) { return { selector: `{__name__="${query}"}`, labelKeys: ['__name__'], @@ -76,7 +76,7 @@ export function parseSelector(query: string, cursorOffset = 1): { labelKeys: any // Add metric if there is one before the selector const metricPrefix = query.slice(0, prefixOpen); - const metricMatch = metricPrefix.match(/\w+$/); + const metricMatch = metricPrefix.match(/[A-Za-z:][\w:]*$/); if (metricMatch) { labels['__name__'] = `"${metricMatch[0]}"`; } From b609d81194f3e6a79a3798cf00040dd8035ab82e Mon Sep 17 00:00:00 2001 From: Mario Trangoni Date: Thu, 20 Sep 2018 19:43:19 +0200 Subject: [PATCH 08/34] pkg/tsdb/elasticsearch/client/search_request.go: simplify loop with append. $ gometalinter --vendor --disable-all --enable=megacheck --disable=gotype --deadline=6m ./... pkg/tsdb/elasticsearch/client/search_request.go:59:4:warning: should replace loop with sr.Aggs = append(sr.Aggs, aggArray...) (S1011) (megacheck) pkg/tsdb/elasticsearch/client/search_request.go:303:4:warning: should replace loop with agg.Aggregation.Aggs = append(agg.Aggregation.Aggs, childAggs...) (S1011) (megacheck) --- pkg/tsdb/elasticsearch/client/search_request.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/pkg/tsdb/elasticsearch/client/search_request.go b/pkg/tsdb/elasticsearch/client/search_request.go index 2b833ce78d3..9d55fc15ff9 100644 --- a/pkg/tsdb/elasticsearch/client/search_request.go +++ b/pkg/tsdb/elasticsearch/client/search_request.go @@ -56,9 +56,7 @@ func (b *SearchRequestBuilder) Build() (*SearchRequest, error) { if err != nil { return nil, err } - for _, agg := range aggArray { - sr.Aggs = append(sr.Aggs, agg) - } + sr.Aggs = append(sr.Aggs, aggArray...) } } @@ -300,9 +298,7 @@ func (b *aggBuilderImpl) Build() (AggArray, error) { return nil, err } - for _, childAgg := range childAggs { - agg.Aggregation.Aggs = append(agg.Aggregation.Aggs, childAgg) - } + agg.Aggregation.Aggs = append(agg.Aggregation.Aggs, childAggs...) } aggs = append(aggs, agg) From 303e70db25daac93e2a892004fdaa1cbc6772d15 Mon Sep 17 00:00:00 2001 From: Mario Trangoni Date: Thu, 20 Sep 2018 20:05:19 +0200 Subject: [PATCH 09/34] pkg/tsdb/elasticsearch/response_parser.go: simplify redundant code $ gometalinter --vendor --disable-all --enable=megacheck --disable=gotype --deadline=6m ./... pkg/tsdb/elasticsearch/response_parser.go:95:41:warning: should use make(map[string]string) instead (S1019) (megacheck) pkg/tsdb/elasticsearch/response_parser.go:125:41:warning: should use make(map[string]string) instead (S1019) (megacheck) pkg/tsdb/elasticsearch/response_parser.go:317:5:warning: redundant break statement (S1023) (megacheck) pkg/tsdb/elasticsearch/response_parser.go:358:5:warning: redundant break statement (S1023) (megacheck) --- pkg/tsdb/elasticsearch/response_parser.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pkg/tsdb/elasticsearch/response_parser.go b/pkg/tsdb/elasticsearch/response_parser.go index 7bdab60389c..0090754840a 100644 --- a/pkg/tsdb/elasticsearch/response_parser.go +++ b/pkg/tsdb/elasticsearch/response_parser.go @@ -92,7 +92,7 @@ func (rp *responseParser) processBuckets(aggs map[string]interface{}, target *Qu } else { for _, b := range esAgg.Get("buckets").MustArray() { bucket := simplejson.NewFromAny(b) - newProps := make(map[string]string, 0) + newProps := make(map[string]string) for k, v := range props { newProps[k] = v @@ -122,7 +122,7 @@ func (rp *responseParser) processBuckets(aggs map[string]interface{}, target *Qu for _, bucketKey := range bucketKeys { bucket := simplejson.NewFromAny(buckets[bucketKey]) - newProps := make(map[string]string, 0) + newProps := make(map[string]string) for k, v := range props { newProps[k] = v @@ -314,7 +314,6 @@ func (rp *responseParser) processAggregationDocs(esAgg *simplejson.Json, aggDef switch metric.Type { case "count": addMetricValue(&values, rp.getMetricName(metric.Type), castToNullFloat(bucket.Get("doc_count"))) - break case "extended_stats": metaKeys := make([]string, 0) meta := metric.Meta.MustMap() @@ -355,7 +354,6 @@ func (rp *responseParser) processAggregationDocs(esAgg *simplejson.Json, aggDef } addMetricValue(&values, metricName, castToNullFloat(bucket.GetPath(metric.ID, "value"))) - break } } From 0dea8fe1e07a0f92714f26b77a7314d773debb4e Mon Sep 17 00:00:00 2001 From: Mario Trangoni Date: Thu, 20 Sep 2018 20:15:22 +0200 Subject: [PATCH 10/34] pkg/services/sqlstore/user.go: empty branch $ gometalinter --vendor --disable-all --enable=megacheck --disable=gotype --deadline=6m ./... pkg/services/sqlstore/user.go:274:3:warning: empty branch (SA9003) (megacheck) --- pkg/services/sqlstore/user.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/pkg/services/sqlstore/user.go b/pkg/services/sqlstore/user.go index 6bd30be1869..848a11d81ab 100644 --- a/pkg/services/sqlstore/user.go +++ b/pkg/services/sqlstore/user.go @@ -271,9 +271,6 @@ func ChangeUserPassword(cmd *m.ChangeUserPasswordCommand) error { func UpdateUserLastSeenAt(cmd *m.UpdateUserLastSeenAtCommand) error { return inTransaction(func(sess *DBSession) error { - if cmd.UserId <= 0 { - } - user := m.User{ Id: cmd.UserId, LastSeenAt: time.Now(), From 03a2a39a2abee974462556c823c7a9d2b9b69ff9 Mon Sep 17 00:00:00 2001 From: Mario Trangoni Date: Thu, 20 Sep 2018 22:31:10 +0200 Subject: [PATCH 11/34] pkg/tracing/tracing.go: replace deprecated cfg.New function $ gometalinter --vendor --disable-all --enable=megacheck --disable=gotype --deadline=6m ./... pkg/tracing/tracing.go:81:25:warning: cfg.New is deprecated: use NewTracer() function (SA1019) (megacheck) --- pkg/tracing/tracing.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/tracing/tracing.go b/pkg/tracing/tracing.go index 61f45af3635..fd7258b7a0a 100644 --- a/pkg/tracing/tracing.go +++ b/pkg/tracing/tracing.go @@ -58,7 +58,8 @@ func (ts *TracingService) parseSettings() { func (ts *TracingService) initGlobalTracer() error { cfg := jaegercfg.Configuration{ - Disabled: !ts.enabled, + ServiceName: "grafana", + Disabled: !ts.enabled, Sampler: &jaegercfg.SamplerConfig{ Type: ts.samplerType, Param: ts.samplerParam, @@ -78,7 +79,7 @@ func (ts *TracingService) initGlobalTracer() error { options = append(options, jaegercfg.Tag(tag, value)) } - tracer, closer, err := cfg.New("grafana", options...) + tracer, closer, err := cfg.NewTracer(options...) if err != nil { return err } From 3689bb778c36b32e9d114520276bccc2cafa7613 Mon Sep 17 00:00:00 2001 From: Mario Trangoni Date: Fri, 21 Sep 2018 10:44:53 +0200 Subject: [PATCH 12/34] Fix misspell issues See, $ gometalinter --disable-all --enable misspell --deadline 10m --vendor ./... pkg/api/dtos/alerting_test.go:32:13:warning: "expectes" is a misspelling of "expects" (misspell) pkg/api/static/static.go:2:18:warning: "Unknwon" is a misspelling of "Unknown" (misspell) pkg/components/imguploader/azureblobuploader.go:55:48:warning: "conatiner" is a misspelling of "container" (misspell) pkg/login/ldap_settings.go:51:115:warning: "compatability" is a misspelling of "compatibility" (misspell) pkg/middleware/auth_proxy_test.go:122:22:warning: "Destory" is a misspelling of "Destroy" (misspell) pkg/middleware/logger.go:2:18:warning: "Unknwon" is a misspelling of "Unknown" (misspell) pkg/services/notifications/codes.go:9:13:warning: "Unknwon" is a misspelling of "Unknown" (misspell) pkg/services/session/mysql.go:170:3:warning: "Destory" is a misspelling of "Destroy" (misspell) pkg/services/session/mysql.go:171:24:warning: "Destory" is a misspelling of "Destroy" (misspell) pkg/services/session/session.go:95:4:warning: "Destory" is a misspelling of "Destroy" (misspell) pkg/services/session/session.go:96:1:warning: "Destory" is a misspelling of "Destroy" (misspell) pkg/services/session/session.go:167:25:warning: "Destory" is a misspelling of "Destroy" (misspell) pkg/setting/setting.go:1:18:warning: "Unknwon" is a misspelling of "Unknown" (misspell) pkg/tsdb/cloudwatch/cloudwatch.go:199:14:warning: "resolutin" is a misspelling of "resolutions" (misspell) pkg/tsdb/cloudwatch/cloudwatch.go:270:15:warning: "resolutin" is a misspelling of "resolutions" (misspell) pkg/tsdb/elasticsearch/response_parser.go:531:24:warning: "Unkown" is a misspelling of "Unknown" (misspell) pkg/tsdb/elasticsearch/client/search_request.go:113:7:warning: "initaite" is a misspelling of "initiate" (misspell) Note: Unknwon is a library name, and Destory a mysql typo. --- pkg/api/dtos/alerting_test.go | 2 +- pkg/components/imguploader/azureblobuploader.go | 2 +- pkg/login/ldap_settings.go | 2 +- pkg/tsdb/cloudwatch/cloudwatch.go | 4 ++-- pkg/tsdb/elasticsearch/client/search_request.go | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/api/dtos/alerting_test.go b/pkg/api/dtos/alerting_test.go index c38f281be9c..f4c09f202cb 100644 --- a/pkg/api/dtos/alerting_test.go +++ b/pkg/api/dtos/alerting_test.go @@ -29,7 +29,7 @@ func TestFormatShort(t *testing.T) { } if parsed != tc.interval { - t.Errorf("expectes the parsed duration to equal the interval. Got %v expected: %v", parsed, tc.interval) + t.Errorf("expects the parsed duration to equal the interval. Got %v expected: %v", parsed, tc.interval) } } } diff --git a/pkg/components/imguploader/azureblobuploader.go b/pkg/components/imguploader/azureblobuploader.go index 3c0ac5b8884..d4117b6fc34 100644 --- a/pkg/components/imguploader/azureblobuploader.go +++ b/pkg/components/imguploader/azureblobuploader.go @@ -52,7 +52,7 @@ func (az *AzureBlobUploader) Upload(ctx context.Context, imageDiskPath string) ( } randomFileName := util.GetRandomString(30) + ".png" // upload image - az.log.Debug("Uploading image to azure_blob", "conatiner_name", az.container_name, "blob_name", randomFileName) + az.log.Debug("Uploading image to azure_blob", "container_name", az.container_name, "blob_name", randomFileName) resp, err := blob.FileUpload(az.container_name, randomFileName, file) if err != nil { return "", err diff --git a/pkg/login/ldap_settings.go b/pkg/login/ldap_settings.go index 7ebfbc79ba8..40791a509db 100644 --- a/pkg/login/ldap_settings.go +++ b/pkg/login/ldap_settings.go @@ -48,7 +48,7 @@ type LdapAttributeMap struct { type LdapGroupToOrgRole struct { GroupDN string `toml:"group_dn"` OrgId int64 `toml:"org_id"` - IsGrafanaAdmin *bool `toml:"grafana_admin"` // This is a pointer to know if it was set or not (for backwards compatability) + IsGrafanaAdmin *bool `toml:"grafana_admin"` // This is a pointer to know if it was set or not (for backwards compatibility) OrgRole m.RoleType `toml:"org_role"` } diff --git a/pkg/tsdb/cloudwatch/cloudwatch.go b/pkg/tsdb/cloudwatch/cloudwatch.go index 92352a51315..be14c6f96ec 100644 --- a/pkg/tsdb/cloudwatch/cloudwatch.go +++ b/pkg/tsdb/cloudwatch/cloudwatch.go @@ -196,7 +196,7 @@ func (e *CloudWatchExecutor) executeQuery(ctx context.Context, query *CloudWatch params.ExtendedStatistics = query.ExtendedStatistics } - // 1 minutes resolutin metrics is stored for 15 days, 15 * 24 * 60 = 21600 + // 1 minutes resolution metrics is stored for 15 days, 15 * 24 * 60 = 21600 if query.HighResolution && (((endTime.Unix() - startTime.Unix()) / int64(query.Period)) > 21600) { return nil, errors.New("too long query period") } @@ -267,7 +267,7 @@ func (e *CloudWatchExecutor) executeGetMetricDataQuery(ctx context.Context, regi ScanBy: aws.String("TimestampAscending"), } for _, query := range queries { - // 1 minutes resolutin metrics is stored for 15 days, 15 * 24 * 60 = 21600 + // 1 minutes resolution metrics is stored for 15 days, 15 * 24 * 60 = 21600 if query.HighResolution && (((endTime.Unix() - startTime.Unix()) / int64(query.Period)) > 21600) { return nil, errors.New("too long query period") } diff --git a/pkg/tsdb/elasticsearch/client/search_request.go b/pkg/tsdb/elasticsearch/client/search_request.go index 9d55fc15ff9..4c577a2c31d 100644 --- a/pkg/tsdb/elasticsearch/client/search_request.go +++ b/pkg/tsdb/elasticsearch/client/search_request.go @@ -110,7 +110,7 @@ func (b *SearchRequestBuilder) Query() *QueryBuilder { return b.queryBuilder } -// Agg initaite and returns a new aggregation builder +// Agg initiate and returns a new aggregation builder func (b *SearchRequestBuilder) Agg() AggBuilder { aggBuilder := newAggBuilder() b.aggBuilders = append(b.aggBuilders, aggBuilder) From 80fa66fcb06c30e8cfa80e8c0f7cfbe0025add6e Mon Sep 17 00:00:00 2001 From: Mario Trangoni Date: Fri, 21 Sep 2018 11:51:26 +0200 Subject: [PATCH 13/34] Fix some typos found by codespell See, $ codespell -S "./.git*,./vendor*,./public*" --- CHANGELOG.md | 4 ++-- build.go | 3 +-- devenv/dev-dashboards/panel_tests_polystat.json | 12 ++++++------ pkg/components/imguploader/azureblobuploader.go | 12 ++++++------ pkg/components/simplejson/simplejson.go | 6 +++--- pkg/services/alerting/extractor.go | 5 +++-- pkg/services/alerting/notifiers/teams.go | 2 +- .../datasources/testdata/broken-yaml/commented.yaml | 2 +- pkg/services/rendering/http_mode.go | 4 ++-- pkg/services/rendering/rendering.go | 2 +- pkg/services/sqlstore/migrations/annotation_mig.go | 2 +- pkg/services/sqlstore/transactions_test.go | 2 +- pkg/tsdb/elasticsearch/client/client_test.go | 2 +- pkg/tsdb/influxdb/query_test.go | 2 +- pkg/tsdb/prometheus/prometheus.go | 4 ++-- pkg/util/md5_test.go | 2 +- 16 files changed, 33 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d32615ce97..ace4348af99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -318,7 +318,7 @@ See [security announcement](https://community.grafana.com/t/grafana-5-2-3-and-4- * **Dashboard**: Sizing and positioning of settings menu icons [#11572](https://github.com/grafana/grafana/pull/11572) * **Dashboard**: Add search filter/tabs to new panel control [#10427](https://github.com/grafana/grafana/issues/10427) * **Folders**: User with org viewer role should not be able to save/move dashboards in/to general folder [#11553](https://github.com/grafana/grafana/issues/11553) -* **Influxdb**: Dont assume the first column in table response is time. [#11476](https://github.com/grafana/grafana/issues/11476), thx [@hahnjo](https://github.com/hahnjo) +* **Influxdb**: Don't assume the first column in table response is time. [#11476](https://github.com/grafana/grafana/issues/11476), thx [@hahnjo](https://github.com/hahnjo) ### Tech * Backend code simplification [#11613](https://github.com/grafana/grafana/pull/11613), thx [@knweiss](https://github.com/knweiss) @@ -1464,7 +1464,7 @@ Grafana 2.x is fundamentally different from 1.x; it now ships with an integrated **New features** - [Issue #1623](https://github.com/grafana/grafana/issues/1623). Share Dashboard: Dashboard snapshot sharing (dash and data snapshot), save to local or save to public snapshot dashboard snapshots.raintank.io site -- [Issue #1622](https://github.com/grafana/grafana/issues/1622). Share Panel: The share modal now has an embed option, gives you an iframe that you can use to embedd a single graph on another web site +- [Issue #1622](https://github.com/grafana/grafana/issues/1622). Share Panel: The share modal now has an embed option, gives you an iframe that you can use to embed a single graph on another web site - [Issue #718](https://github.com/grafana/grafana/issues/718). Dashboard: When saving a dashboard and another user has made changes in between the user is prompted with a warning if he really wants to overwrite the other's changes - [Issue #1331](https://github.com/grafana/grafana/issues/1331). Graph & Singlestat: New axis/unit format selector and more units (kbytes, Joule, Watt, eV), and new design for graph axis & grid tab and single stat options tab views - [Issue #1241](https://github.com/grafana/grafana/issues/1242). Timepicker: New option in timepicker (under dashboard settings), to change ``now`` to be for example ``now-1m``, useful when you want to ignore last minute because it contains incomplete data diff --git a/build.go b/build.go index 561dd70df0e..9502f52be11 100644 --- a/build.go +++ b/build.go @@ -120,7 +120,6 @@ func main() { createLinuxPackages() } - case "pkg-rpm": grunt(gruntBuildArg("release")...) createRpmPackages() @@ -417,7 +416,7 @@ func test(pkg string) { func build(binaryName, pkg string, tags []string) { binary := fmt.Sprintf("./bin/%s-%s/%s", goos, goarch, binaryName) if isDev { - //dont include os and arch in output path in dev environment + //don't include os and arch in output path in dev environment binary = fmt.Sprintf("./bin/%s", binaryName) } diff --git a/devenv/dev-dashboards/panel_tests_polystat.json b/devenv/dev-dashboards/panel_tests_polystat.json index 51d3085c438..fc3f4c92b3c 100644 --- a/devenv/dev-dashboards/panel_tests_polystat.json +++ b/devenv/dev-dashboards/panel_tests_polystat.json @@ -884,8 +884,8 @@ "value": "celsius" }, { - "text": "Farenheit (°F)", - "value": "farenheit" + "text": "Fahrenheit (°F)", + "value": "fahrenheit" }, { "text": "Kelvin (K)", @@ -1991,8 +1991,8 @@ "value": "celsius" }, { - "text": "Farenheit (°F)", - "value": "farenheit" + "text": "Fahrenheit (°F)", + "value": "fahrenheit" }, { "text": "Kelvin (K)", @@ -3078,8 +3078,8 @@ "value": "celsius" }, { - "text": "Farenheit (°F)", - "value": "farenheit" + "text": "Fahrenheit (°F)", + "value": "fahrenheit" }, { "text": "Kelvin (K)", diff --git a/pkg/components/imguploader/azureblobuploader.go b/pkg/components/imguploader/azureblobuploader.go index d4117b6fc34..a902807925b 100644 --- a/pkg/components/imguploader/azureblobuploader.go +++ b/pkg/components/imguploader/azureblobuploader.go @@ -274,10 +274,10 @@ func (a *Auth) canonicalizedHeaders(req *http.Request) string { } } - splitted := strings.Split(buffer.String(), "\n") - sort.Strings(splitted) + split := strings.Split(buffer.String(), "\n") + sort.Strings(split) - return strings.Join(splitted, "\n") + return strings.Join(split, "\n") } /* @@ -313,8 +313,8 @@ func (a *Auth) canonicalizedResource(req *http.Request) string { buffer.WriteString(fmt.Sprintf("\n%s:%s", key, strings.Join(values, ","))) } - splitted := strings.Split(buffer.String(), "\n") - sort.Strings(splitted) + split := strings.Split(buffer.String(), "\n") + sort.Strings(split) - return strings.Join(splitted, "\n") + return strings.Join(split, "\n") } diff --git a/pkg/components/simplejson/simplejson.go b/pkg/components/simplejson/simplejson.go index 85e2f955943..35e305eb414 100644 --- a/pkg/components/simplejson/simplejson.go +++ b/pkg/components/simplejson/simplejson.go @@ -256,7 +256,7 @@ func (j *Json) StringArray() ([]string, error) { // MustArray guarantees the return of a `[]interface{}` (with optional default) // -// useful when you want to interate over array values in a succinct manner: +// useful when you want to iterate over array values in a succinct manner: // for i, v := range js.Get("results").MustArray() { // fmt.Println(i, v) // } @@ -281,7 +281,7 @@ func (j *Json) MustArray(args ...[]interface{}) []interface{} { // MustMap guarantees the return of a `map[string]interface{}` (with optional default) // -// useful when you want to interate over map values in a succinct manner: +// useful when you want to iterate over map values in a succinct manner: // for k, v := range js.Get("dictionary").MustMap() { // fmt.Println(k, v) // } @@ -329,7 +329,7 @@ func (j *Json) MustString(args ...string) string { // MustStringArray guarantees the return of a `[]string` (with optional default) // -// useful when you want to interate over array values in a succinct manner: +// useful when you want to iterate over array values in a succinct manner: // for i, s := range js.Get("results").MustStringArray() { // fmt.Println(i, s) // } diff --git a/pkg/services/alerting/extractor.go b/pkg/services/alerting/extractor.go index e1c1bfacb2e..229092e217b 100644 --- a/pkg/services/alerting/extractor.go +++ b/pkg/services/alerting/extractor.go @@ -82,12 +82,13 @@ func (e *DashAlertExtractor) getAlertFromPanels(jsonWithPanels *simplejson.Json, if collapsed && collapsedJSON.MustBool() { // extract alerts from sub panels for collapsed panels - als, err := e.getAlertFromPanels(panel, validateAlertFunc) + alertSlice, err := e.getAlertFromPanels(panel, + validateAlertFunc) if err != nil { return nil, err } - alerts = append(alerts, als...) + alerts = append(alerts, alertSlice...) continue } diff --git a/pkg/services/alerting/notifiers/teams.go b/pkg/services/alerting/notifiers/teams.go index 7beb71e5c65..2dad11285b4 100644 --- a/pkg/services/alerting/notifiers/teams.go +++ b/pkg/services/alerting/notifiers/teams.go @@ -74,7 +74,7 @@ func (this *TeamsNotifier) Notify(evalContext *alerting.EvalContext) error { } message := "" - if evalContext.Rule.State != m.AlertStateOK { //dont add message when going back to alert state ok. + if evalContext.Rule.State != m.AlertStateOK { //don't add message when going back to alert state ok. message = evalContext.Rule.Message } diff --git a/pkg/services/provisioning/datasources/testdata/broken-yaml/commented.yaml b/pkg/services/provisioning/datasources/testdata/broken-yaml/commented.yaml index 1bb9cb53b45..fc13398d472 100644 --- a/pkg/services/provisioning/datasources/testdata/broken-yaml/commented.yaml +++ b/pkg/services/provisioning/datasources/testdata/broken-yaml/commented.yaml @@ -4,7 +4,7 @@ # org_id: 1 # # list of datasources to insert/update depending -# # whats available in the datbase +# # what's available in the datbase #datasources: # # name of the datasource. Required # - name: Graphite diff --git a/pkg/services/rendering/http_mode.go b/pkg/services/rendering/http_mode.go index d47dfaeaae1..40259c44746 100644 --- a/pkg/services/rendering/http_mode.go +++ b/pkg/services/rendering/http_mode.go @@ -70,7 +70,7 @@ func (rs *RenderingService) renderViaHttp(ctx context.Context, opts Opts) (*Rend return nil, ErrTimeout } - // if we didnt get a 200 response, something went wrong. + // if we didn't get a 200 response, something went wrong. if resp.StatusCode != http.StatusOK { rs.log.Error("Remote rendering request failed", "error", resp.Status) return nil, fmt.Errorf("Remote rendering request failed. %d: %s", resp.StatusCode, resp.Status) @@ -83,7 +83,7 @@ func (rs *RenderingService) renderViaHttp(ctx context.Context, opts Opts) (*Rend defer out.Close() _, err = io.Copy(out, resp.Body) if err != nil { - // check that we didnt timeout while receiving the response. + // check that we didn't timeout while receiving the response. if reqContext.Err() == context.DeadlineExceeded { rs.log.Info("Rendering timed out") return nil, ErrTimeout diff --git a/pkg/services/rendering/rendering.go b/pkg/services/rendering/rendering.go index ff4a67cc9b6..ecef83d74d9 100644 --- a/pkg/services/rendering/rendering.go +++ b/pkg/services/rendering/rendering.go @@ -45,7 +45,7 @@ func (rs *RenderingService) Init() error { // set value used for domain attribute of renderKey cookie if rs.Cfg.RendererUrl != "" { - // RendererCallbackUrl has already been passed, it wont generate an error. + // RendererCallbackUrl has already been passed, it won't generate an error. u, _ := url.Parse(rs.Cfg.RendererCallbackUrl) rs.domain = u.Hostname() } else if setting.HttpAddr != setting.DEFAULT_HTTP_ADDR { diff --git a/pkg/services/sqlstore/migrations/annotation_mig.go b/pkg/services/sqlstore/migrations/annotation_mig.go index d231d3283e2..49920dee490 100644 --- a/pkg/services/sqlstore/migrations/annotation_mig.go +++ b/pkg/services/sqlstore/migrations/annotation_mig.go @@ -105,7 +105,7 @@ func addAnnotationMig(mg *Migrator) { })) // - // Convert epoch saved as seconds to miliseconds + // Convert epoch saved as seconds to milliseconds // updateEpochSql := "UPDATE annotation SET epoch = (epoch*1000) where epoch < 9999999999" mg.AddMigration("Convert existing annotations from seconds to milliseconds", NewRawSqlMigration(updateEpochSql)) diff --git a/pkg/services/sqlstore/transactions_test.go b/pkg/services/sqlstore/transactions_test.go index 937649921ba..41dedde5db4 100644 --- a/pkg/services/sqlstore/transactions_test.go +++ b/pkg/services/sqlstore/transactions_test.go @@ -39,7 +39,7 @@ func TestTransaction(t *testing.T) { So(err, ShouldEqual, models.ErrInvalidApiKey) }) - Convey("wont update if one handler fails", func() { + Convey("won't update if one handler fails", func() { err := ss.InTransaction(context.Background(), func(ctx context.Context) error { err := DeleteApiKeyCtx(ctx, deleteApiKeyCmd) if err != nil { diff --git a/pkg/tsdb/elasticsearch/client/client_test.go b/pkg/tsdb/elasticsearch/client/client_test.go index 11d1cdb1d71..af9ac0d8fce 100644 --- a/pkg/tsdb/elasticsearch/client/client_test.go +++ b/pkg/tsdb/elasticsearch/client/client_test.go @@ -40,7 +40,7 @@ func TestClient(t *testing.T) { So(err, ShouldNotBeNil) }) - Convey("When unspported version set should return error", func() { + Convey("When unsupported version set should return error", func() { ds := &models.DataSource{ JsonData: simplejson.NewFromAny(map[string]interface{}{ "esVersion": 6, diff --git a/pkg/tsdb/influxdb/query_test.go b/pkg/tsdb/influxdb/query_test.go index f1270560269..cc1358a72d7 100644 --- a/pkg/tsdb/influxdb/query_test.go +++ b/pkg/tsdb/influxdb/query_test.go @@ -158,7 +158,7 @@ func TestInfluxdbQueryBuilder(t *testing.T) { So(strings.Join(query.renderTags(), ""), ShouldEqual, `"key" < 10001`) }) - Convey("can render number greather then condition tags", func() { + Convey("can render number greater then condition tags", func() { query := &Query{Tags: []*Tag{{Operator: ">", Value: "10001", Key: "key"}}} So(strings.Join(query.renderTags(), ""), ShouldEqual, `"key" > 10001`) diff --git a/pkg/tsdb/prometheus/prometheus.go b/pkg/tsdb/prometheus/prometheus.go index bf9fe9f152c..83bb683fccf 100644 --- a/pkg/tsdb/prometheus/prometheus.go +++ b/pkg/tsdb/prometheus/prometheus.go @@ -92,12 +92,12 @@ func (e *PrometheusExecutor) Query(ctx context.Context, dsInfo *models.DataSourc return nil, err } - querys, err := parseQuery(dsInfo, tsdbQuery.Queries, tsdbQuery) + queries, err := parseQuery(dsInfo, tsdbQuery.Queries, tsdbQuery) if err != nil { return nil, err } - for _, query := range querys { + for _, query := range queries { timeRange := apiv1.Range{ Start: query.Start, End: query.End, diff --git a/pkg/util/md5_test.go b/pkg/util/md5_test.go index 1338d42bb51..16ef1ddb4a0 100644 --- a/pkg/util/md5_test.go +++ b/pkg/util/md5_test.go @@ -3,7 +3,7 @@ package util import "testing" func TestMd5Sum(t *testing.T) { - input := "dont hash passwords with md5" + input := "don't hash passwords with md5" have, err := Md5SumString(input) if err != nil { From f0167e17edef3e21abc00d308300d311765159c5 Mon Sep 17 00:00:00 2001 From: Mario Trangoni Date: Fri, 21 Sep 2018 13:39:24 +0200 Subject: [PATCH 14/34] Revert Fahrenheit to Farenheit This is a typo in https://github.com/grafana/grafana/blob/master/public/app/core/utils/kbn.ts#L1051 --- devenv/dev-dashboards/panel_tests_polystat.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/devenv/dev-dashboards/panel_tests_polystat.json b/devenv/dev-dashboards/panel_tests_polystat.json index fc3f4c92b3c..51d3085c438 100644 --- a/devenv/dev-dashboards/panel_tests_polystat.json +++ b/devenv/dev-dashboards/panel_tests_polystat.json @@ -884,8 +884,8 @@ "value": "celsius" }, { - "text": "Fahrenheit (°F)", - "value": "fahrenheit" + "text": "Farenheit (°F)", + "value": "farenheit" }, { "text": "Kelvin (K)", @@ -1991,8 +1991,8 @@ "value": "celsius" }, { - "text": "Fahrenheit (°F)", - "value": "fahrenheit" + "text": "Farenheit (°F)", + "value": "farenheit" }, { "text": "Kelvin (K)", @@ -3078,8 +3078,8 @@ "value": "celsius" }, { - "text": "Fahrenheit (°F)", - "value": "fahrenheit" + "text": "Farenheit (°F)", + "value": "farenheit" }, { "text": "Kelvin (K)", From da46cc2fca45b0e5310529ba5b5509e388260347 Mon Sep 17 00:00:00 2001 From: Mario Trangoni Date: Fri, 21 Sep 2018 13:41:03 +0200 Subject: [PATCH 15/34] Fix changed want md5 hash --- pkg/util/md5_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/util/md5_test.go b/pkg/util/md5_test.go index 16ef1ddb4a0..43c685b8763 100644 --- a/pkg/util/md5_test.go +++ b/pkg/util/md5_test.go @@ -10,7 +10,7 @@ func TestMd5Sum(t *testing.T) { t.Fatal("expected err to be nil") } - want := "2d6a56c82d09d374643b926d3417afba" + want := "dd1f7fdb3466c0d09c2e839d1f1530f8" if have != want { t.Fatalf("expected: %s got: %s", want, have) } From 60dfff11a049b583a13c61e2a535eae04c025c46 Mon Sep 17 00:00:00 2001 From: Mario Trangoni Date: Fri, 21 Sep 2018 13:41:31 +0200 Subject: [PATCH 16/34] Fix datbase > database --- .../datasources/testdata/broken-yaml/commented.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/services/provisioning/datasources/testdata/broken-yaml/commented.yaml b/pkg/services/provisioning/datasources/testdata/broken-yaml/commented.yaml index fc13398d472..b532c9012ec 100644 --- a/pkg/services/provisioning/datasources/testdata/broken-yaml/commented.yaml +++ b/pkg/services/provisioning/datasources/testdata/broken-yaml/commented.yaml @@ -4,7 +4,7 @@ # org_id: 1 # # list of datasources to insert/update depending -# # what's available in the datbase +# # what's available in the database #datasources: # # name of the datasource. Required # - name: Graphite From 7641c37dfcdab0b511addab081725af722477507 Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Fri, 21 Sep 2018 16:57:39 +0200 Subject: [PATCH 17/34] docs: improve oauth generic azure ad instructions --- docs/sources/auth/generic-oauth.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/auth/generic-oauth.md b/docs/sources/auth/generic-oauth.md index f89595d3b11..5bb5c4cd753 100644 --- a/docs/sources/auth/generic-oauth.md +++ b/docs/sources/auth/generic-oauth.md @@ -174,7 +174,7 @@ allowed_organizations = allowed_organizations = ``` -Note: It's important to ensure that the SERVER_ROOT_URL in Grafana is set in your Azure Application Return URLs +> Note: It's important to ensure that the [root_url](/installation/configuration/#root-url) in Grafana is set in your Azure Application Reply URLs (App -> Settings -> Reply URLs) ## Set up OAuth2 with Centrify From 5fd24e2435a28e95a88a1a9989f532c4b6809581 Mon Sep 17 00:00:00 2001 From: Jon Ferreira Date: Fri, 21 Sep 2018 17:17:29 -0400 Subject: [PATCH 18/34] Fix https://github.com/grafana/grafana/issues/13387 metric segment options displays after blur --- public/app/core/directives/metric_segment.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/public/app/core/directives/metric_segment.ts b/public/app/core/directives/metric_segment.ts index 7759e14f2cc..de904e95fc6 100644 --- a/public/app/core/directives/metric_segment.ts +++ b/public/app/core/directives/metric_segment.ts @@ -118,6 +118,9 @@ export function metricSegment($compile, $sce) { }; $scope.matcher = function(item) { + if (linkMode) { + return false; + } let str = this.query; if (str[0] === '/') { str = str.substring(1); From 98dad530e282f7aed968a4ee62afdfcb36422922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 22 Sep 2018 10:06:57 +0200 Subject: [PATCH 19/34] provisioning: changed provisioning default update interval from 3 to 10 seconds --- docs/sources/administration/provisioning.md | 2 +- pkg/services/provisioning/dashboards/config_reader.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/sources/administration/provisioning.md b/docs/sources/administration/provisioning.md index a026d1ec0cd..16d425d289a 100644 --- a/docs/sources/administration/provisioning.md +++ b/docs/sources/administration/provisioning.md @@ -200,7 +200,7 @@ providers: folder: '' type: file disableDeletion: false - updateIntervalSeconds: 3 #how often Grafana will scan for changed dashboards + updateIntervalSeconds: 10 #how often Grafana will scan for changed dashboards options: path: /var/lib/grafana/dashboards ``` diff --git a/pkg/services/provisioning/dashboards/config_reader.go b/pkg/services/provisioning/dashboards/config_reader.go index 7508550838f..bfef06b558e 100644 --- a/pkg/services/provisioning/dashboards/config_reader.go +++ b/pkg/services/provisioning/dashboards/config_reader.go @@ -83,7 +83,7 @@ func (cr *configReader) readConfig() ([]*DashboardsAsConfig, error) { } if dashboards[i].UpdateIntervalSeconds == 0 { - dashboards[i].UpdateIntervalSeconds = 3 + dashboards[i].UpdateIntervalSeconds = 10 } } From e91729a5683114d4b8729eca6a21b7eb35333184 Mon Sep 17 00:00:00 2001 From: Jon Ferreira Date: Sat, 22 Sep 2018 15:00:36 -0400 Subject: [PATCH 20/34] When stacking graphs, always include the y-offset so that tooltips can render proper values for individual points --- public/vendor/flot/jquery.flot.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/vendor/flot/jquery.flot.js b/public/vendor/flot/jquery.flot.js index 8ee09e25c41..4a85b08c8d7 100644 --- a/public/vendor/flot/jquery.flot.js +++ b/public/vendor/flot/jquery.flot.js @@ -1129,7 +1129,7 @@ Licensed under the MIT license. format.push({ x: true, number: true, required: true }); format.push({ y: true, number: true, required: true }); - if (s.bars.show || (s.lines.show && s.lines.fill)) { + if (s.stack || s.bars.show || (s.lines.show && s.lines.fill)) { var autoscale = !!((s.bars.show && s.bars.zero) || (s.lines.show && s.lines.zero)); format.push({ y: true, number: true, required: false, defaultValue: 0, autoscale: autoscale }); if (s.bars.horizontal) { From 9774ec0ad75516a5b3e5151a07712fad8ae998b4 Mon Sep 17 00:00:00 2001 From: bergquist Date: Mon, 24 Sep 2018 09:41:11 +0200 Subject: [PATCH 21/34] devenv: adds script for creating many dashboards with alerts --- .gitignore | 1 + .../bulk_alerting_dashboards.yaml | 9 + .../bulkdash_alerting.jsonnet | 168 ++++++++++++++++++ devenv/setup.sh | 23 ++- 4 files changed, 198 insertions(+), 3 deletions(-) create mode 100644 devenv/bulk_alerting_dashboards/bulk_alerting_dashboards.yaml create mode 100644 devenv/bulk_alerting_dashboards/bulkdash_alerting.jsonnet diff --git a/.gitignore b/.gitignore index 78b8d075ef6..08525d92519 100644 --- a/.gitignore +++ b/.gitignore @@ -72,3 +72,4 @@ debug.test *.orig /devenv/bulk-dashboards/*.json +/devenv/bulk_alerting_dashboards/*.json diff --git a/devenv/bulk_alerting_dashboards/bulk_alerting_dashboards.yaml b/devenv/bulk_alerting_dashboards/bulk_alerting_dashboards.yaml new file mode 100644 index 00000000000..1ede5dcd30a --- /dev/null +++ b/devenv/bulk_alerting_dashboards/bulk_alerting_dashboards.yaml @@ -0,0 +1,9 @@ +apiVersion: 1 + +providers: + - name: 'Bulk alerting dashboards' + folder: 'Bulk alerting dashboards' + type: file + options: + path: devenv/bulk_alerting_dashboards + diff --git a/devenv/bulk_alerting_dashboards/bulkdash_alerting.jsonnet b/devenv/bulk_alerting_dashboards/bulkdash_alerting.jsonnet new file mode 100644 index 00000000000..daa362b3ced --- /dev/null +++ b/devenv/bulk_alerting_dashboards/bulkdash_alerting.jsonnet @@ -0,0 +1,168 @@ +{ + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "links": [], + "panels": [ + { + "alert": { + "conditions": [ + { + "evaluator": { + "params": [ + 65 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "frequency": "10s", + "handler": 1, + "name": "bulk alerting", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fill": 1, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "$$hashKey": "object:117", + "expr": "go_goroutines", + "format": "time_series", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 50 + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Panel Title", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "New dashboard", + "uid": null, + "version": 0 +} \ No newline at end of file diff --git a/devenv/setup.sh b/devenv/setup.sh index cc71ecc71bf..8b8f2d51284 100755 --- a/devenv/setup.sh +++ b/devenv/setup.sh @@ -14,6 +14,20 @@ bulkDashboard() { ln -s -f -r ./bulk-dashboards/bulk-dashboards.yaml ../conf/provisioning/dashboards/custom.yaml } +bulkAlertingDashboard() { + + requiresJsonnet + + COUNTER=0 + MAX=100 + while [ $COUNTER -lt $MAX ]; do + jsonnet -o "bulk_alerting_dashboards/alerting_dashboard${COUNTER}.json" -e "local bulkDash = import 'bulk_alerting_dashboards/bulkdash_alerting.jsonnet'; bulkDash + { uid: 'uid-${COUNTER}', title: 'alerting-title-${COUNTER}' }" + let COUNTER=COUNTER+1 + done + + ln -s -f -r ./bulk_alerting_dashboards/bulk_alerting_dashboards.yaml ../conf/provisioning/dashboards/custom.yaml +} + requiresJsonnet() { if ! type "jsonnet" > /dev/null; then echo "you need you install jsonnet to run this script" @@ -36,8 +50,9 @@ devDatasources() { usage() { echo -e "\n" echo "Usage:" - echo " bulk-dashboards - create and provisioning 400 dashboards" - echo " no args - provisiong core datasources and dev dashboards" + echo " bulk-dashboards - create and provisioning 400 dashboards" + echo " bulk-alerting-dashboards - create and provisioning 400 dashboards with alerts" + echo " no args - provisiong core datasources and dev dashboards" } main() { @@ -48,7 +63,9 @@ main() { local cmd=$1 - if [[ $cmd == "bulk-dashboards" ]]; then + if [[ $cmd == "bulk-alerting-dashboards" ]]; then + bulkAlertingDashboard + elif [[ $cmd == "bulk-dashboards" ]]; then bulkDashboard else devDashboards From fd5acdd857fe32915de908a7cf442cd340c354e2 Mon Sep 17 00:00:00 2001 From: bergquist Date: Mon, 24 Sep 2018 10:59:39 +0200 Subject: [PATCH 22/34] target gfdev-prometheus datasource --- devenv/bulk_alerting_dashboards/bulkdash_alerting.jsonnet | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devenv/bulk_alerting_dashboards/bulkdash_alerting.jsonnet b/devenv/bulk_alerting_dashboards/bulkdash_alerting.jsonnet index daa362b3ced..a7acd57745d 100644 --- a/devenv/bulk_alerting_dashboards/bulkdash_alerting.jsonnet +++ b/devenv/bulk_alerting_dashboards/bulkdash_alerting.jsonnet @@ -43,7 +43,7 @@ "bars": false, "dashLength": 10, "dashes": false, - "datasource": "Prometheus", + "datasource": "gdev-prometheus", "fill": 1, "gridPos": { "h": 9, From d07a3a7637fde223bf8878c1158613bc83a8bc9b Mon Sep 17 00:00:00 2001 From: David Kaltschmidt Date: Mon, 24 Sep 2018 12:16:06 +0200 Subject: [PATCH 23/34] Explore: moved code to app/features/explore --- .../{containers/Explore => features/explore}/ElapsedTime.tsx | 0 public/app/{containers/Explore => features/explore}/Explore.tsx | 0 public/app/{containers/Explore => features/explore}/Graph.tsx | 0 .../app/{containers/Explore => features/explore}/JSONViewer.tsx | 0 public/app/{containers/Explore => features/explore}/Legend.tsx | 0 public/app/{containers/Explore => features/explore}/Logs.tsx | 0 .../Explore => features/explore}/PromQueryField.test.tsx | 0 .../{containers/Explore => features/explore}/PromQueryField.tsx | 0 .../app/{containers/Explore => features/explore}/QueryField.tsx | 0 .../app/{containers/Explore => features/explore}/QueryRows.tsx | 0 public/app/{containers/Explore => features/explore}/Table.tsx | 0 .../Explore => features/explore}/TimePicker.test.tsx | 0 .../app/{containers/Explore => features/explore}/TimePicker.tsx | 0 .../app/{containers/Explore => features/explore}/Typeahead.tsx | 0 public/app/{containers/Explore => features/explore}/Value.ts | 0 public/app/{containers/Explore => features/explore}/Wrapper.tsx | 0 .../Explore => features/explore}/slate-plugins/braces.test.ts | 0 .../Explore => features/explore}/slate-plugins/braces.ts | 0 .../Explore => features/explore}/slate-plugins/clear.test.ts | 0 .../Explore => features/explore}/slate-plugins/clear.ts | 0 .../Explore => features/explore}/slate-plugins/newline.ts | 0 .../Explore => features/explore}/slate-plugins/prism/promql.ts | 0 .../Explore => features/explore}/slate-plugins/runner.ts | 0 .../{containers/Explore => features/explore}/utils/debounce.ts | 0 .../app/{containers/Explore => features/explore}/utils/dom.ts | 0 .../Explore => features/explore}/utils/prometheus.test.ts | 0 .../Explore => features/explore}/utils/prometheus.ts | 0 .../app/{containers/Explore => features/explore}/utils/query.ts | 0 public/app/routes/routes.ts | 2 +- 29 files changed, 1 insertion(+), 1 deletion(-) rename public/app/{containers/Explore => features/explore}/ElapsedTime.tsx (100%) rename public/app/{containers/Explore => features/explore}/Explore.tsx (100%) rename public/app/{containers/Explore => features/explore}/Graph.tsx (100%) rename public/app/{containers/Explore => features/explore}/JSONViewer.tsx (100%) rename public/app/{containers/Explore => features/explore}/Legend.tsx (100%) rename public/app/{containers/Explore => features/explore}/Logs.tsx (100%) rename public/app/{containers/Explore => features/explore}/PromQueryField.test.tsx (100%) rename public/app/{containers/Explore => features/explore}/PromQueryField.tsx (100%) rename public/app/{containers/Explore => features/explore}/QueryField.tsx (100%) rename public/app/{containers/Explore => features/explore}/QueryRows.tsx (100%) rename public/app/{containers/Explore => features/explore}/Table.tsx (100%) rename public/app/{containers/Explore => features/explore}/TimePicker.test.tsx (100%) rename public/app/{containers/Explore => features/explore}/TimePicker.tsx (100%) rename public/app/{containers/Explore => features/explore}/Typeahead.tsx (100%) rename public/app/{containers/Explore => features/explore}/Value.ts (100%) rename public/app/{containers/Explore => features/explore}/Wrapper.tsx (100%) rename public/app/{containers/Explore => features/explore}/slate-plugins/braces.test.ts (100%) rename public/app/{containers/Explore => features/explore}/slate-plugins/braces.ts (100%) rename public/app/{containers/Explore => features/explore}/slate-plugins/clear.test.ts (100%) rename public/app/{containers/Explore => features/explore}/slate-plugins/clear.ts (100%) rename public/app/{containers/Explore => features/explore}/slate-plugins/newline.ts (100%) rename public/app/{containers/Explore => features/explore}/slate-plugins/prism/promql.ts (100%) rename public/app/{containers/Explore => features/explore}/slate-plugins/runner.ts (100%) rename public/app/{containers/Explore => features/explore}/utils/debounce.ts (100%) rename public/app/{containers/Explore => features/explore}/utils/dom.ts (100%) rename public/app/{containers/Explore => features/explore}/utils/prometheus.test.ts (100%) rename public/app/{containers/Explore => features/explore}/utils/prometheus.ts (100%) rename public/app/{containers/Explore => features/explore}/utils/query.ts (100%) diff --git a/public/app/containers/Explore/ElapsedTime.tsx b/public/app/features/explore/ElapsedTime.tsx similarity index 100% rename from public/app/containers/Explore/ElapsedTime.tsx rename to public/app/features/explore/ElapsedTime.tsx diff --git a/public/app/containers/Explore/Explore.tsx b/public/app/features/explore/Explore.tsx similarity index 100% rename from public/app/containers/Explore/Explore.tsx rename to public/app/features/explore/Explore.tsx diff --git a/public/app/containers/Explore/Graph.tsx b/public/app/features/explore/Graph.tsx similarity index 100% rename from public/app/containers/Explore/Graph.tsx rename to public/app/features/explore/Graph.tsx diff --git a/public/app/containers/Explore/JSONViewer.tsx b/public/app/features/explore/JSONViewer.tsx similarity index 100% rename from public/app/containers/Explore/JSONViewer.tsx rename to public/app/features/explore/JSONViewer.tsx diff --git a/public/app/containers/Explore/Legend.tsx b/public/app/features/explore/Legend.tsx similarity index 100% rename from public/app/containers/Explore/Legend.tsx rename to public/app/features/explore/Legend.tsx diff --git a/public/app/containers/Explore/Logs.tsx b/public/app/features/explore/Logs.tsx similarity index 100% rename from public/app/containers/Explore/Logs.tsx rename to public/app/features/explore/Logs.tsx diff --git a/public/app/containers/Explore/PromQueryField.test.tsx b/public/app/features/explore/PromQueryField.test.tsx similarity index 100% rename from public/app/containers/Explore/PromQueryField.test.tsx rename to public/app/features/explore/PromQueryField.test.tsx diff --git a/public/app/containers/Explore/PromQueryField.tsx b/public/app/features/explore/PromQueryField.tsx similarity index 100% rename from public/app/containers/Explore/PromQueryField.tsx rename to public/app/features/explore/PromQueryField.tsx diff --git a/public/app/containers/Explore/QueryField.tsx b/public/app/features/explore/QueryField.tsx similarity index 100% rename from public/app/containers/Explore/QueryField.tsx rename to public/app/features/explore/QueryField.tsx diff --git a/public/app/containers/Explore/QueryRows.tsx b/public/app/features/explore/QueryRows.tsx similarity index 100% rename from public/app/containers/Explore/QueryRows.tsx rename to public/app/features/explore/QueryRows.tsx diff --git a/public/app/containers/Explore/Table.tsx b/public/app/features/explore/Table.tsx similarity index 100% rename from public/app/containers/Explore/Table.tsx rename to public/app/features/explore/Table.tsx diff --git a/public/app/containers/Explore/TimePicker.test.tsx b/public/app/features/explore/TimePicker.test.tsx similarity index 100% rename from public/app/containers/Explore/TimePicker.test.tsx rename to public/app/features/explore/TimePicker.test.tsx diff --git a/public/app/containers/Explore/TimePicker.tsx b/public/app/features/explore/TimePicker.tsx similarity index 100% rename from public/app/containers/Explore/TimePicker.tsx rename to public/app/features/explore/TimePicker.tsx diff --git a/public/app/containers/Explore/Typeahead.tsx b/public/app/features/explore/Typeahead.tsx similarity index 100% rename from public/app/containers/Explore/Typeahead.tsx rename to public/app/features/explore/Typeahead.tsx diff --git a/public/app/containers/Explore/Value.ts b/public/app/features/explore/Value.ts similarity index 100% rename from public/app/containers/Explore/Value.ts rename to public/app/features/explore/Value.ts diff --git a/public/app/containers/Explore/Wrapper.tsx b/public/app/features/explore/Wrapper.tsx similarity index 100% rename from public/app/containers/Explore/Wrapper.tsx rename to public/app/features/explore/Wrapper.tsx diff --git a/public/app/containers/Explore/slate-plugins/braces.test.ts b/public/app/features/explore/slate-plugins/braces.test.ts similarity index 100% rename from public/app/containers/Explore/slate-plugins/braces.test.ts rename to public/app/features/explore/slate-plugins/braces.test.ts diff --git a/public/app/containers/Explore/slate-plugins/braces.ts b/public/app/features/explore/slate-plugins/braces.ts similarity index 100% rename from public/app/containers/Explore/slate-plugins/braces.ts rename to public/app/features/explore/slate-plugins/braces.ts diff --git a/public/app/containers/Explore/slate-plugins/clear.test.ts b/public/app/features/explore/slate-plugins/clear.test.ts similarity index 100% rename from public/app/containers/Explore/slate-plugins/clear.test.ts rename to public/app/features/explore/slate-plugins/clear.test.ts diff --git a/public/app/containers/Explore/slate-plugins/clear.ts b/public/app/features/explore/slate-plugins/clear.ts similarity index 100% rename from public/app/containers/Explore/slate-plugins/clear.ts rename to public/app/features/explore/slate-plugins/clear.ts diff --git a/public/app/containers/Explore/slate-plugins/newline.ts b/public/app/features/explore/slate-plugins/newline.ts similarity index 100% rename from public/app/containers/Explore/slate-plugins/newline.ts rename to public/app/features/explore/slate-plugins/newline.ts diff --git a/public/app/containers/Explore/slate-plugins/prism/promql.ts b/public/app/features/explore/slate-plugins/prism/promql.ts similarity index 100% rename from public/app/containers/Explore/slate-plugins/prism/promql.ts rename to public/app/features/explore/slate-plugins/prism/promql.ts diff --git a/public/app/containers/Explore/slate-plugins/runner.ts b/public/app/features/explore/slate-plugins/runner.ts similarity index 100% rename from public/app/containers/Explore/slate-plugins/runner.ts rename to public/app/features/explore/slate-plugins/runner.ts diff --git a/public/app/containers/Explore/utils/debounce.ts b/public/app/features/explore/utils/debounce.ts similarity index 100% rename from public/app/containers/Explore/utils/debounce.ts rename to public/app/features/explore/utils/debounce.ts diff --git a/public/app/containers/Explore/utils/dom.ts b/public/app/features/explore/utils/dom.ts similarity index 100% rename from public/app/containers/Explore/utils/dom.ts rename to public/app/features/explore/utils/dom.ts diff --git a/public/app/containers/Explore/utils/prometheus.test.ts b/public/app/features/explore/utils/prometheus.test.ts similarity index 100% rename from public/app/containers/Explore/utils/prometheus.test.ts rename to public/app/features/explore/utils/prometheus.test.ts diff --git a/public/app/containers/Explore/utils/prometheus.ts b/public/app/features/explore/utils/prometheus.ts similarity index 100% rename from public/app/containers/Explore/utils/prometheus.ts rename to public/app/features/explore/utils/prometheus.ts diff --git a/public/app/containers/Explore/utils/query.ts b/public/app/features/explore/utils/query.ts similarity index 100% rename from public/app/containers/Explore/utils/query.ts rename to public/app/features/explore/utils/query.ts diff --git a/public/app/routes/routes.ts b/public/app/routes/routes.ts index 160250dce96..015b4ae0b51 100644 --- a/public/app/routes/routes.ts +++ b/public/app/routes/routes.ts @@ -116,7 +116,7 @@ export function setupAngularRoutes($routeProvider, $locationProvider) { template: '', resolve: { roles: () => ['Editor', 'Admin'], - component: () => import(/* webpackChunkName: "explore" */ 'app/containers/Explore/Wrapper'), + component: () => import(/* webpackChunkName: "explore" */ 'app/features/explore/Wrapper'), }, }) .when('/org', { From 30fe407e8e2ee442a5e75cf9d60c044acd809df9 Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Mon, 24 Sep 2018 12:44:37 +0200 Subject: [PATCH 24/34] devenv: fix uid for bulk alert dashboards --- devenv/setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devenv/setup.sh b/devenv/setup.sh index 8b8f2d51284..7b5499a9f52 100755 --- a/devenv/setup.sh +++ b/devenv/setup.sh @@ -21,7 +21,7 @@ bulkAlertingDashboard() { COUNTER=0 MAX=100 while [ $COUNTER -lt $MAX ]; do - jsonnet -o "bulk_alerting_dashboards/alerting_dashboard${COUNTER}.json" -e "local bulkDash = import 'bulk_alerting_dashboards/bulkdash_alerting.jsonnet'; bulkDash + { uid: 'uid-${COUNTER}', title: 'alerting-title-${COUNTER}' }" + jsonnet -o "bulk_alerting_dashboards/alerting_dashboard${COUNTER}.json" -e "local bulkDash = import 'bulk_alerting_dashboards/bulkdash_alerting.jsonnet'; bulkDash + { uid: 'bd-${COUNTER}', title: 'alerting-title-${COUNTER}' }" let COUNTER=COUNTER+1 done From 4dab595ed78feb67b8e79e8d89ef7bbf63df7eb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 24 Sep 2018 15:58:22 +0200 Subject: [PATCH 25/34] rendering: Added concurrent rendering limits --- conf/defaults.ini | 2 ++ conf/sample.ini | 2 ++ pkg/services/alerting/notifier.go | 1 + pkg/services/alerting/result_handler.go | 2 +- pkg/services/rendering/interface.go | 1 + pkg/services/rendering/rendering.go | 33 ++++++++++++++---- pkg/setting/setting.go | 14 +++++--- public/img/rendering_error.png | Bin 0 -> 3161 bytes public/img/rendering_limit.png | Bin 0 -> 3859 bytes public/img/rendering_plugin_not_installed.png | Bin 0 -> 3651 bytes public/img/rendering_timeout.png | Bin 0 -> 3382 bytes 11 files changed, 44 insertions(+), 11 deletions(-) create mode 100644 public/img/rendering_error.png create mode 100644 public/img/rendering_limit.png create mode 100644 public/img/rendering_plugin_not_installed.png create mode 100644 public/img/rendering_timeout.png diff --git a/conf/defaults.ini b/conf/defaults.ini index 15b8927e65a..caccebbd910 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -550,3 +550,5 @@ container_name = # Options to configure external image rendering server like https://github.com/grafana/grafana-image-renderer server_url = callback_url = +concurrent_limit = 10 +concurrent_limit_alerting = 5 diff --git a/conf/sample.ini b/conf/sample.ini index 2ef254f79b9..7a460faca0e 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -471,3 +471,5 @@ log_queries = # Options to configure external image rendering server like https://github.com/grafana/grafana-image-renderer ;server_url = ;callback_url = +;concurrent_limit = 10 +;concurrent_limit_alerting = 5 diff --git a/pkg/services/alerting/notifier.go b/pkg/services/alerting/notifier.go index 7fbd956f4f9..839893f3444 100644 --- a/pkg/services/alerting/notifier.go +++ b/pkg/services/alerting/notifier.go @@ -113,6 +113,7 @@ func (n *notificationService) uploadImage(context *EvalContext) (err error) { Timeout: alertTimeout / 2, OrgId: context.Rule.OrgId, OrgRole: m.ROLE_ADMIN, + IsAlert: true, } ref, err := context.GetDashboardUID() diff --git a/pkg/services/alerting/result_handler.go b/pkg/services/alerting/result_handler.go index 363d06d1132..893cca948f9 100644 --- a/pkg/services/alerting/result_handler.go +++ b/pkg/services/alerting/result_handler.go @@ -100,7 +100,7 @@ func (handler *DefaultResultHandler) Handle(evalContext *EvalContext) error { } } } - handler.notifier.SendIfNeeded(evalContext) + handler.notifier.SendIfNeeded(evalContext) return nil } diff --git a/pkg/services/rendering/interface.go b/pkg/services/rendering/interface.go index 85c139cfc04..856e6e683ff 100644 --- a/pkg/services/rendering/interface.go +++ b/pkg/services/rendering/interface.go @@ -22,6 +22,7 @@ type Opts struct { Path string Encoding string Timezone string + IsAlert bool } type RenderResult struct { diff --git a/pkg/services/rendering/rendering.go b/pkg/services/rendering/rendering.go index ecef83d74d9..2b9d91771e9 100644 --- a/pkg/services/rendering/rendering.go +++ b/pkg/services/rendering/rendering.go @@ -24,12 +24,13 @@ func init() { } type RenderingService struct { - log log.Logger - pluginClient *plugin.Client - grpcPlugin pluginModel.RendererPlugin - pluginInfo *plugins.RendererPlugin - renderAction renderFunc - domain string + log log.Logger + pluginClient *plugin.Client + grpcPlugin pluginModel.RendererPlugin + pluginInfo *plugins.RendererPlugin + renderAction renderFunc + domain string + inProgressCount int Cfg *setting.Cfg `inject:""` } @@ -89,7 +90,27 @@ func (rs *RenderingService) Run(ctx context.Context) error { return err } +func (rs *RenderingService) getLimit(isAlerting bool) int { + if isAlerting { + return rs.Cfg.RendererLimitAlerting + } else { + return rs.Cfg.RendererLimit + } +} + func (rs *RenderingService) Render(ctx context.Context, opts Opts) (*RenderResult, error) { + if rs.inProgressCount > rs.getLimit(opts.IsAlert) { + return &RenderResult{ + FilePath: filepath.Join(setting.HomePath, "public/img/rendering_limit.png"), + }, nil + } + + defer func() { + rs.inProgressCount -= 1 + }() + + rs.inProgressCount += 1 + if rs.renderAction != nil { return rs.renderAction(ctx, opts) } else { diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go index 1a253b9b238..71e499f9298 100644 --- a/pkg/setting/setting.go +++ b/pkg/setting/setting.go @@ -196,10 +196,13 @@ type Cfg struct { Smtp SmtpSettings // Rendering - ImagesDir string - PhantomDir string - RendererUrl string - RendererCallbackUrl string + ImagesDir string + PhantomDir string + RendererUrl string + RendererCallbackUrl string + RendererLimit int + RendererLimitAlerting int + DisableBruteForceLoginProtection bool TempDataLifetime time.Duration @@ -645,6 +648,9 @@ func (cfg *Cfg) Load(args *CommandLineArgs) error { // Rendering renderSec := iniFile.Section("rendering") + cfg.RendererLimit = renderSec.Key("concurrent_limit").MustInt(10) + cfg.RendererLimitAlerting = renderSec.Key("concurrent_limit").MustInt(5) + cfg.RendererUrl = renderSec.Key("server_url").String() cfg.RendererCallbackUrl = renderSec.Key("callback_url").String() if cfg.RendererCallbackUrl == "" { diff --git a/public/img/rendering_error.png b/public/img/rendering_error.png new file mode 100644 index 0000000000000000000000000000000000000000..cc327c267be865451f631737dbcbb7eda1af4a71 GIT binary patch literal 3161 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 H$HjjG5OI== literal 0 HcmV?d00001 diff --git a/public/img/rendering_limit.png b/public/img/rendering_limit.png new file mode 100644 index 0000000000000000000000000000000000000000..f2ba9aad0ba8047d6d770694dc6fb8fff9a4c646 GIT binary patch literal 3859 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 literal 0 HcmV?d00001 diff --git a/public/img/rendering_plugin_not_installed.png b/public/img/rendering_plugin_not_installed.png new file mode 100644 index 0000000000000000000000000000000000000000..f135ff7cc9f9b3898396404cfe1b510fd81bbc42 GIT binary patch literal 3651 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 UD64y-2ma-(&JfL*r##9320j&!NB{r; literal 0 HcmV?d00001 diff --git a/public/img/rendering_timeout.png b/public/img/rendering_timeout.png new file mode 100644 index 0000000000000000000000000000000000000000..07a87eb5de3f7d288899b0835a5f81205d15e27c GIT binary patch literal 3382 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 c|9=4X#! Date: Tue, 25 Sep 2018 11:14:44 +0200 Subject: [PATCH 26/34] fix: Legend to the right, as table, should follow the width prop. Removing css conflicting with baron's width calculation. #13312 --- public/sass/components/_panel_graph.scss | 4 ---- 1 file changed, 4 deletions(-) diff --git a/public/sass/components/_panel_graph.scss b/public/sass/components/_panel_graph.scss index 72f3ca3dbbe..8049a2c3107 100644 --- a/public/sass/components/_panel_graph.scss +++ b/public/sass/components/_panel_graph.scss @@ -17,10 +17,6 @@ padding-left: 0px; } - .graph-legend-table { - width: auto; - } - .graph-legend-table .graph-legend-series { display: table-row; } From 46405288570acc4eb02746eeebaabe4ea6c9324b Mon Sep 17 00:00:00 2001 From: Johannes Schill Date: Tue, 25 Sep 2018 11:17:26 +0200 Subject: [PATCH 27/34] Remove non-existing css prop --- public/sass/components/_panel_graph.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/public/sass/components/_panel_graph.scss b/public/sass/components/_panel_graph.scss index 8049a2c3107..01fcc5a3e64 100644 --- a/public/sass/components/_panel_graph.scss +++ b/public/sass/components/_panel_graph.scss @@ -31,7 +31,6 @@ } .datapoints-warning { - pointer: none; position: absolute; top: 50%; left: 50%; From cb96c6d9424decdf217ef42a1dba5484f055e2ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 25 Sep 2018 12:17:04 +0200 Subject: [PATCH 28/34] Changed setting to be an alerting setting --- conf/defaults.ini | 6 ++++-- conf/sample.ini | 6 ++++-- docs/sources/installation/configuration.md | 8 ++++++++ pkg/api/render.go | 19 ++++++++++--------- pkg/services/alerting/notifier.go | 13 +++++++------ pkg/services/rendering/interface.go | 20 ++++++++++---------- pkg/services/rendering/rendering.go | 10 +--------- pkg/setting/setting.go | 5 ++--- 8 files changed, 46 insertions(+), 41 deletions(-) diff --git a/conf/defaults.ini b/conf/defaults.ini index caccebbd910..eb8debc0094 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -474,6 +474,10 @@ error_or_timeout = alerting # Default setting for how Grafana handles nodata or null values in alerting. (alerting, no_data, keep_state, ok) nodata_or_nullvalues = no_data +# Alert notifications can include images, but rendering many images at the same time can overload the server +# This limit will protect the server from render overloading and make sure notifications are sent out quickly +concurrent_render_limit = 5 + #################################### Explore ############################# [explore] # Enable the Explore section @@ -550,5 +554,3 @@ container_name = # Options to configure external image rendering server like https://github.com/grafana/grafana-image-renderer server_url = callback_url = -concurrent_limit = 10 -concurrent_limit_alerting = 5 diff --git a/conf/sample.ini b/conf/sample.ini index 7a460faca0e..f393c66a20e 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -393,6 +393,10 @@ log_queries = # Default setting for how Grafana handles nodata or null values in alerting. (alerting, no_data, keep_state, ok) ;nodata_or_nullvalues = no_data +# Alert notifications can include images, but rendering many images at the same time can overload the server +# This limit will protect the server from render overloading and make sure notifications are sent out quickly +;concurrent_render_limit = 5 + #################################### Explore ############################# [explore] # Enable the Explore section @@ -471,5 +475,3 @@ log_queries = # Options to configure external image rendering server like https://github.com/grafana/grafana-image-renderer ;server_url = ;callback_url = -;concurrent_limit = 10 -;concurrent_limit_alerting = 5 diff --git a/docs/sources/installation/configuration.md b/docs/sources/installation/configuration.md index 2bf4789257d..5a838e8a321 100644 --- a/docs/sources/installation/configuration.md +++ b/docs/sources/installation/configuration.md @@ -566,3 +566,11 @@ Default setting for new alert rules. Defaults to categorize error and timeouts a > Available in 5.3 and above Default setting for how Grafana handles nodata or null values in alerting. (alerting, no_data, keep_state, ok) + +# concurrent_render_limit + +> Available in 5.3 and above + +Alert notifications can include images, but rendering many images at the same time can overload the server. +This limit will protect the server from render overloading and make sure notifications are sent out quickly. Default +value is `5`. diff --git a/pkg/api/render.go b/pkg/api/render.go index b8ef6cc5cb6..cf672af9bea 100644 --- a/pkg/api/render.go +++ b/pkg/api/render.go @@ -41,15 +41,16 @@ func (hs *HTTPServer) RenderToPng(c *m.ReqContext) { } result, err := hs.RenderService.Render(c.Req.Context(), rendering.Opts{ - Width: width, - Height: height, - Timeout: time.Duration(timeout) * time.Second, - OrgId: c.OrgId, - UserId: c.UserId, - OrgRole: c.OrgRole, - Path: c.Params("*") + queryParams, - Timezone: queryReader.Get("tz", ""), - Encoding: queryReader.Get("encoding", ""), + Width: width, + Height: height, + Timeout: time.Duration(timeout) * time.Second, + OrgId: c.OrgId, + UserId: c.UserId, + OrgRole: c.OrgRole, + Path: c.Params("*") + queryParams, + Timezone: queryReader.Get("tz", ""), + Encoding: queryReader.Get("encoding", ""), + ConcurrentLimit: 30, }) if err != nil && err == rendering.ErrTimeout { diff --git a/pkg/services/alerting/notifier.go b/pkg/services/alerting/notifier.go index 839893f3444..353df1938a2 100644 --- a/pkg/services/alerting/notifier.go +++ b/pkg/services/alerting/notifier.go @@ -11,6 +11,7 @@ import ( "github.com/grafana/grafana/pkg/log" "github.com/grafana/grafana/pkg/metrics" "github.com/grafana/grafana/pkg/services/rendering" + "github.com/grafana/grafana/pkg/setting" m "github.com/grafana/grafana/pkg/models" ) @@ -108,12 +109,12 @@ func (n *notificationService) uploadImage(context *EvalContext) (err error) { } renderOpts := rendering.Opts{ - Width: 1000, - Height: 500, - Timeout: alertTimeout / 2, - OrgId: context.Rule.OrgId, - OrgRole: m.ROLE_ADMIN, - IsAlert: true, + Width: 1000, + Height: 500, + Timeout: alertTimeout / 2, + OrgId: context.Rule.OrgId, + OrgRole: m.ROLE_ADMIN, + ConcurrentLimit: setting.AlertingRenderLimit, } ref, err := context.GetDashboardUID() diff --git a/pkg/services/rendering/interface.go b/pkg/services/rendering/interface.go index 856e6e683ff..39cb1ada0f5 100644 --- a/pkg/services/rendering/interface.go +++ b/pkg/services/rendering/interface.go @@ -13,16 +13,16 @@ var ErrNoRenderer = errors.New("No renderer plugin found nor is an external rend var ErrPhantomJSNotInstalled = errors.New("PhantomJS executable not found") type Opts struct { - Width int - Height int - Timeout time.Duration - OrgId int64 - UserId int64 - OrgRole models.RoleType - Path string - Encoding string - Timezone string - IsAlert bool + Width int + Height int + Timeout time.Duration + OrgId int64 + UserId int64 + OrgRole models.RoleType + Path string + Encoding string + Timezone string + ConcurrentLimit int } type RenderResult struct { diff --git a/pkg/services/rendering/rendering.go b/pkg/services/rendering/rendering.go index 2b9d91771e9..0b4f23e93b4 100644 --- a/pkg/services/rendering/rendering.go +++ b/pkg/services/rendering/rendering.go @@ -90,16 +90,8 @@ func (rs *RenderingService) Run(ctx context.Context) error { return err } -func (rs *RenderingService) getLimit(isAlerting bool) int { - if isAlerting { - return rs.Cfg.RendererLimitAlerting - } else { - return rs.Cfg.RendererLimit - } -} - func (rs *RenderingService) Render(ctx context.Context, opts Opts) (*RenderResult, error) { - if rs.inProgressCount > rs.getLimit(opts.IsAlert) { + if rs.inProgressCount > opts.ConcurrentLimit { return &RenderResult{ FilePath: filepath.Join(setting.HomePath, "public/img/rendering_limit.png"), }, nil diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go index 71e499f9298..27df73a9eed 100644 --- a/pkg/setting/setting.go +++ b/pkg/setting/setting.go @@ -166,6 +166,7 @@ var ( // Alerting AlertingEnabled bool ExecuteAlerts bool + AlertingRenderLimit int AlertingErrorOrTimeout string AlertingNoDataOrNullValues string @@ -648,9 +649,6 @@ func (cfg *Cfg) Load(args *CommandLineArgs) error { // Rendering renderSec := iniFile.Section("rendering") - cfg.RendererLimit = renderSec.Key("concurrent_limit").MustInt(10) - cfg.RendererLimitAlerting = renderSec.Key("concurrent_limit").MustInt(5) - cfg.RendererUrl = renderSec.Key("server_url").String() cfg.RendererCallbackUrl = renderSec.Key("callback_url").String() if cfg.RendererCallbackUrl == "" { @@ -683,6 +681,7 @@ func (cfg *Cfg) Load(args *CommandLineArgs) error { alerting := iniFile.Section("alerting") AlertingEnabled = alerting.Key("enabled").MustBool(true) ExecuteAlerts = alerting.Key("execute_alerts").MustBool(true) + AlertingRenderLimit = alerting.Key("concurrent_render_limit").MustInt(5) AlertingErrorOrTimeout = alerting.Key("error_or_timeout").MustString("alerting") AlertingNoDataOrNullValues = alerting.Key("nodata_or_nullvalues").MustString("no_data") From d2f2c3f22034f947b4564123bba5fdfc019cc143 Mon Sep 17 00:00:00 2001 From: Axel Pirek Date: Tue, 25 Sep 2018 12:38:02 +0200 Subject: [PATCH 29/34] Fix spelling of your and you're --- CHANGELOG.md | 2 +- .../graphite1/conf/opt/graphite/conf/aggregation-rules.conf | 2 +- docs/README.md | 2 +- docs/sources/guides/whats-new-in-v4-2.md | 2 +- docs/sources/tutorials/ha_setup.md | 2 +- pkg/cmd/grafana-cli/commands/install_command.go | 2 +- public/views/index.template.html | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ace4348af99..39479054af3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -505,7 +505,7 @@ See [security announcement](https://community.grafana.com/t/grafana-5-2-3-and-4- # 4.6.2 (2017-11-16) ## Important -* **Prometheus**: Fixes bug with new prometheus alerts in Grafana. Make sure to download this version if your using Prometheus for alerting. More details in the issue. [#9777](https://github.com/grafana/grafana/issues/9777) +* **Prometheus**: Fixes bug with new prometheus alerts in Grafana. Make sure to download this version if you're using Prometheus for alerting. More details in the issue. [#9777](https://github.com/grafana/grafana/issues/9777) ## Fixes * **Color picker**: Bug after using textbox input field to change/paste color string [#9769](https://github.com/grafana/grafana/issues/9769) diff --git a/devenv/docker/blocks/graphite1/conf/opt/graphite/conf/aggregation-rules.conf b/devenv/docker/blocks/graphite1/conf/opt/graphite/conf/aggregation-rules.conf index c9520124a2a..792bbfd6857 100644 --- a/devenv/docker/blocks/graphite1/conf/opt/graphite/conf/aggregation-rules.conf +++ b/devenv/docker/blocks/graphite1/conf/opt/graphite/conf/aggregation-rules.conf @@ -8,7 +8,7 @@ # 'avg'. The name of the aggregate metric will be derived from # 'output_template' filling in any captured fields from 'input_pattern'. # -# For example, if you're metric naming scheme is: +# For example, if your metric naming scheme is: # # .applications... # diff --git a/docs/README.md b/docs/README.md index ff5ef6a4131..7310f184a60 100644 --- a/docs/README.md +++ b/docs/README.md @@ -65,7 +65,7 @@ make docs-build This will rebuild the docs docker container. -To be able to use the image your have to quit (CTRL-C) the `make watch` command (that you run in the same directory as this README). Then simply rerun `make watch`, it will restart the docs server but now with access to your image. +To be able to use the image you have to quit (CTRL-C) the `make watch` command (that you run in the same directory as this README). Then simply rerun `make watch`, it will restart the docs server but now with access to your image. ### Editing content diff --git a/docs/sources/guides/whats-new-in-v4-2.md b/docs/sources/guides/whats-new-in-v4-2.md index e976ed24700..e36e762bb76 100644 --- a/docs/sources/guides/whats-new-in-v4-2.md +++ b/docs/sources/guides/whats-new-in-v4-2.md @@ -67,7 +67,7 @@ Making it possible to have users in multiple groups and have detailed access con ## Upgrade & Breaking changes -If your using https in grafana we now force you to use tls 1.2 and the most secure ciphers. +If you're using https in grafana we now force you to use tls 1.2 and the most secure ciphers. We think its better to be secure by default rather then making it configurable. If you want to run https with lower versions of tls we suggest you put a reserve proxy in front of grafana. diff --git a/docs/sources/tutorials/ha_setup.md b/docs/sources/tutorials/ha_setup.md index 0f138b20a17..5fdb091a348 100644 --- a/docs/sources/tutorials/ha_setup.md +++ b/docs/sources/tutorials/ha_setup.md @@ -22,7 +22,7 @@ Setting up Grafana for high availability is fairly simple. It comes down to two First, you need to do is to setup MySQL or Postgres on another server and configure Grafana to use that database. You can find the configuration for doing that in the [[database]]({{< relref "configuration.md" >}}#database) section in the grafana config. -Grafana will now persist all long term data in the database. How to configure the database for high availability is out of scope for this guide. We recommend finding an expert on for the database your using. +Grafana will now persist all long term data in the database. How to configure the database for high availability is out of scope for this guide. We recommend finding an expert on for the database you're using. ## User sessions diff --git a/pkg/cmd/grafana-cli/commands/install_command.go b/pkg/cmd/grafana-cli/commands/install_command.go index 5d4969e06af..f88bb9bbfff 100644 --- a/pkg/cmd/grafana-cli/commands/install_command.go +++ b/pkg/cmd/grafana-cli/commands/install_command.go @@ -112,7 +112,7 @@ func SelectVersion(plugin m.Plugin, version string) (m.Version, error) { } } - return m.Version{}, errors.New("Could not find the version your looking for") + return m.Version{}, errors.New("Could not find the version you're looking for") } func RemoveGitBuildFromName(pluginName, filename string) string { diff --git a/public/views/index.template.html b/public/views/index.template.html index 606db2c769e..ec51a12d34f 100644 --- a/public/views/index.template.html +++ b/public/views/index.template.html @@ -184,7 +184,7 @@
Loading Grafana

- If your seeing this Grafana has failed to load its application files + If you're seeing this Grafana has failed to load its application files

From 862ca07f037cf90c03674172954d034b49f3306f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 25 Sep 2018 14:01:38 +0200 Subject: [PATCH 30/34] fix: updated tests --- pkg/services/provisioning/dashboards/config_reader_test.go | 4 ++-- .../test-configs/dashboards-from-disk/dev-dashboards.yaml | 2 +- .../dashboards/testdata/test-configs/version-0/version-0.yaml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/services/provisioning/dashboards/config_reader_test.go b/pkg/services/provisioning/dashboards/config_reader_test.go index df0d2ae038e..d386e42349d 100644 --- a/pkg/services/provisioning/dashboards/config_reader_test.go +++ b/pkg/services/provisioning/dashboards/config_reader_test.go @@ -70,7 +70,7 @@ func validateDashboardAsConfig(t *testing.T, cfg []*DashboardsAsConfig) { So(len(ds.Options), ShouldEqual, 1) So(ds.Options["path"], ShouldEqual, "/var/lib/grafana/dashboards") So(ds.DisableDeletion, ShouldBeTrue) - So(ds.UpdateIntervalSeconds, ShouldEqual, 10) + So(ds.UpdateIntervalSeconds, ShouldEqual, 15) ds2 := cfg[1] So(ds2.Name, ShouldEqual, "default") @@ -81,5 +81,5 @@ func validateDashboardAsConfig(t *testing.T, cfg []*DashboardsAsConfig) { So(len(ds2.Options), ShouldEqual, 1) So(ds2.Options["path"], ShouldEqual, "/var/lib/grafana/dashboards") So(ds2.DisableDeletion, ShouldBeFalse) - So(ds2.UpdateIntervalSeconds, ShouldEqual, 3) + So(ds2.UpdateIntervalSeconds, ShouldEqual, 10) } diff --git a/pkg/services/provisioning/dashboards/testdata/test-configs/dashboards-from-disk/dev-dashboards.yaml b/pkg/services/provisioning/dashboards/testdata/test-configs/dashboards-from-disk/dev-dashboards.yaml index e26c329f87c..c43c4a14c53 100644 --- a/pkg/services/provisioning/dashboards/testdata/test-configs/dashboards-from-disk/dev-dashboards.yaml +++ b/pkg/services/provisioning/dashboards/testdata/test-configs/dashboards-from-disk/dev-dashboards.yaml @@ -6,7 +6,7 @@ providers: folder: 'developers' editable: true disableDeletion: true - updateIntervalSeconds: 10 + updateIntervalSeconds: 15 type: file options: path: /var/lib/grafana/dashboards diff --git a/pkg/services/provisioning/dashboards/testdata/test-configs/version-0/version-0.yaml b/pkg/services/provisioning/dashboards/testdata/test-configs/version-0/version-0.yaml index 69a317fb396..8b7b8991759 100644 --- a/pkg/services/provisioning/dashboards/testdata/test-configs/version-0/version-0.yaml +++ b/pkg/services/provisioning/dashboards/testdata/test-configs/version-0/version-0.yaml @@ -3,7 +3,7 @@ folder: 'developers' editable: true disableDeletion: true - updateIntervalSeconds: 10 + updateIntervalSeconds: 15 type: file options: path: /var/lib/grafana/dashboards From 54f7920f0dff5ceee62fb3e9d1ebac6bce6ede60 Mon Sep 17 00:00:00 2001 From: Johannes Schill Date: Tue, 25 Sep 2018 14:02:55 +0200 Subject: [PATCH 31/34] Remove option r from ln command since its not working everywhere --- devenv/setup.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/devenv/setup.sh b/devenv/setup.sh index 7b5499a9f52..c9cc0d47a6f 100755 --- a/devenv/setup.sh +++ b/devenv/setup.sh @@ -11,7 +11,7 @@ bulkDashboard() { let COUNTER=COUNTER+1 done - ln -s -f -r ./bulk-dashboards/bulk-dashboards.yaml ../conf/provisioning/dashboards/custom.yaml + ln -s -f ../../../devenv/bulk-dashboards/bulk-dashboards.yaml ../conf/provisioning/dashboards/custom.yaml } bulkAlertingDashboard() { @@ -25,7 +25,7 @@ bulkAlertingDashboard() { let COUNTER=COUNTER+1 done - ln -s -f -r ./bulk_alerting_dashboards/bulk_alerting_dashboards.yaml ../conf/provisioning/dashboards/custom.yaml + ln -s -f ../../../devenv/bulk_alerting_dashboards/bulk_alerting_dashboards.yaml ../conf/provisioning/dashboards/custom.yaml } requiresJsonnet() { From 499b71c8ff49404eb07aacb67caf2891d2feddbf Mon Sep 17 00:00:00 2001 From: Chris Hicks <29731108+Chris-Hicks@users.noreply.github.com> Date: Tue, 25 Sep 2018 16:12:11 +0100 Subject: [PATCH 32/34] Remove .dropdown-menu-open on body click fixes #13409 --- public/app/core/components/grafana_app.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/public/app/core/components/grafana_app.ts b/public/app/core/components/grafana_app.ts index a0ea0279d30..4272c8a0b71 100644 --- a/public/app/core/components/grafana_app.ts +++ b/public/app/core/components/grafana_app.ts @@ -245,6 +245,9 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop return; } + // ensure dropdown menu doesn't impact on z-index + body.find('.dropdown-menu-open').removeClass('dropdown-menu-open'); + // for stuff that animates, slides out etc, clicking it needs to // hide it right away const clickAutoHide = target.closest('[data-click-hide]'); From 9dbdc29118dad87f1a32d88d2697ca09c6d1102a Mon Sep 17 00:00:00 2001 From: Sven Klemm Date: Wed, 26 Sep 2018 10:56:25 +0200 Subject: [PATCH 33/34] filter NULL values for column value suggestions --- public/app/plugins/datasource/postgres/meta_query.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/public/app/plugins/datasource/postgres/meta_query.ts b/public/app/plugins/datasource/postgres/meta_query.ts index 7339a3e3882..fd13f3b4482 100644 --- a/public/app/plugins/datasource/postgres/meta_query.ts +++ b/public/app/plugins/datasource/postgres/meta_query.ts @@ -144,6 +144,7 @@ table_schema IN ( let query = 'SELECT DISTINCT quote_literal(' + column + ')'; query += ' FROM ' + this.target.table; query += ' WHERE $__timeFilter(' + this.target.timeColumn + ')'; + query += ' AND ' + column + ' IS NOT NULL'; query += ' ORDER BY 1 LIMIT 100'; return query; } From b04052f51573d847b907eb3a2aafd309aece4f89 Mon Sep 17 00:00:00 2001 From: bergquist Date: Mon, 24 Sep 2018 16:16:10 +0200 Subject: [PATCH 34/34] alerting: move all notification conditions to defaultShouldNotify --- pkg/models/alert_notifications.go | 2 +- pkg/services/alerting/notifier.go | 2 +- pkg/services/alerting/notifiers/base.go | 21 ++-- pkg/services/alerting/notifiers/base_test.go | 102 +++++++++++++----- pkg/services/sqlstore/alert_notification.go | 18 ++-- .../sqlstore/alert_notification_test.go | 24 +++-- 6 files changed, 110 insertions(+), 59 deletions(-) diff --git a/pkg/models/alert_notifications.go b/pkg/models/alert_notifications.go index 42d33d5ed22..b90b3d36ced 100644 --- a/pkg/models/alert_notifications.go +++ b/pkg/models/alert_notifications.go @@ -98,7 +98,7 @@ type GetLatestNotificationQuery struct { AlertId int64 NotifierId int64 - Result *AlertNotificationJournal + Result []AlertNotificationJournal } type CleanNotificationJournalCommand struct { diff --git a/pkg/services/alerting/notifier.go b/pkg/services/alerting/notifier.go index 353df1938a2..cbad5cbfdcf 100644 --- a/pkg/services/alerting/notifier.go +++ b/pkg/services/alerting/notifier.go @@ -68,7 +68,7 @@ func (n *notificationService) sendNotifications(evalContext *EvalContext, notifi // Verify that we can send the notification again // but this time within the same transaction. - if !evalContext.IsTestRun && !not.ShouldNotify(context.Background(), evalContext) { + if !evalContext.IsTestRun && !not.ShouldNotify(ctx, evalContext) { return nil } diff --git a/pkg/services/alerting/notifiers/base.go b/pkg/services/alerting/notifiers/base.go index ca011356247..24daa02bce8 100644 --- a/pkg/services/alerting/notifiers/base.go +++ b/pkg/services/alerting/notifiers/base.go @@ -42,12 +42,21 @@ func NewNotifierBase(model *models.AlertNotification) NotifierBase { } } -func defaultShouldNotify(context *alerting.EvalContext, sendReminder bool, frequency time.Duration, lastNotify time.Time) bool { +func defaultShouldNotify(context *alerting.EvalContext, sendReminder bool, frequency time.Duration, journals []models.AlertNotificationJournal) bool { // Only notify on state change. if context.PrevAlertState == context.Rule.State && !sendReminder { return false } + // get last successfully sent notification + lastNotify := time.Time{} + for _, j := range journals { + if j.Success { + lastNotify = time.Unix(j.SentAt, 0) + break + } + } + // Do not notify if interval has not elapsed if sendReminder && !lastNotify.IsZero() && lastNotify.Add(frequency).After(time.Now()) { return false @@ -75,20 +84,12 @@ func (n *NotifierBase) ShouldNotify(ctx context.Context, c *alerting.EvalContext } err := bus.DispatchCtx(ctx, cmd) - if err == models.ErrJournalingNotFound { - return true - } - if err != nil { n.log.Error("Could not determine last time alert notifier fired", "Alert name", c.Rule.Name, "Error", err) return false } - if !cmd.Result.Success { - return true - } - - return defaultShouldNotify(c, n.SendReminder, n.Frequency, time.Unix(cmd.Result.SentAt, 0)) + return defaultShouldNotify(c, n.SendReminder, n.Frequency, cmd.Result) } func (n *NotifierBase) GetType() string { diff --git a/pkg/services/alerting/notifiers/base_test.go b/pkg/services/alerting/notifiers/base_test.go index 57b82f32466..9ea4b82fd54 100644 --- a/pkg/services/alerting/notifiers/base_test.go +++ b/pkg/services/alerting/notifiers/base_test.go @@ -15,51 +15,105 @@ import ( ) func TestShouldSendAlertNotification(t *testing.T) { + tnow := time.Now() + tcs := []struct { name string prevState m.AlertStateType newState m.AlertStateType - expected bool sendReminder bool + frequency time.Duration + journals []m.AlertNotificationJournal + + expect bool }{ { - name: "pending -> ok should not trigger an notification", - newState: m.AlertStatePending, - prevState: m.AlertStateOK, - expected: false, + name: "pending -> ok should not trigger an notification", + newState: m.AlertStatePending, + prevState: m.AlertStateOK, + sendReminder: false, + journals: []m.AlertNotificationJournal{}, + + expect: false, }, { - name: "ok -> alerting should trigger an notification", - newState: m.AlertStateOK, - prevState: m.AlertStateAlerting, - expected: true, + name: "ok -> alerting should trigger an notification", + newState: m.AlertStateOK, + prevState: m.AlertStateAlerting, + sendReminder: false, + journals: []m.AlertNotificationJournal{}, + + expect: true, }, { - name: "ok -> pending should not trigger an notification", - newState: m.AlertStateOK, - prevState: m.AlertStatePending, - expected: false, + name: "ok -> pending should not trigger an notification", + newState: m.AlertStateOK, + prevState: m.AlertStatePending, + sendReminder: false, + journals: []m.AlertNotificationJournal{}, + + expect: false, }, { name: "ok -> ok should not trigger an notification", newState: m.AlertStateOK, prevState: m.AlertStateOK, - expected: false, sendReminder: false, + journals: []m.AlertNotificationJournal{}, + + expect: false, }, { - name: "ok -> alerting should not trigger an notification", + name: "ok -> alerting should trigger an notification", newState: m.AlertStateOK, prevState: m.AlertStateAlerting, - expected: true, sendReminder: true, + journals: []m.AlertNotificationJournal{}, + + expect: true, }, { name: "ok -> ok with reminder should not trigger an notification", newState: m.AlertStateOK, prevState: m.AlertStateOK, - expected: false, sendReminder: true, + journals: []m.AlertNotificationJournal{}, + + expect: false, + }, + { + name: "alerting -> alerting with reminder and no journaling should trigger", + newState: m.AlertStateAlerting, + prevState: m.AlertStateAlerting, + frequency: time.Minute * 10, + sendReminder: true, + journals: []m.AlertNotificationJournal{}, + + expect: true, + }, + { + name: "alerting -> alerting with reminder and successful recent journal event should not trigger", + newState: m.AlertStateAlerting, + prevState: m.AlertStateAlerting, + frequency: time.Minute * 10, + sendReminder: true, + journals: []m.AlertNotificationJournal{ + {SentAt: tnow.Add(-time.Minute).Unix(), Success: true}, + }, + + expect: false, + }, + { + name: "alerting -> alerting with reminder and failed recent journal event should trigger", + newState: m.AlertStateAlerting, + prevState: m.AlertStateAlerting, + frequency: time.Minute * 10, + sendReminder: true, + expect: true, + journals: []m.AlertNotificationJournal{ + {SentAt: tnow.Add(-time.Minute).Unix(), Success: false}, // recent failed notification + {SentAt: tnow.Add(-time.Hour).Unix(), Success: true}, // old successful notification + }, }, } @@ -69,8 +123,8 @@ func TestShouldSendAlertNotification(t *testing.T) { }) evalContext.Rule.State = tc.prevState - if defaultShouldNotify(evalContext, true, 0, time.Now()) != tc.expected { - t.Errorf("failed %s. expected %+v to return %v", tc.name, tc, tc.expected) + if defaultShouldNotify(evalContext, true, tc.frequency, tc.journals) != tc.expect { + t.Errorf("failed test %s.\n expected \n%+v \nto return: %v", tc.name, tc, tc.expect) } } } @@ -87,16 +141,6 @@ func TestShouldNotifyWhenNoJournalingIsFound(t *testing.T) { }) evalContext := alerting.NewEvalContext(context.TODO(), &alerting.Rule{}) - Convey("should notify if no journaling is found", func() { - bus.AddHandlerCtx("", func(ctx context.Context, q *m.GetLatestNotificationQuery) error { - return m.ErrJournalingNotFound - }) - - if !notifier.ShouldNotify(context.Background(), evalContext) { - t.Errorf("should send notifications when ErrJournalingNotFound is returned") - } - }) - Convey("should not notify query returns error", func() { bus.AddHandlerCtx("", func(ctx context.Context, q *m.GetLatestNotificationQuery) error { return errors.New("some kind of error unknown error") diff --git a/pkg/services/sqlstore/alert_notification.go b/pkg/services/sqlstore/alert_notification.go index 31867910ddb..df247e6891d 100644 --- a/pkg/services/sqlstore/alert_notification.go +++ b/pkg/services/sqlstore/alert_notification.go @@ -230,7 +230,7 @@ func UpdateAlertNotification(cmd *m.UpdateAlertNotificationCommand) error { } func RecordNotificationJournal(ctx context.Context, cmd *m.RecordNotificationJournalCommand) error { - return inTransactionCtx(ctx, func(sess *DBSession) error { + return withDbSession(ctx, func(sess *DBSession) error { journalEntry := &m.AlertNotificationJournal{ OrgId: cmd.OrgId, AlertId: cmd.AlertId, @@ -245,21 +245,19 @@ func RecordNotificationJournal(ctx context.Context, cmd *m.RecordNotificationJou } func GetLatestNotification(ctx context.Context, cmd *m.GetLatestNotificationQuery) error { - return inTransactionCtx(ctx, func(sess *DBSession) error { - nj := &m.AlertNotificationJournal{} + return withDbSession(ctx, func(sess *DBSession) error { + nj := []m.AlertNotificationJournal{} - _, err := sess.Desc("alert_notification_journal.sent_at"). - Limit(1). - Where("alert_notification_journal.org_id = ? AND alert_notification_journal.alert_id = ? AND alert_notification_journal.notifier_id = ?", cmd.OrgId, cmd.AlertId, cmd.NotifierId).Get(nj) + err := sess.Desc("alert_notification_journal.sent_at"). + Where("alert_notification_journal.org_id = ?", cmd.OrgId). + Where("alert_notification_journal.alert_id = ?", cmd.AlertId). + Where("alert_notification_journal.notifier_id = ?", cmd.NotifierId). + Find(&nj) if err != nil { return err } - if nj.AlertId == 0 && nj.Id == 0 && nj.NotifierId == 0 && nj.OrgId == 0 { - return m.ErrJournalingNotFound - } - cmd.Result = nj return nil }) diff --git a/pkg/services/sqlstore/alert_notification_test.go b/pkg/services/sqlstore/alert_notification_test.go index 83fb42db9bb..1e3df45b5cf 100644 --- a/pkg/services/sqlstore/alert_notification_test.go +++ b/pkg/services/sqlstore/alert_notification_test.go @@ -15,16 +15,21 @@ func TestAlertNotificationSQLAccess(t *testing.T) { InitTestDB(t) Convey("Alert notification journal", func() { - var alertId int64 = 5 + var alertId int64 = 7 var orgId int64 = 5 - var notifierId int64 = 5 + var notifierId int64 = 10 Convey("Getting last journal should raise error if no one exists", func() { query := &m.GetLatestNotificationQuery{AlertId: alertId, OrgId: orgId, NotifierId: notifierId} - err := GetLatestNotification(context.Background(), query) - So(err, ShouldEqual, m.ErrJournalingNotFound) + GetLatestNotification(context.Background(), query) + So(len(query.Result), ShouldEqual, 0) - Convey("shoulbe be able to record two journaling events", func() { + // recording an journal entry in another org to make sure org filter works as expected. + journalInOtherOrg := &m.RecordNotificationJournalCommand{AlertId: alertId, NotifierId: notifierId, OrgId: 10, Success: true, SentAt: 1} + err := RecordNotificationJournal(context.Background(), journalInOtherOrg) + So(err, ShouldBeNil) + + Convey("should be able to record two journaling events", func() { createCmd := &m.RecordNotificationJournalCommand{AlertId: alertId, NotifierId: notifierId, OrgId: orgId, Success: true, SentAt: 1} err := RecordNotificationJournal(context.Background(), createCmd) @@ -38,17 +43,20 @@ func TestAlertNotificationSQLAccess(t *testing.T) { Convey("get last journaling event", func() { err := GetLatestNotification(context.Background(), query) So(err, ShouldBeNil) - So(query.Result.SentAt, ShouldEqual, 1001) + So(len(query.Result), ShouldEqual, 2) + last := query.Result[0] + So(last.SentAt, ShouldEqual, 1001) Convey("be able to clear all journaling for an notifier", func() { cmd := &m.CleanNotificationJournalCommand{AlertId: alertId, NotifierId: notifierId, OrgId: orgId} err := CleanNotificationJournal(context.Background(), cmd) So(err, ShouldBeNil) - Convey("querying for last junaling should raise error", func() { + Convey("querying for last journaling should return no journal entries", func() { query := &m.GetLatestNotificationQuery{AlertId: alertId, OrgId: orgId, NotifierId: notifierId} err := GetLatestNotification(context.Background(), query) - So(err, ShouldEqual, m.ErrJournalingNotFound) + So(err, ShouldBeNil) + So(len(query.Result), ShouldEqual, 0) }) }) })