diff --git a/CHANGELOG.md b/CHANGELOG.md index 01315d1b773..55298901618 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,9 @@ -# 4.0-pre (unreleased) +# 4.0-beta2 (unrelased) + +### Bugfixes +* **Graph Panel**: Bar width if bars was only used in series override, [#6528](https://github.com/grafana/grafana/issues/6528) + +# 4.0-beta1 (2016-11-09) ### Enhancements * **Login**: Adds option to disable username/password logins, closes [#4674](https://github.com/grafana/grafana/issues/4674) @@ -18,12 +23,13 @@ * **Background Tasks**: Now support automatic purging of old rendered images, closes [#2172](https://github.com/grafana/grafana/issues/2172) * **Dashboard**: After inactivity hide nav/row actions, fade to nice clean view, can be toggled with `d v`, also added kiosk mode, toggled via `d k` [#6476](https://github.com/grafana/grafana/issues/6476) * **Dashboard**: Improved dashboard row menu & add panel UX [#6442](https://github.com/grafana/grafana/issues/6442) +* **Graph Panel**: Support for stacking null values [#2912](https://github.com/grafana/grafana/issues/2912), [#6287](https://github.com/grafana/grafana/issues/6287), thanks @benrubson! ### Breaking changes * **SystemD**: Change systemd description, closes [#5971](https://github.com/grafana/grafana/pull/5971) * **lodash upgrade**: Upgraded lodash from 2.4.2 to 4.15.0, this contains a number of breaking changes that could effect plugins. closes [#6021](https://github.com/grafana/grafana/pull/6021) -### Bugfixes +### Bug fixes * **Table Panel**: Fixed problem when switching to Mixed datasource in metrics tab, fixes [#5999](https://github.com/grafana/grafana/pull/5999) * **Playlist**: Fixed problem with play order not matching order defined in playlist, fixes [#5467](https://github.com/grafana/grafana/pull/5467) * **Graph panel**: Fixed problem with auto decimals on y axis when datamin=datamax, fixes [#6070](https://github.com/grafana/grafana/pull/6070) diff --git a/circle.yml b/circle.yml index 39dc626df04..2422715bda3 100644 --- a/circle.yml +++ b/circle.yml @@ -5,7 +5,7 @@ machine: GOPATH: "/home/ubuntu/.go_workspace" ORG_PATH: "github.com/grafana" REPO_PATH: "${ORG_PATH}/grafana" - GODIST: "go1.7.1.linux-amd64.tar.gz" + GODIST: "go1.7.3.linux-amd64.tar.gz" post: - mkdir -p download - test -e download/$GODIST || curl -o download/$GODIST https://storage.googleapis.com/golang/$GODIST diff --git a/docs/sources/alerting/notifications.md b/docs/sources/alerting/notifications.md index 18745b222b7..ce9dcdf1b93 100644 --- a/docs/sources/alerting/notifications.md +++ b/docs/sources/alerting/notifications.md @@ -25,31 +25,12 @@ to add and configure a `notification` object. This is done from the Alerting/Not On the notifications list page hit the `New Notification` button to go the the page where you can configure and setup a new notification. -You you specify name and type, and type specific options. You can also test the notification to make +You specify name and type, and type specific options. You can also test the notification to make sure it's working and setup correctly. - - - - - - - - - - - - - - - - - - - ### Send on all alerts -This option will make this notification used for all alert rules, existing and new. +When checked this option will make this notification used for all alert rules, existing and new. ## Supported notification types @@ -61,12 +42,25 @@ To enable email notification you have to setup [SMTP settings](/installation/con in the Grafana config. Email notification will upload an image of the alert graph to an external image destination if available or fallback on attaching the image in the email. +### Slack + +{{< imgbox max-width="40%" img="/img/docs/v4/slack_notification.png" caption="Alerting Slack Notification" >}} + +To set up slack you need to configure an incoming webhook url at slack. You can follow their guide for how +to do that https://api.slack.com/incoming-webhooks If you want to include screenshots of the firing alerts +in the slack messages you have to configure the [external image destination](#external-image-store) in Grafana. + +Setting | Description +---------- | ----------- +Recipient | allows you to override the slack recipient. +Mention | make it possible to include a mention in the slack notification sent by Grafana. Ex @here or @channel + ### Webhook The webhook notification is a simple way to send information about an state change over HTTP to a custom endpoint. Using this notification you could integrated Grafana into any system you choose, by yourself. -Example json schema: +Example json body: ```json { "title": "My alert", @@ -85,19 +79,6 @@ Example json schema: } ``` -### Slack - -{{< imgbox max-width="40%" img="/img/docs/v4/slack_notification.png" caption="Alerting Slack Notification" >}} - -To set up slack you need to configure an incoming webhook url at slack. You can follow their guide for how -to do that https://api.slack.com/incoming-webhooks If you want to include screenshots of the firing alerts -in the slack messages you have to configure the [external image destination](#external-image-store) in Grafana. - -Setting | Description ----------- | ----------- -Recipient | allows you to override the slack recipient. -Mention | make it possible to include a mention in the slack notification sent by Grafana. Ex @here or @channel - ### PagerDuty To set up PagerDuty, all you have to do is to provide an api key. @@ -120,7 +101,3 @@ config file. This is not an optional requirement, you can get slack and email notifications without setting this up. - - - - diff --git a/docs/sources/alerting/rules.md b/docs/sources/alerting/rules.md index 823637941da..ecab88f48d2 100644 --- a/docs/sources/alerting/rules.md +++ b/docs/sources/alerting/rules.md @@ -1,5 +1,5 @@ +++ -title = "Alerting Engine Rules Guide" +title = "Alerting Engine & Rules Guide" description = "Configuring Alert Rules" keywords = ["grafana", "alerting", "guide", "rules"] type = "docs" @@ -73,7 +73,7 @@ in the scenario below. - No new notifications are sent as the alert rule is already in state `Alerting`. So as you can see from the above scenario Grafana will not send out notifications when other series cause the alert -to fire if the rule already is in state ´Alerting`. To improve support for queries that return multiple series +to fire if the rule already is in state `Alerting`. To improve support for queries that return multiple series we plan to track state **per series** in a future release. ### No Data / Null values @@ -107,6 +107,12 @@ The message can contain anything, information about how you might solve the issu The actual notifications are configured and shared between multiple alerts. Read the [Notifications]({{< relref "notifications.md" >}}) guide for how to configure and setup notifications. +## Alert State History & Annotations + +Alert state changes are recorded in the internal annotation table in Grafana's database. The state changes +are visualized as annotations in the alert rule's graph panel. You can also go into the `State history` +submenu in the alert tab to view & clear state history. + ## Troubleshooting {{< imgbox max-width="40%" img="/img/docs/v4/alert_test_rule.png" caption="Test Rule" >}} diff --git a/docs/sources/installation/debian.md b/docs/sources/installation/debian.md index 2c37ef4d14f..90ebd2053fd 100644 --- a/docs/sources/installation/debian.md +++ b/docs/sources/installation/debian.md @@ -14,13 +14,22 @@ weight = 1 Description | Download ------------ | ------------- -Stable .deb for Debian-based Linux | [3.1.1 (x86-64 deb)](https://grafanarel.s3.amazonaws.com/builds/grafana_3.1.1-1470047149_amd64.deb) +Stable for Debian-based Linux | [3.1.1 (x86-64 deb)](https://grafanarel.s3.amazonaws.com/builds/grafana_3.1.1-1470047149_amd64.deb) +Latest Beta for Debian-based Linux | [4.0.0-beta1 (x86-64 deb)](https://grafanarel.s3.amazonaws.com/builds/grafana_4.0.0-1478693311beta1_amd64.deb) ## Install Stable - $ wget https://grafanarel.s3.amazonaws.com/builds/grafana_3.1.1-1470047149_amd64.deb +``` +$ wget https://grafanarel.s3.amazonaws.com/builds/grafana_3.1.1-1470047149_amd64.deb +$ sudo apt-get install -y adduser libfontconfig +$ sudo dpkg -i grafana_3.1.1-1470047149_amd64.deb +``` + +## Install Latest Beta + + $ wget https://grafanarel.s3.amazonaws.com/builds/grafana_4.0.0-1478693311beta1_amd64.deb $ sudo apt-get install -y adduser libfontconfig - $ sudo dpkg -i grafana_3.1.1-1470047149_amd64.deb + $ sudo dpkg -i grafana_4.0.0-1478693311beta1_amd64.deb ## APT Repository diff --git a/docs/sources/installation/rpm.md b/docs/sources/installation/rpm.md index b23e851182b..cf33e69aa12 100644 --- a/docs/sources/installation/rpm.md +++ b/docs/sources/installation/rpm.md @@ -14,7 +14,8 @@ weight = 2 Description | Download ------------ | ------------- -Stable .RPM for CentOS / Fedora / OpenSuse / Redhat Linux | [3.1.1 (x86-64 rpm)](https://grafanarel.s3.amazonaws.com/builds/grafana-3.1.1-1470047149.x86_64.rpm) +Stable for CentOS / Fedora / OpenSuse / Redhat Linux | [3.1.1 (x86-64 rpm)](https://grafanarel.s3.amazonaws.com/builds/grafana-3.1.1-1470047149.x86_64.rpm) +Latest Beta for CentOS / Fedora / OpenSuse / Redhat Linux | [4.0.0-beta1 (x86-64 rpm)](https://grafanarel.s3.amazonaws.com/builds/grafana-4.0.0-1478693311beta1.x86_64.rpm) ## Install Stable @@ -33,6 +34,21 @@ Or install manually using `rpm`. $ sudo rpm -i --nodeps grafana-3.1.1-1470047149.x86_64.rpm +## Or Install Latest Beta + + $ sudo yum install https://grafanarel.s3.amazonaws.com/builds/grafana-4.0.0-1478693311beta1.x86_64.rpm + +Or install manually using `rpm`. + +#### On CentOS / Fedora / Redhat: + + $ sudo yum install initscripts fontconfig + $ sudo rpm -Uvh grafana-4.0.0-1478693311beta1.x86_64.rpm + +#### On OpenSuse: + + $ sudo rpm -i --nodeps grafana-4.0.0-1478693311beta1.x86_64.rpm + ## Install via YUM Repository Add the following to a new file at `/etc/yum.repos.d/grafana.repo` diff --git a/docs/sources/installation/windows.md b/docs/sources/installation/windows.md index f75f29085c5..537e156e948 100644 --- a/docs/sources/installation/windows.md +++ b/docs/sources/installation/windows.md @@ -13,7 +13,9 @@ weight = 3 Description | Download ------------ | ------------- -Stable Zip package for Windows | [grafana.3.1.1.windows-x64.zip](https://grafanarel.s3.amazonaws.com/winbuilds/dist/grafana-3.1.1.windows-x64.zip) +Latest stable package for Windows | [grafana.3.1.1.windows-x64.zip](https://grafanarel.s3.amazonaws.com/winbuilds/dist/grafana-3.1.1.windows-x64.zip) +Latest beta package for Windows | [grafana.4.0.0-beta1.windows-x64.zip](https://grafanarel.s3.amazonaws.com/builds/grafana-4.0.0-beta1.windows-x64.zip) + ## Configure diff --git a/package.json b/package.json index e1b009ecf24..a17bf04dbcc 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "company": "Coding Instinct AB" }, "name": "grafana", - "version": "4.0.0-pre1", + "version": "4.0.0-beta1", "repository": { "type": "git", "url": "http://github.com/grafana/grafana.git" diff --git a/pkg/tsdb/influxdb/influxdb.go b/pkg/tsdb/influxdb/influxdb.go index 61be1b08556..a64a6af2ee9 100644 --- a/pkg/tsdb/influxdb/influxdb.go +++ b/pkg/tsdb/influxdb/influxdb.go @@ -57,7 +57,7 @@ func (e *InfluxDBExecutor) Execute(ctx context.Context, queries tsdb.QuerySlice, } if setting.Env == setting.DEV { - glog.Debug("Influxdb query", "raw query", query) + glog.Debug("Influxdb query", "raw query", rawQuery) } req, err := e.createRequest(rawQuery) diff --git a/pkg/tsdb/influxdb/model_parser.go b/pkg/tsdb/influxdb/model_parser.go index cbd4b397d9d..2db7a78ed75 100644 --- a/pkg/tsdb/influxdb/model_parser.go +++ b/pkg/tsdb/influxdb/model_parser.go @@ -12,7 +12,6 @@ type InfluxdbQueryParser struct{} func (qp *InfluxdbQueryParser) Parse(model *simplejson.Json, dsInfo *tsdb.DataSourceInfo) (*Query, error) { policy := model.Get("policy").MustString("default") rawQuery := model.Get("query").MustString("") - interval := model.Get("interval").MustString("") alias := model.Get("alias").MustString("") measurement := model.Get("measurement").MustString("") @@ -37,7 +36,8 @@ func (qp *InfluxdbQueryParser) Parse(model *simplejson.Json, dsInfo *tsdb.DataSo return nil, err } - if interval == "" { + interval := model.Get("interval").MustString("") + if interval == "" && dsInfo.JsonData != nil { dsInterval := dsInfo.JsonData.Get("timeInterval").MustString("") if dsInterval != "" { interval = dsInterval diff --git a/pkg/tsdb/influxdb/query_builder.go b/pkg/tsdb/influxdb/query_builder.go index a4b122cbbd2..b783ff5c603 100644 --- a/pkg/tsdb/influxdb/query_builder.go +++ b/pkg/tsdb/influxdb/query_builder.go @@ -5,9 +5,15 @@ import ( "strconv" "strings" + "regexp" + "github.com/grafana/grafana/pkg/tsdb" ) +var ( + regexpOperatorPattern *regexp.Regexp = regexp.MustCompile(`^\/.*\/$`) +) + type QueryBuilder struct{} func (qb *QueryBuilder) Build(query *Query, queryContext *tsdb.QueryContext) (string, error) { @@ -43,18 +49,28 @@ func (qb *QueryBuilder) renderTags(query *Query) []string { str += " " } - value := tag.Value - nValue, err := strconv.ParseFloat(tag.Value, 64) - - if tag.Operator == "=~" || tag.Operator == "!~" { - value = fmt.Sprintf("%s", value) - } else if err == nil { - value = fmt.Sprintf("%v", nValue) - } else { - value = fmt.Sprintf("'%s'", value) + //If the operator is missing we fall back to sensible defaults + if tag.Operator == "" { + if regexpOperatorPattern.Match([]byte(tag.Value)) { + tag.Operator = "=~" + } else { + tag.Operator = "=" + } } - res = append(res, fmt.Sprintf(`%s"%s" %s %s`, str, tag.Key, tag.Operator, value)) + textValue := "" + numericValue, err := strconv.ParseFloat(tag.Value, 64) + + // quote value unless regex or number + if tag.Operator == "=~" || tag.Operator == "!~" { + textValue = tag.Value + } else if err == nil { + textValue = fmt.Sprintf("%v", numericValue) + } else { + textValue = fmt.Sprintf("'%s'", tag.Value) + } + + res = append(res, fmt.Sprintf(`%s"%s" %s %s`, str, tag.Key, tag.Operator, textValue)) } return res diff --git a/pkg/tsdb/influxdb/query_builder_test.go b/pkg/tsdb/influxdb/query_builder_test.go index d13fe3a3c6f..408db18e549 100644 --- a/pkg/tsdb/influxdb/query_builder_test.go +++ b/pkg/tsdb/influxdb/query_builder_test.go @@ -86,16 +86,34 @@ func TestInfluxdbQueryBuilder(t *testing.T) { So(rawQuery, ShouldEqual, `Raw query`) }) - Convey("can render regex tags", func() { - query := &Query{Tags: []*Tag{&Tag{Operator: "=~", Value: "value", Key: "key"}}} + Convey("can render normal tags without operator", func() { + query := &Query{Tags: []*Tag{&Tag{Operator: "", Value: `value`, Key: "key"}}} - So(strings.Join(builder.renderTags(query), ""), ShouldEqual, `"key" =~ value`) + So(strings.Join(builder.renderTags(query), ""), ShouldEqual, `"key" = 'value'`) + }) + + Convey("can render regex tags without operator", func() { + query := &Query{Tags: []*Tag{&Tag{Operator: "", Value: `/value/`, Key: "key"}}} + + So(strings.Join(builder.renderTags(query), ""), ShouldEqual, `"key" =~ /value/`) + }) + + Convey("can render regex tags", func() { + query := &Query{Tags: []*Tag{&Tag{Operator: "=~", Value: `/value/`, Key: "key"}}} + + So(strings.Join(builder.renderTags(query), ""), ShouldEqual, `"key" =~ /value/`) }) Convey("can render number tags", func() { - query := &Query{Tags: []*Tag{&Tag{Operator: "=", Value: "1", Key: "key"}}} + query := &Query{Tags: []*Tag{&Tag{Operator: "=", Value: "10001", Key: "key"}}} - So(strings.Join(builder.renderTags(query), ""), ShouldEqual, `"key" = 1`) + So(strings.Join(builder.renderTags(query), ""), ShouldEqual, `"key" = 10001`) + }) + + Convey("can render number tags with decimals", func() { + query := &Query{Tags: []*Tag{&Tag{Operator: "=", Value: "10001.1", Key: "key"}}} + + So(strings.Join(builder.renderTags(query), ""), ShouldEqual, `"key" = 10001.1`) }) Convey("can render string tags", func() { diff --git a/public/app/core/components/help/help.html b/public/app/core/components/help/help.html index 8482e9df7d1..3356f21d452 100644 --- a/public/app/core/components/help/help.html +++ b/public/app/core/components/help/help.html @@ -22,7 +22,7 @@
mod = - CTRL on windows, CMD key on Mac + CTRL on windows or linux and CMD key on Mac