Skip to content

Commit

Permalink
Merge remote-tracking branch 'grafana/master'
Browse files Browse the repository at this point in the history
* grafana/master:
  docs: refer to v5.3 instead of v5.2
  docs: stackdriver fixes after review
  stackdriver docs: metric query editor and annotations
  changelog: add notes about closing grafana#13616
  made it possible to have frontend code in symlinked folders that can add routes
  Added Loading state on org pages
  fix phantomjs render of graph panel when legend as table to the right
  changelog: add notes about closing grafana#13172
  add test for es alert when group by has no limit
  poc: frontend extensions
  remove tab
  bug fix
  Update time_series_query.go
  add admin page to show enterprise license status
  add gopkg.in/square/go-jose.v2 to dependencies, update github.com/hashicorp/yamux
  • Loading branch information
ryantxu committed Oct 11, 2018
2 parents 3213e23 + 90f6817 commit 1e9c744
Show file tree
Hide file tree
Showing 75 changed files with 12,120 additions and 214 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ profile.cov
/pkg/cmd/grafana-server/grafana-server
/pkg/cmd/grafana-server/debug
/pkg/extensions
/public/app/enterprise
debug.test
/examples/*/dist
/packaging/**/*.rpm
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,16 @@
### Minor

* **Datasource Proxy**: Keep trailing slash for datasource proxy requests [#13326](https://github.com/grafana/grafana/pull/13326), thx [@ryantxu](https://github.com/ryantxu)
* **Elasticsearch**: Fix no limit size in terms aggregation for alerting queries [#13172](https://github.com/grafana/grafana/issues/13172), thx [@Yukinoshita-Yukino](https://github.com/Yukinoshita-Yukino)

### Breaking changes

* Postgres/MySQL/MSSQL datasources now per default uses `max open connections` = `unlimited` (earlier 10), `max idle connections` = `2` (earlier 10) and `connection max lifetime` = `4` hours (earlier unlimited)

# 5.3.1 (unreleased)

* **Render**: Fix PhantomJS render of graph panel when legend displayed as table to the right [#13616](https://github.com/grafana/grafana/issues/13616)

# 5.3.0 (2018-10-10)

* **Stackdriver**: Filter wildcards and regex matching are not yet supported [#13495](https://github.com/grafana/grafana/issues/13495)
Expand Down
16 changes: 14 additions & 2 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Gopkg.toml
Original file line number Diff line number Diff line change
Expand Up @@ -207,3 +207,7 @@ ignored = [
[[constraint]]
name = "github.com/VividCortex/mysqlerr"
branch = "master"

[[constraint]]
name = "gopkg.in/square/go-jose.v2"
version = "2.1.9"
70 changes: 50 additions & 20 deletions docs/sources/features/datasources/stackdriver.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Grafana ships with built-in support for Google Stackdriver. Just add it as a dat
1. Open the side menu by clicking the Grafana icon in the top header.
2. In the side menu under the `Dashboards` link you should find a link named `Data Sources`.
3. Click the `+ Add data source` button in the top header.
4. Select `Stackdriver` from the *Type* dropdown.
4. Select `Stackdriver` from the _Type_ dropdown.
5. Upload or paste in the Service Account Key file. See below for steps on how to create a Service Account Key file.

> NOTE: If you're not seeing the `Data Sources` link in your side menu it means that your current user does not have the `Admin` role for the current organization.
Expand All @@ -43,44 +43,54 @@ To authenticate with the Stackdriver API, you need to create a Google Cloud Plat

The following APIs need to be enabled first:

- [Monitoring API](https://console.cloud.google.com/apis/library/monitoring.googleapis.com)
- [Cloud Resource Manager API](https://console.cloud.google.com/apis/library/cloudresourcemanager.googleapis.com)
* [Monitoring API](https://console.cloud.google.com/apis/library/monitoring.googleapis.com)
* [Cloud Resource Manager API](https://console.cloud.google.com/apis/library/cloudresourcemanager.googleapis.com)

Click on the links above and click the `Enable` button:

![Enable GCP APIs](/img/docs/v54/stackdriver_enable_api.png)
{{< docs-imagebox img="/img/docs/v53/stackdriver_enable_api.png" class="docs-image--no-shadow" caption="Enable GCP APIs" >}}

#### Create a GCP Service Account for a Project

1. Navigate to the [APIs & Services Credentials page](https://console.cloud.google.com/apis/credentials).
2. Click on the `Create credentials` dropdown/button and choose the `Service account key` option.

![Create service account button](/img/docs/v54/stackdriver_create_service_account_button.png)
{{< docs-imagebox img="/img/docs/v53/stackdriver_create_service_account_button.png" class="docs-image--no-shadow" caption="Create service account button" >}}

3. On the `Create service account key` page, choose key type `JSON`. Then in the `Service Account` dropdown, choose the `New service account` option:

![Create service account key](/img/docs/v54/stackdriver_create_service_account_key.png)
{{< docs-imagebox img="/img/docs/v53/stackdriver_create_service_account_key.png" class="docs-image--no-shadow" caption="Create service account key" >}}

4. Some new fields will appear. Fill in a name for the service account in the `Service account name` field and then choose the `Monitoring Viewer` role from the `Role` dropdown:

![Choose role](/img/docs/v54/stackdriver_service_account_choose_role.png)
{{< docs-imagebox img="/img/docs/v53/stackdriver_service_account_choose_role.png" class="docs-image--no-shadow" caption="Choose role" >}}

5. Click the Create button. A JSON key file will be created and downloaded to your computer. Store this file in a secure place as it allows access to your Stackdriver data.
6. Upload it to Grafana on the datasource Configuration page. You can either upload the file or paste in the contents of the file.

![Choose role](/img/docs/v54/stackdriver_grafana_upload_key.png)

{{< docs-imagebox img="/img/docs/v53/stackdriver_grafana_upload_key.png" class="docs-image--no-shadow" caption="Upload service key file to Grafana" >}}

7. The file contents will be encrypted and saved in the Grafana database. Don't forget to save after uploading the file!
![Choose role](/img/docs/v54/stackdriver_grafana_key_uploaded.png)

{{< docs-imagebox img="/img/docs/v53/stackdriver_grafana_key_uploaded.png" class="docs-image--no-shadow" caption="Service key file is uploaded to Grafana" >}}

## Metric Query Editor

Choose a metric from the `Metric` dropdown.
{{< docs-imagebox img="/img/docs/v53/stackdriver_query_editor.png" max-width= "400px" class="docs-image--right" >}}

The Stackdriver query editor allows you to select metrics, group/aggregate by labels and by time, and use filters to specify which time series you want in the results.

Begin by choosing a `Service` and then a metric from the `Metric` dropdown. Use the plus and minus icons in the filter and group by sections to add/remove filters or group by clauses.

Stackdriver metrics can be of different kinds (GAUGE, DELTA, CUMULATIVE) and these kinds have support for different aggregation options (reducers and aligners). The Grafana query editor shows the list of available aggregation methods for a selected metric and sets a default reducer and aligner when you select the metric. Units for the Y-axis are also automatically selected by the query editor.

### Filter

To add a filter, click the plus icon and choose a field to filter by and enter a filter value e.g. `instance_name = grafana-1`. You can remove the filter by clicking on the filter name and select `--remove filter--`.

#### Simple wildcards

When the operator is set to `=` or `!=` it is possible to add wildcards to the filter value field. E.g `us-*` will capture all values that starts with "us-" and `*central-a` will capture all values that ends with "central-a". `*-central-*` captures all values that has the substring of -central-. Simple wildcards are less expensive than regular expressions.
When the operator is set to `=` or `!=` it is possible to add wildcards to the filter value field. E.g `us-*` will capture all values that starts with "us-" and `*central-a` will capture all values that ends with "central-a". `*-central-*` captures all values that has the substring of -central-. Simple wildcards are less expensive than regular expressions.

#### Regular expressions

Expand All @@ -97,9 +107,9 @@ The `Aligner` field allows you to align multiple time series after the same grou
The `Alignment Period` groups a metric by time if an aggregation is chosen. The default is to use the GCP Stackdriver default groupings (which allows you to compare graphs in Grafana with graphs in the Stackdriver UI).
The option is called `Stackdriver auto` and the defaults are:

- 1m for time ranges < 23 hours
- 5m for time ranges >= 23 hours and < 6 days
- 1h for time ranges >= 6 days
* 1m for time ranges < 23 hours
* 5m for time ranges >= 23 hours and < 6 days
* 1h for time ranges >= 6 days

The other automatic option is `Grafana auto`. This will automatically set the group by time depending on the time range chosen and the width of the graph panel. Read more about the details [here](http://docs.grafana.org/reference/templating/#the-interval-variable).

Expand Down Expand Up @@ -151,15 +161,34 @@ Writing variable queries is not supported yet.

There are two syntaxes:

- `$<varname>` Example: rate(http_requests_total{job=~"$job"}[5m])
- `[[varname]]` Example: rate(http_requests_total{job=~"[[job]]"}[5m])
* `$<varname>` Example: `metric.label.$metric_label`
* `[[varname]]` Example: `metric.label.[[metric_label]]`

Why two ways? The first syntax is easier to read and write but does not allow you to use a variable in the middle of a word. When the *Multi-value* or *Include all value* options are enabled, Grafana converts the labels from plain text to a regex compatible string, which means you have to use `=~` instead of `=`.
Why two ways? The first syntax is easier to read and write but does not allow you to use a variable in the middle of a word. When the _Multi-value_ or _Include all value_ options are enabled, Grafana converts the labels from plain text to a regex compatible string, which means you have to use `=~` instead of `=`.

## Annotations

{{< docs-imagebox img="/img/docs/v53/stackdriver_annotations_query_editor.png" max-width= "400px" class="docs-image--right" >}}

[Annotations]({{< relref "reference/annotations.md" >}}) allows you to overlay rich event information on top of graphs. You add annotation
queries via the Dashboard menu / Annotations view.
queries via the Dashboard menu / Annotations view. Annotation rendering is expensive so it is important to limit the number of rows returned. There is no support for showing Stackdriver annotations and events yet but it works well with [custom metrics](https://cloud.google.com/monitoring/custom-metrics/) in Stackdriver.

With the query editor for annotations, you can select a metric and filters. The `Title` and `Text` fields support templating and can use data returned from the query. For example, the Title field could have the following text:

`{{metric.type}} has value: {{metric.value}}`

Example Result: `monitoring.googleapis.com/uptime_check/http_status has this value: 502`

### Patterns for the Annotation Query Editor

| Alias Pattern Format | Description | Alias Pattern Example | Example Result |
| ------------------------ | -------------------------------- | -------------------------------- | ------------------------------------------------- |
| `{{metric.value}}` | value of the metric/point | `{{metric.value}}` | `555` |
| `{{metric.type}}` | returns the full Metric Type | `{{metric.type}}` | `compute.googleapis.com/instance/cpu/utilization` |
| `{{metric.name}}` | returns the metric name part | `{{metric.name}}` | `instance/cpu/utilization` |
| `{{metric.service}}` | returns the service part | `{{metric.service}}` | `compute` |
| `{{metric.label.xxx}}` | returns the metric label value | `{{metric.label.instance_name}}` | `grafana-1-prod` |
| `{{resource.label.xxx}}` | returns the resource label value | `{{resource.label.zone}}` | `us-east1-b` |

## Configure the Datasource with Provisioning

Expand All @@ -173,6 +202,7 @@ apiVersion: 1
datasources:
- name: Stackdriver
type: stackdriver
access: proxy
jsonData:
tokenUri: https://oauth2.googleapis.com/token
clientEmail: stackdriver@myproject.iam.gserviceaccount.com
Expand Down
26 changes: 17 additions & 9 deletions docs/sources/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ aliases = ["v1.1", "guides/reference/admin"]
<h4>Provisioning</h4>
<p>A guide to help you automate your Grafana setup & configuration.</p>
</a>
<a href="{{< relref "guides/whats-new-in-v5-2.md" >}}" class="nav-cards__item nav-cards__item--guide">
<h4>What's new in v5.2</h4>
<p>Article on all the new cool features and enhancements in v5.2</p>
<a href="{{< relref "guides/whats-new-in-v5-3.md" >}}" class="nav-cards__item nav-cards__item--guide">
<h4>What's new in v5.3</h4>
<p>Article on all the new cool features and enhancements in v5.3</p>
</a>
<a href="{{< relref "tutorials/screencasts.md" >}}" class="nav-cards__item nav-cards__item--guide">
<h4>Screencasts</h4>
Expand All @@ -88,9 +88,13 @@ aliases = ["v1.1", "guides/reference/admin"]
<img src="/img/docs/logos/icon_prometheus.svg" >
<h5>Prometheus</h5>
</a>
<a href="{{< relref "features/datasources/opentsdb.md" >}}" class="nav-cards__item nav-cards__item--ds">
<img src="/img/docs/logos/icon_opentsdb.png" >
<h5>OpenTSDB</h5>
<a href="{{< relref "features/datasources/stackdriver.md" >}}" class="nav-cards__item nav-cards__item--ds">
<img src="/img/docs/logos/stackdriver_logo.png">
<h5>Google Stackdriver</h5>
</a>
<a href="{{< relref "features/datasources/cloudwatch.md" >}}" class="nav-cards__item nav-cards__item--ds">
<img src="/img/docs/logos/icon_cloudwatch.svg">
<h5>Cloudwatch</h5>
</a>
<a href="{{< relref "features/datasources/mysql.md" >}}" class="nav-cards__item nav-cards__item--ds">
<img src="/img/docs/logos/icon_mysql.png" >
Expand All @@ -100,8 +104,12 @@ aliases = ["v1.1", "guides/reference/admin"]
<img src="/img/docs/logos/icon_postgres.svg" >
<h5>Postgres</h5>
</a>
<a href="{{< relref "features/datasources/cloudwatch.md" >}}" class="nav-cards__item nav-cards__item--ds">
<img src="/img/docs/logos/icon_cloudwatch.svg">
<h5>Cloudwatch</h5>
<a href="{{< relref "features/datasources/mssql.md" >}}" class="nav-cards__item nav-cards__item--ds">
<img src="/img/docs/logos/sql_server_logo.svg">
<h5>Microsoft SQL Server</h5>
</a>
<a href="{{< relref "features/datasources/opentsdb.md" >}}" class="nav-cards__item nav-cards__item--ds">
<img src="/img/docs/logos/icon_opentsdb.png" >
<h5>OpenTSDB</h5>
</a>
</div>
8 changes: 4 additions & 4 deletions pkg/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import (
)

func (hs *HTTPServer) registerRoutes() {
reqSignedIn := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true})
reqGrafanaAdmin := middleware.Auth(&middleware.AuthOptions{ReqSignedIn: true, ReqGrafanaAdmin: true})
reqEditorRole := middleware.RoleAuth(m.ROLE_EDITOR, m.ROLE_ADMIN)
reqOrgAdmin := middleware.RoleAuth(m.ROLE_ADMIN)
reqSignedIn := middleware.ReqSignedIn
reqGrafanaAdmin := middleware.ReqGrafanaAdmin
reqEditorRole := middleware.ReqEditorRole
reqOrgAdmin := middleware.ReqOrgAdmin
redirectFromLegacyDashboardURL := middleware.RedirectFromLegacyDashboardURL()
redirectFromLegacyDashboardSoloURL := middleware.RedirectFromLegacyDashboardSoloURL()
quota := middleware.Quota
Expand Down
21 changes: 14 additions & 7 deletions pkg/api/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,20 +316,27 @@ func setIndexViewData(c *m.ReqContext) (*dtos.IndexViewData, error) {
}

if c.IsGrafanaAdmin {
children := []*dtos.NavLink{
{Text: "Users", Id: "global-users", Url: setting.AppSubUrl + "/admin/users", Icon: "gicon gicon-user"},
{Text: "Orgs", Id: "global-orgs", Url: setting.AppSubUrl + "/admin/orgs", Icon: "gicon gicon-org"},
{Text: "Settings", Id: "server-settings", Url: setting.AppSubUrl + "/admin/settings", Icon: "gicon gicon-preferences"},
{Text: "Stats", Id: "server-stats", Url: setting.AppSubUrl + "/admin/stats", Icon: "fa fa-fw fa-bar-chart"},
}

if setting.IsEnterprise {
children = append(children, &dtos.NavLink{Text: "Licensing", Id: "licensing", Url: setting.AppSubUrl + "/admin/licensing", Icon: "fa fa-fw fa-unlock-alt"})
}

children = append(children, &dtos.NavLink{Text: "Style Guide", Id: "styleguide", Url: setting.AppSubUrl + "/styleguide", Icon: "fa fa-fw fa-eyedropper"})

cfgNode.Children = append(cfgNode.Children, &dtos.NavLink{
Text: "Server Admin",
HideFromTabs: true,
SubTitle: "Manage all users & orgs",
Id: "admin",
Icon: "gicon gicon-shield",
Url: setting.AppSubUrl + "/admin/users",
Children: []*dtos.NavLink{
{Text: "Users", Id: "global-users", Url: setting.AppSubUrl + "/admin/users", Icon: "gicon gicon-user"},
{Text: "Orgs", Id: "global-orgs", Url: setting.AppSubUrl + "/admin/orgs", Icon: "gicon gicon-org"},
{Text: "Settings", Id: "server-settings", Url: setting.AppSubUrl + "/admin/settings", Icon: "gicon gicon-preferences"},
{Text: "Stats", Id: "server-stats", Url: setting.AppSubUrl + "/admin/stats", Icon: "fa fa-fw fa-bar-chart"},
{Text: "Style Guide", Id: "styleguide", Url: setting.AppSubUrl + "/styleguide", Icon: "fa fa-fw fa-eyedropper"},
},
Children: children,
})
}

Expand Down
4 changes: 4 additions & 0 deletions pkg/extensions/main.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
package extensions

import (
_ "gopkg.in/square/go-jose.v2"
)

var IsEnterprise bool = false
7 changes: 7 additions & 0 deletions pkg/middleware/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ import (
"github.com/grafana/grafana/pkg/util"
)

var (
ReqGrafanaAdmin = Auth(&AuthOptions{ReqSignedIn: true, ReqGrafanaAdmin: true})
ReqSignedIn = Auth(&AuthOptions{ReqSignedIn: true})
ReqEditorRole = RoleAuth(m.ROLE_EDITOR, m.ROLE_ADMIN)
ReqOrgAdmin = RoleAuth(m.ROLE_ADMIN)
)

func GetContextHandler() macaron.Handler {
return func(c *macaron.Context) {
ctx := &m.ReqContext{
Expand Down
4 changes: 4 additions & 0 deletions pkg/tsdb/elasticsearch/time_series_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,10 @@ func addTermsAgg(aggBuilder es.AggBuilder, bucketAgg *BucketAgg, metrics []*Metr
} else {
a.Size = 500
}
if a.Size == 0 {
a.Size = 500
}

if minDocCount, err := bucketAgg.Settings.Get("min_doc_count").Int(); err == nil {
a.MinDocCount = &minDocCount
}
Expand Down
6 changes: 4 additions & 2 deletions pkg/tsdb/elasticsearch/time_series_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func TestExecuteTimeSeriesQuery(t *testing.T) {
_, err := executeTsdbQuery(c, `{
"timeField": "@timestamp",
"bucketAggs": [
{ "type": "terms", "field": "@host", "id": "2" },
{ "type": "terms", "field": "@host", "id": "2", "settings": { "size": "0", "order": "asc" } },
{ "type": "date_histogram", "field": "@timestamp", "id": "3" }
],
"metrics": [{"type": "count", "id": "1" }]
Expand All @@ -69,7 +69,9 @@ func TestExecuteTimeSeriesQuery(t *testing.T) {
sr := c.multisearchRequests[0].Requests[0]
firstLevel := sr.Aggs[0]
So(firstLevel.Key, ShouldEqual, "2")
So(firstLevel.Aggregation.Aggregation.(*es.TermsAggregation).Field, ShouldEqual, "@host")
termsAgg := firstLevel.Aggregation.Aggregation.(*es.TermsAggregation)
So(termsAgg.Field, ShouldEqual, "@host")
So(termsAgg.Size, ShouldEqual, 500)
secondLevel := firstLevel.Aggregation.Aggs[0]
So(secondLevel.Key, ShouldEqual, "3")
So(secondLevel.Aggregation.Aggregation.(*es.DateHistogramAgg).Field, ShouldEqual, "@timestamp")
Expand Down
6 changes: 6 additions & 0 deletions public/app/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ _.move = (array, fromIndex, toIndex) => {
import { coreModule, registerAngularDirectives } from './core/core';
import { setupAngularRoutes } from './routes/routes';

// import enterprise frontend
const enterpriseIndex = (require as any).context('.', true, /enterprise\/index.ts/);
enterpriseIndex.keys().forEach(key => {
enterpriseIndex(key);
});

declare var System: any;

export class GrafanaApp {
Expand Down
Loading

0 comments on commit 1e9c744

Please sign in to comment.