Merge remote-tracking branch 'origin/master' into develop

This commit is contained in:
Torkel Ödegaard
2018-12-14 17:02:08 +01:00
34 changed files with 8101 additions and 545 deletions

View File

@@ -6,27 +6,35 @@
### Minor
* **Elasticsearch**: Add support for offset in date histogram aggregation [#12653](https://github.com/grafana/grafana/issues/12653), thx [@mattiarossi](https://github.com/mattiarossi)
* **Elasticsearch**: Add support for moving average and derivative using doc count (metric count) [#8843](https://github.com/grafana/grafana/issues/8843) [#11175](https://github.com/grafana/grafana/issues/11175)
* **Auth**: Prevent password reset when login form is disabled or either LDAP or Auth Proxy is enabled [#14246](https://github.com/grafana/grafana/issues/14246), thx [@SilverFire](https://github.com/SilverFire)
* **Dataproxy**: Override incoming Authorization header [#13815](https://github.com/grafana/grafana/issues/13815), thx [@kornholi](https://github.com/kornholi)
* **Admin**: Fix prevent removing last grafana admin permissions [#11067](https://github.com/grafana/grafana/issues/11067), thx [@danielbh](https://github.com/danielbh)
* **Templating**: Escaping "Custom" template variables [#13754](https://github.com/grafana/grafana/issues/13754), thx [@IntegersOfK](https://github.com/IntegersOfK)
# 5.4.2 (2018-12-13)
* **Datasource admin**: Fix for issue creating new data source when same name exists [#14467](https://github.com/grafana/grafana/issues/14467)
* **OAuth**: Fix for oauth auto login setting, can now be set using env variable [#14435](https://github.com/grafana/grafana/issues/14435)
* **Dashboard search**: Fix for searching tags in tags filter dropdown.
# 5.4.1 (2018-12-10)
* **Stackdriver**: Fixes issue with data proxy and Authorization header [#14262](https://github.com/grafana/grafana/issues/14262)
* **Units**: fixedUnit for Flow:l/min and mL/min [#14294](https://github.com/grafana/grafana/issues/14294), thx [@flopp999](https://github.com/flopp999).
* **Units**: fixedUnit for Flow:l/min and mL/min [#14294](https://github.com/grafana/grafana/issues/14294), thx [@flopp999](https://github.com/flopp999).
* **Logging**: Fix for issue where data proxy logged a secret when debug logging was enabled, now redacted. [#14319](https://github.com/grafana/grafana/issues/14319)
* **InfluxDB**: Add support for alerting on InfluxDB queries that use the cumulative_sum function. [#14314](https://github.com/grafana/grafana/pull/14314), thx [@nitti](https://github.com/nitti)
* **Plugins**: Panel plugins should no receive the panel-initialized event again as usual.
* **Plugins**: Panel plugins should no receive the panel-initialized event again as usual.
* **Embedded Graphs**: Iframe graph panels should now work as usual. [#14284](https://github.com/grafana/grafana/issues/14284)
* **Postgres**: Improve PostgreSQL Query Editor if using different Schemas, [#14313](
https://github.com/grafana/grafana/pull/14313)
* **Quotas**: Fixed for updating org & user quotas. [#14347](https://github.com/grafana/grafana/pull/14347), thx [#moznion](https://github.com/moznion)
* **Cloudwatch**: Add the AWS/SES Cloudwatch metrics of BounceRate and ComplaintRate to auto complete list. [#14401](https://github.com/grafana/grafana/pull/14401), thx [@sglajchEG](https://github.com/sglajchEG)
* **Dashboard Search**: Fixed filtering by tag issues.
* **Dashboard Search**: Fixed filtering by tag issues.
* **Graph**: Fixed time region issues, [#14425](https://github.com/grafana/grafana/issues/14425), [#14280](https://github.com/grafana/grafana/issues/14280)
* **Graph**: Fixed issue with series color picker popover being placed outside window.
* **Graph**: Fixed issue with series color picker popover being placed outside window.
# 5.4.0 (2018-12-03)

View File

@@ -246,6 +246,10 @@ disable_signout_menu = false
# URL to redirect the user to after sign out
signout_redirect_url =
# Set to true to attempt login with OAuth automatically, skipping the login screen.
# This setting is ignored if multiple OAuth providers are configured.
oauth_auto_login = false
#################################### Anonymous Auth ######################
[auth.anonymous]
# enable anonymous access

View File

@@ -226,6 +226,10 @@ log_queries =
# URL to redirect the user to after sign out
;signout_redirect_url =
# Set to true to attempt login with OAuth automatically, skipping the login screen.
# This setting is ignored if multiple OAuth providers are configured.
;oauth_auto_login = false
#################################### Anonymous Auth ##########################
[auth.anonymous]
# enable anonymous access

View File

@@ -35,7 +35,7 @@ datasources:
tsdbResolution: 1
tsdbVersion: 1
- name: gdev-elasticsearch-metrics
- name: gdev-elasticsearch-v2-metrics
type: elasticsearch
access: proxy
database: "[metrics-]YYYY.MM.DD"
@@ -43,6 +43,57 @@ datasources:
jsonData:
interval: Daily
timeField: "@timestamp"
esVersion: 2
- name: gdev-elasticsearch-v2-logs
type: elasticsearch
access: proxy
database: "[logs-]YYYY.MM.DD"
url: http://localhost:9200
jsonData:
interval: Daily
timeField: "@timestamp"
esVersion: 2
- name: gdev-elasticsearch-v5-metrics
type: elasticsearch
access: proxy
database: "[metrics-]YYYY.MM.DD"
url: http://localhost:10200
jsonData:
interval: Daily
timeField: "@timestamp"
esVersion: 5
- name: gdev-elasticsearch-v5-logs
type: elasticsearch
access: proxy
database: "[logs-]YYYY.MM.DD"
url: http://localhost:10200
jsonData:
interval: Daily
timeField: "@timestamp"
esVersion: 5
- name: gdev-elasticsearch-v6-metrics
type: elasticsearch
access: proxy
database: "[metrics-]YYYY.MM.DD"
url: http://localhost:11200
jsonData:
interval: Daily
timeField: "@timestamp"
esVersion: 60
- name: gdev-elasticsearch-v6-logs
type: elasticsearch
access: proxy
database: "[logs-]YYYY.MM.DD"
url: http://localhost:11200
jsonData:
interval: Daily
timeField: "@timestamp"
esVersion: 60
- name: gdev-mysql
type: mysql

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,649 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": false,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"limit": 100,
"name": "Annotations & Alerts",
"showIn": 0,
"type": "dashboard"
},
{
"datasource": "Elastic 5 Logs",
"enable": false,
"iconColor": "rgba(255, 96, 96, 1)",
"limit": 100,
"name": "test",
"query": "",
"showIn": 0,
"textField": "description",
"type": "alert"
}
]
},
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"iteration": 1542303970887,
"links": [
{
"icon": "external link",
"tags": [
"gdev",
"elasticsearch"
],
"type": "dashboards"
}
],
"panels": [
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "gdev-elasticsearch-v2-metrics",
"editable": true,
"error": false,
"fill": 1,
"grid": {},
"gridPos": {
"h": 7,
"w": 24,
"x": 0,
"y": 0
},
"id": 1,
"legend": {
"alignAsTable": true,
"avg": false,
"current": false,
"max": true,
"min": false,
"rightSide": true,
"show": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 2,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"bucketAggs": [
{
"field": "@hostname",
"id": "3",
"settings": {
"min_doc_count": 1,
"order": "asc",
"orderBy": "1",
"size": "5"
},
"type": "terms"
},
{
"field": "@timestamp",
"id": "2",
"settings": {
"interval": "auto",
"min_doc_count": 0,
"trimEdges": 0
},
"type": "date_histogram"
}
],
"dsType": "elasticsearch",
"metrics": [
{
"field": "@value",
"id": "1",
"meta": {},
"settings": {},
"type": "max"
}
],
"query": "*",
"refId": "A",
"target": "",
"timeField": "@timestamp"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Top 5 servers",
"tooltip": {
"msResolution": true,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"aliasColors": {
"Count": "#6ED0E0"
},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "gdev-elasticsearch-v2-metrics",
"editable": true,
"error": false,
"fill": 1,
"grid": {},
"gridPos": {
"h": 6,
"w": 12,
"x": 0,
"y": 7
},
"id": 2,
"legend": {
"alignAsTable": true,
"avg": true,
"current": false,
"max": false,
"min": false,
"rightSide": true,
"show": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 2,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [
{
"alias": "Count",
"lines": false,
"yaxis": 2,
"zindex": -1
}
],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"alias": "{{metric}}",
"bucketAggs": [
{
"field": "@timestamp",
"id": "2",
"settings": {
"interval": "5m",
"min_doc_count": 0,
"trimEdges": 0
},
"type": "date_histogram"
}
],
"dsType": "elasticsearch",
"metrics": [
{
"field": "@value",
"id": "1",
"meta": {},
"settings": {
"percents": [
25,
50,
75,
95,
99
]
},
"type": "percentiles"
}
],
"query": "@metric:cpu",
"refId": "A",
"target": "",
"timeField": "@timestamp"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Percentiles & Metric filter",
"tooltip": {
"msResolution": false,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"aliasColors": {
"Count": "#6ED0E0"
},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "gdev-elasticsearch-v2-metrics",
"editable": true,
"error": false,
"fill": 1,
"grid": {},
"gridPos": {
"h": 6,
"w": 12,
"x": 12,
"y": 7
},
"id": 3,
"legend": {
"alignAsTable": true,
"avg": true,
"current": false,
"max": false,
"min": false,
"rightSide": true,
"show": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 2,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [
{
"alias": "Count",
"lines": false,
"yaxis": 2,
"zindex": -1
}
],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"alias": "{{metric}}",
"bucketAggs": [
{
"field": "@timestamp",
"id": "2",
"settings": {
"interval": "auto",
"min_doc_count": 0,
"trimEdges": 0
},
"type": "date_histogram"
}
],
"dsType": "elasticsearch",
"metrics": [
{
"field": "@value",
"id": "1",
"meta": {
"std_deviation_bounds_lower": true,
"std_deviation_bounds_upper": true
},
"settings": {},
"type": "extended_stats"
}
],
"query": "@metric:cpu",
"refId": "A",
"target": "",
"timeField": "@timestamp"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Standard dev",
"tooltip": {
"msResolution": true,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"columns": [
{
"text": "@hostname",
"value": "@hostname"
},
{
"text": "Average",
"value": "Average"
},
{
"text": "Max",
"value": "Max"
},
{
"text": "Sum",
"value": "Sum"
}
],
"datasource": "gdev-elasticsearch-v2-metrics",
"editable": true,
"error": false,
"fontSize": "100%",
"gridPos": {
"h": 7,
"w": 24,
"x": 0,
"y": 13
},
"id": 6,
"links": [],
"pageSize": null,
"scroll": true,
"showHeader": true,
"sort": {
"col": 0,
"desc": true
},
"styles": [
{
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"pattern": "@timestamp",
"type": "date"
},
{
"colorMode": null,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 2,
"pattern": "/.*/",
"thresholds": [],
"type": "number",
"unit": "short"
}
],
"targets": [
{
"bucketAggs": [
{
"field": "@hostname",
"id": "2",
"settings": {
"min_doc_count": 1,
"order": "asc",
"orderBy": "_term",
"size": "0"
},
"type": "terms"
}
],
"dsType": "elasticsearch",
"metrics": [
{
"field": "@value",
"id": "1",
"meta": {},
"settings": {},
"type": "avg"
},
{
"field": "@value",
"id": "3",
"meta": {},
"settings": {},
"type": "max"
},
{
"field": "@value",
"id": "4",
"meta": {},
"settings": {},
"type": "sum"
}
],
"refId": "B",
"timeField": "@timestamp"
}
],
"title": "ES Metrics",
"transform": "table",
"type": "table"
},
{
"columns": [
{
"text": "@timestamp",
"value": "@timestamp"
},
{
"text": "@message",
"value": "@message"
},
{
"text": "tags",
"value": "tags"
},
{
"text": "description",
"value": "description"
}
],
"datasource": "gdev-elasticsearch-v2-logs",
"editable": true,
"error": false,
"fontSize": "100%",
"gridPos": {
"h": 7,
"w": 24,
"x": 0,
"y": 20
},
"id": 5,
"links": [],
"pageSize": null,
"scroll": true,
"showHeader": true,
"sort": {
"col": 0,
"desc": true
},
"styles": [
{
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"pattern": "@timestamp",
"type": "date"
}
],
"targets": [
{
"bucketAggs": [],
"dsType": "elasticsearch",
"metrics": [
{
"field": "select field",
"id": "1",
"meta": {},
"settings": {
"size": 500
},
"type": "raw_document"
}
],
"refId": "A",
"target": "",
"timeField": "@timestamp"
}
],
"title": "ES Log query",
"transform": "json",
"type": "table"
}
],
"schemaVersion": 16,
"style": "dark",
"tags": [
"elasticsearch",
"gdev"
],
"templating": {
"list": [
{
"datasource": "gdev-elasticsearch-v2-metrics",
"filters": [],
"hide": 0,
"label": "",
"name": "Filters",
"skipUrlSync": false,
"type": "adhoc"
}
]
},
"time": {
"from": "now-30m",
"to": "now"
},
"timepicker": {
"collapse": false,
"enable": true,
"notice": false,
"now": true,
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"status": "Stable",
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
],
"type": "timepicker"
},
"timezone": "browser",
"title": "Datasource tests - Elasticsearch v2",
"uid": "RlqLq2fiz",
"version": 2
}

View File

@@ -0,0 +1,651 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": false,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"limit": 100,
"name": "Annotations & Alerts",
"showIn": 0,
"type": "dashboard"
},
{
"datasource": "Elastic 5 Logs",
"enable": false,
"iconColor": "rgba(255, 96, 96, 1)",
"limit": 100,
"name": "test",
"query": "",
"showIn": 0,
"textField": "description",
"type": "alert"
}
]
},
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"iteration": 1542303896062,
"links": [
{
"asDropdown": false,
"icon": "external link",
"tags": [
"gdev",
"elasticsearch"
],
"title": "Dashboard",
"type": "dashboards"
}
],
"panels": [
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "gdev-elasticsearch-v5-metrics",
"editable": true,
"error": false,
"fill": 1,
"grid": {},
"gridPos": {
"h": 7,
"w": 24,
"x": 0,
"y": 0
},
"id": 1,
"legend": {
"alignAsTable": true,
"avg": false,
"current": false,
"max": true,
"min": false,
"rightSide": true,
"show": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 2,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"bucketAggs": [
{
"field": "@hostname",
"id": "3",
"settings": {
"min_doc_count": 1,
"order": "asc",
"orderBy": "1",
"size": "5"
},
"type": "terms"
},
{
"field": "@timestamp",
"id": "2",
"settings": {
"interval": "auto",
"min_doc_count": 0,
"trimEdges": 0
},
"type": "date_histogram"
}
],
"dsType": "elasticsearch",
"metrics": [
{
"field": "@value",
"id": "1",
"meta": {},
"settings": {},
"type": "max"
}
],
"query": "*",
"refId": "A",
"target": "",
"timeField": "@timestamp"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Top 5 servers",
"tooltip": {
"msResolution": true,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"aliasColors": {
"Count": "#6ED0E0"
},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "gdev-elasticsearch-v5-metrics",
"editable": true,
"error": false,
"fill": 1,
"grid": {},
"gridPos": {
"h": 6,
"w": 12,
"x": 0,
"y": 7
},
"id": 2,
"legend": {
"alignAsTable": true,
"avg": true,
"current": false,
"max": false,
"min": false,
"rightSide": true,
"show": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 2,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [
{
"alias": "Count",
"lines": false,
"yaxis": 2,
"zindex": -1
}
],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"alias": "{{metric}}",
"bucketAggs": [
{
"field": "@timestamp",
"id": "2",
"settings": {
"interval": "5m",
"min_doc_count": 0,
"trimEdges": 0
},
"type": "date_histogram"
}
],
"dsType": "elasticsearch",
"metrics": [
{
"field": "@value",
"id": "1",
"meta": {},
"settings": {
"percents": [
25,
50,
75,
95,
99
]
},
"type": "percentiles"
}
],
"query": "@metric:cpu",
"refId": "A",
"target": "",
"timeField": "@timestamp"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Percentiles & Metric filter",
"tooltip": {
"msResolution": false,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"aliasColors": {
"Count": "#6ED0E0"
},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "gdev-elasticsearch-v5-metrics",
"editable": true,
"error": false,
"fill": 1,
"grid": {},
"gridPos": {
"h": 6,
"w": 12,
"x": 12,
"y": 7
},
"id": 3,
"legend": {
"alignAsTable": true,
"avg": true,
"current": false,
"max": false,
"min": false,
"rightSide": true,
"show": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 2,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [
{
"alias": "Count",
"lines": false,
"yaxis": 2,
"zindex": -1
}
],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"alias": "{{metric}}",
"bucketAggs": [
{
"field": "@timestamp",
"id": "2",
"settings": {
"interval": "auto",
"min_doc_count": 0,
"trimEdges": 0
},
"type": "date_histogram"
}
],
"dsType": "elasticsearch",
"metrics": [
{
"field": "@value",
"id": "1",
"meta": {
"std_deviation_bounds_lower": true,
"std_deviation_bounds_upper": true
},
"settings": {},
"type": "extended_stats"
}
],
"query": "@metric:cpu",
"refId": "A",
"target": "",
"timeField": "@timestamp"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Standard dev",
"tooltip": {
"msResolution": true,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"columns": [
{
"text": "@hostname",
"value": "@hostname"
},
{
"text": "Average",
"value": "Average"
},
{
"text": "Max",
"value": "Max"
},
{
"text": "Sum",
"value": "Sum"
}
],
"datasource": "gdev-elasticsearch-v5-metrics",
"editable": true,
"error": false,
"fontSize": "100%",
"gridPos": {
"h": 7,
"w": 24,
"x": 0,
"y": 13
},
"id": 6,
"links": [],
"pageSize": null,
"scroll": true,
"showHeader": true,
"sort": {
"col": 0,
"desc": true
},
"styles": [
{
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"pattern": "@timestamp",
"type": "date"
},
{
"colorMode": null,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 2,
"pattern": "/.*/",
"thresholds": [],
"type": "number",
"unit": "short"
}
],
"targets": [
{
"bucketAggs": [
{
"field": "@hostname",
"id": "2",
"settings": {
"min_doc_count": 1,
"order": "asc",
"orderBy": "_term",
"size": "0"
},
"type": "terms"
}
],
"dsType": "elasticsearch",
"metrics": [
{
"field": "@value",
"id": "1",
"meta": {},
"settings": {},
"type": "avg"
},
{
"field": "@value",
"id": "3",
"meta": {},
"settings": {},
"type": "max"
},
{
"field": "@value",
"id": "4",
"meta": {},
"settings": {},
"type": "sum"
}
],
"refId": "B",
"timeField": "@timestamp"
}
],
"title": "ES Metrics",
"transform": "table",
"type": "table"
},
{
"columns": [
{
"text": "@timestamp",
"value": "@timestamp"
},
{
"text": "@message",
"value": "@message"
},
{
"text": "tags",
"value": "tags"
},
{
"text": "description",
"value": "description"
}
],
"datasource": "gdev-elasticsearch-v5-logs",
"editable": true,
"error": false,
"fontSize": "100%",
"gridPos": {
"h": 7,
"w": 24,
"x": 0,
"y": 20
},
"id": 5,
"links": [],
"pageSize": null,
"scroll": true,
"showHeader": true,
"sort": {
"col": 0,
"desc": true
},
"styles": [
{
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"pattern": "@timestamp",
"type": "date"
}
],
"targets": [
{
"bucketAggs": [],
"dsType": "elasticsearch",
"metrics": [
{
"field": "select field",
"id": "1",
"meta": {},
"settings": {
"size": 500
},
"type": "raw_document"
}
],
"refId": "A",
"target": "",
"timeField": "@timestamp"
}
],
"title": "ES Log query",
"transform": "json",
"type": "table"
}
],
"schemaVersion": 16,
"style": "dark",
"tags": [
"elasticsearch",
"gdev"
],
"templating": {
"list": [
{
"datasource": "gdev-elasticsearch-v5-metrics",
"filters": [],
"hide": 0,
"label": "",
"name": "Filters",
"skipUrlSync": false,
"type": "adhoc"
}
]
},
"time": {
"from": "now-30m",
"to": "now"
},
"timepicker": {
"collapse": false,
"enable": true,
"notice": false,
"now": true,
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"status": "Stable",
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
],
"type": "timepicker"
},
"timezone": "browser",
"title": "Datasource tests - Elasticsearch v5",
"uid": "8HjT32Bmz",
"version": 27
}

View File

@@ -0,0 +1,649 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": false,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"limit": 100,
"name": "Annotations & Alerts",
"showIn": 0,
"type": "dashboard"
},
{
"datasource": "Elastic 5 Logs",
"enable": false,
"iconColor": "rgba(255, 96, 96, 1)",
"limit": 100,
"name": "test",
"query": "",
"showIn": 0,
"textField": "description",
"type": "alert"
}
]
},
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"iteration": 1542303999511,
"links": [
{
"icon": "external link",
"tags": [
"gdev",
"elasticsearch"
],
"type": "dashboards"
}
],
"panels": [
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "gdev-elasticsearch-v6-metrics",
"editable": true,
"error": false,
"fill": 1,
"grid": {},
"gridPos": {
"h": 7,
"w": 24,
"x": 0,
"y": 0
},
"id": 1,
"legend": {
"alignAsTable": true,
"avg": false,
"current": false,
"max": true,
"min": false,
"rightSide": true,
"show": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 2,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"bucketAggs": [
{
"field": "@hostname",
"id": "3",
"settings": {
"min_doc_count": 1,
"order": "asc",
"orderBy": "1",
"size": "5"
},
"type": "terms"
},
{
"field": "@timestamp",
"id": "2",
"settings": {
"interval": "auto",
"min_doc_count": 0,
"trimEdges": 0
},
"type": "date_histogram"
}
],
"dsType": "elasticsearch",
"metrics": [
{
"field": "@value",
"id": "1",
"meta": {},
"settings": {},
"type": "max"
}
],
"query": "*",
"refId": "A",
"target": "",
"timeField": "@timestamp"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Top 5 servers",
"tooltip": {
"msResolution": true,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"aliasColors": {
"Count": "#6ED0E0"
},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "gdev-elasticsearch-v6-metrics",
"editable": true,
"error": false,
"fill": 1,
"grid": {},
"gridPos": {
"h": 6,
"w": 12,
"x": 0,
"y": 7
},
"id": 2,
"legend": {
"alignAsTable": true,
"avg": true,
"current": false,
"max": false,
"min": false,
"rightSide": true,
"show": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 2,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [
{
"alias": "Count",
"lines": false,
"yaxis": 2,
"zindex": -1
}
],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"alias": "{{metric}}",
"bucketAggs": [
{
"field": "@timestamp",
"id": "2",
"settings": {
"interval": "5m",
"min_doc_count": 0,
"trimEdges": 0
},
"type": "date_histogram"
}
],
"dsType": "elasticsearch",
"metrics": [
{
"field": "@value",
"id": "1",
"meta": {},
"settings": {
"percents": [
25,
50,
75,
95,
99
]
},
"type": "percentiles"
}
],
"query": "@metric:cpu",
"refId": "A",
"target": "",
"timeField": "@timestamp"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Percentiles & Metric filter",
"tooltip": {
"msResolution": false,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"aliasColors": {
"Count": "#6ED0E0"
},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "gdev-elasticsearch-v6-metrics",
"editable": true,
"error": false,
"fill": 1,
"grid": {},
"gridPos": {
"h": 6,
"w": 12,
"x": 12,
"y": 7
},
"id": 3,
"legend": {
"alignAsTable": true,
"avg": true,
"current": false,
"max": false,
"min": false,
"rightSide": true,
"show": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 2,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [
{
"alias": "Count",
"lines": false,
"yaxis": 2,
"zindex": -1
}
],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"alias": "{{metric}}",
"bucketAggs": [
{
"field": "@timestamp",
"id": "2",
"settings": {
"interval": "auto",
"min_doc_count": 0,
"trimEdges": 0
},
"type": "date_histogram"
}
],
"dsType": "elasticsearch",
"metrics": [
{
"field": "@value",
"id": "1",
"meta": {
"std_deviation_bounds_lower": true,
"std_deviation_bounds_upper": true
},
"settings": {},
"type": "extended_stats"
}
],
"query": "@metric:cpu",
"refId": "A",
"target": "",
"timeField": "@timestamp"
}
],
"thresholds": [],
"timeFrom": null,
"timeRegions": [],
"timeShift": null,
"title": "Standard dev",
"tooltip": {
"msResolution": true,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": null
}
},
{
"columns": [
{
"text": "@hostname",
"value": "@hostname"
},
{
"text": "Average",
"value": "Average"
},
{
"text": "Max",
"value": "Max"
},
{
"text": "Sum",
"value": "Sum"
}
],
"datasource": "gdev-elasticsearch-v6-metrics",
"editable": true,
"error": false,
"fontSize": "100%",
"gridPos": {
"h": 7,
"w": 24,
"x": 0,
"y": 13
},
"id": 6,
"links": [],
"pageSize": null,
"scroll": true,
"showHeader": true,
"sort": {
"col": 0,
"desc": true
},
"styles": [
{
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"pattern": "@timestamp",
"type": "date"
},
{
"colorMode": null,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"decimals": 2,
"pattern": "/.*/",
"thresholds": [],
"type": "number",
"unit": "short"
}
],
"targets": [
{
"bucketAggs": [
{
"field": "@hostname",
"id": "2",
"settings": {
"min_doc_count": 1,
"order": "asc",
"orderBy": "_term",
"size": "0"
},
"type": "terms"
}
],
"dsType": "elasticsearch",
"metrics": [
{
"field": "@value",
"id": "1",
"meta": {},
"settings": {},
"type": "avg"
},
{
"field": "@value",
"id": "3",
"meta": {},
"settings": {},
"type": "max"
},
{
"field": "@value",
"id": "4",
"meta": {},
"settings": {},
"type": "sum"
}
],
"refId": "B",
"timeField": "@timestamp"
}
],
"title": "ES Metrics",
"transform": "table",
"type": "table"
},
{
"columns": [
{
"text": "@timestamp",
"value": "@timestamp"
},
{
"text": "@message",
"value": "@message"
},
{
"text": "tags",
"value": "tags"
},
{
"text": "description",
"value": "description"
}
],
"datasource": "gdev-elasticsearch-v6-logs",
"editable": true,
"error": false,
"fontSize": "100%",
"gridPos": {
"h": 7,
"w": 24,
"x": 0,
"y": 20
},
"id": 5,
"links": [],
"pageSize": null,
"scroll": true,
"showHeader": true,
"sort": {
"col": 0,
"desc": true
},
"styles": [
{
"dateFormat": "YYYY-MM-DD HH:mm:ss",
"pattern": "@timestamp",
"type": "date"
}
],
"targets": [
{
"bucketAggs": [],
"dsType": "elasticsearch",
"metrics": [
{
"field": "select field",
"id": "1",
"meta": {},
"settings": {
"size": 500
},
"type": "raw_document"
}
],
"refId": "A",
"target": "",
"timeField": "@timestamp"
}
],
"title": "ES Log query",
"transform": "json",
"type": "table"
}
],
"schemaVersion": 16,
"style": "dark",
"tags": [
"elasticsearch",
"gdev"
],
"templating": {
"list": [
{
"datasource": "gdev-elasticsearch-v6-metrics",
"filters": [],
"hide": 0,
"label": "",
"name": "Filters",
"skipUrlSync": false,
"type": "adhoc"
}
]
},
"time": {
"from": "now-30m",
"to": "now"
},
"timepicker": {
"collapse": false,
"enable": true,
"notice": false,
"now": true,
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"status": "Stable",
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
],
"type": "timepicker"
},
"timezone": "browser",
"title": "Datasource tests - Elasticsearch v6",
"uid": "NF8Pq2Biz",
"version": 2
}

View File

@@ -5,7 +5,7 @@
- "9200:9200"
- "9300:9300"
volumes:
- ./blocks/elastic/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
- ./docker/blocks/elastic/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
fake-elastic-data:
image: grafana/fake-data-gen

View File

@@ -1,15 +1,18 @@
# You need to run 'sysctl -w vm.max_map_count=262144' on the host machine
version: '2'
services:
elasticsearch5:
image: elasticsearch:5
command: elasticsearch
ports:
- "10200:9200"
- "10300:9300"
- '10200:9200'
- '10300:9300'
fake-elastic5-data:
image: grafana/fake-data-gen
network_mode: bridge
links:
- elasticsearch5
# network_mode: bridge
environment:
FD_DATASOURCE: elasticsearch
FD_PORT: 10200

View File

@@ -1,17 +1,19 @@
version: '2'
services:
influxdb:
image: influxdb:latest
container_name: influxdb
ports:
- "2004:2004"
- "8083:8083"
- "8086:8086"
- '2004:2004'
- '8083:8083'
- '8086:8086'
volumes:
- ./docker/blocks/influxdb/influxdb.conf:/etc/influxdb/influxdb.conf
fake-influxdb-data:
image: grafana/fake-data-gen
network_mode: bridge
links:
- influxdb
environment:
FD_DATASOURCE: influxdb
FD_PORT: 8086

View File

@@ -0,0 +1,162 @@
+++
title = "Explore"
type = "docs"
[menu.docs]
name = "Explore"
identifier = "explore"
parent = "features"
weight = 5
+++
# Introduction
One of the major new features of Grafana 6.0 is the new query-focused Explore workflow for troubleshooting and/or for data exploration.
Grafana's dashboard UI is all about building dashboards for visualization. Explore strips away all the dashboard and panel options so that you can focus on the query. Iterate until you have a working query and then think about building a dashboard.
For infrastructure monitoring and incident response, you no longer need to switch to other tools to debug what went wrong. Explore allows you to dig deeper into your metrics and logs to find the cause. Grafana's new logging datasource, [Loki](https://github.com/grafana/loki) is tightly integrated into Explore and allows you to correlate metrics and logs by viewing them side-by-side. This creates a new debugging workflow where you can:
1. Receive an alert
2. Drill down and examine metrics
3. Drill down again and search logs related to the metric and time interval (and in the future, distributed traces).
If you just want to explore your data and do not want to create a dashboard then Explore makes this much easier. Explore will show the results as both a graph and a table enabling you to see trends in the data and more detail at the same time (if the datasource supports both graph and table data).
## Turning the Explore Feature On
Explore will be officially released in Grafana 6.0. It is however already in the latest nightly builds of Grafana and can be turned using a feature flag in the config file. Restart Grafana after making the config file change.
```ini
[explore]
# Enable the Explore section
enabled = true
```
Or if using docker:
```bash
docker pull grafana/grafana:master
docker run --name grafana -p 3000:3000 -e "GF_EXPLORE_ENABLED=true" grafana/grafana:master
```
## How to Start Exploring
There is a new Explore icon on the menu bar to the left. This opens a new empty Explore tab.
{{< docs-imagebox img="/img/docs/v60/explore_menu.png" class="docs-image--no-shadow" caption="Screenshot of the new Explore Icon" >}}
If you want to start with an existing query in a panel then choose the Explore option from the Panel menu. This opens an Explore tab with the query from the panel and allows you to tweak or iterate in the query outside of your dashboard.
{{< docs-imagebox img="/img/docs/v60/explore_panel_menu.png" class="docs-image--no-shadow" caption="Screenshot of the new Explore option in the panel menu" >}}
Choose your datasource in the dropdown in the top left. Prometheus has a custom Explore implementation, the other datasources (for now) use their standard query editor.
The query field is where you can write your query and explore your data. There are three buttons beside the query field, a clear button (X), an add query button (+) and the remove query button (-). Just like the normal query editor, you can add and remove multiple queries.
## Split and Compare
The Split feature is an easy way to compare graphs and tables side-by-side or to look at related data together on one page. Click the split button to duplicate the current query and split the page into two side-by-side queries. It is possible to select another datasource for the new query which for example, allows you to compare the same query for two different servers or to compare the staging environment to the production environment.
{{< docs-imagebox img="/img/docs/v60/explore_split.png" class="docs-image--no-shadow" caption="Screenshot of the new Explore option in the panel menu" >}}
You can close the newly created query by clicking on the Close Split button.
## Prometheus-specific Features
The first version of Explore features a custom querying experience for Prometheus. When a query is executed, it actually executes two queries, a normal Prometheus query for the graph and an Instant Query for the table. An Instant Query returns the last value for each time series which shows a good summary of the data shown in the graph.
### Metrics Explorer
On the left-hand side of the query field is a `Metrics` button, clicking on this opens the Metric Explorer. This shows a hierarchical menu with metrics grouped by their prefix. For example, all the Alert Manager metrics will be grouped under the `alertmanager` prefix. This is a good starting point if you just want to explore which metrics are available.
{{< docs-imagebox img="/img/docs/v60/explore_metric_explorer.png" class="docs-image--no-shadow" caption="Screenshot of the new Explore option in the panel menu" >}}
### Query Field
The Query field supports autocomplete for metric names, function and works mostly the same way as the standard Prometheus query editor. Press the enter key to execute a query.
The autocomplete menu can be trigger by pressing Ctrl + Space. The Autocomplete menu contains a new History section with a list of recently executed queries.
Suggestions can appear under the query field - click on them to update your query with the suggested change.
- For counters (monotonously increasing metrics), a rate function will be suggested.
- For buckets, a histogram function will be suggested.
- For recording rules, possible to expand the rules.
### Table Filters
Click on the filter button <span title="Filter for label" class="logs-label__icon fa fa-search-plus"></span> in a labels column in the Table panel to add filters to the query expression. This works with multiple queries too - the filter will be added for all the queries.
## Logs Integration - Loki-specific Features
For Grafana 6.0, the first log integration is for the new open source log aggregation system from Grafana Labs - [Loki](https://github.com/grafana/loki). Loki is designed to be very cost effective, as it does not index the contents of the logs, but rather a set of labels for each log stream. The logs from Loki are queried in a similar way to querying with label selectors in Prometheus. It uses labels to group log streams which can be made to match up with your Prometheus labels. Read more about Grafana Loki [here](https://github.com/grafana/loki) or the Grafana Labs hosted variant: [Grafana Cloud Logs](https://grafana.com/loki).
### Switching from Metrics to Logs
If you switch from a Prometheus query to a logs query (you can do a split first to have your metrics and logs side by side) then it will keep the labels from your query that exist in the logs and use those to query the log streams. For example, the following Prometheus query:
`grafana_alerting_active_alerts{job="grafana"}`
after switching to the Logs datasource, the query changes to:
`{job="grafana"}`
This will return a chunk of logs in the selected time range that can be grepped/text searched.
### Log Queries
A log query consists of two parts: **log stream selector**, and a **search expression**. For performance reasons you need to start by choosing a log stream by selecting a log label.
The Logs Explorer (the `Log labels` button) next to the query field shows a list of labels of available log streams. An alternative way to write a query is to use the query field's autocomplete - you start by typing a left curly brace `{` and the autocomplete menu will suggest a list of labels. Press the `enter` key to execute the query.
Once the result is returned, the log panel shows a list of log rows and a bar chart where the x-axis shows the time and the y-axis shows the frequency/count.
{{< docs-imagebox img="/img/docs/v60/explore_loki.png" class="docs-image--no-shadow" caption="Explore Loki Log Streams" >}}
#### Log Stream Selector
For the label part of the query expression, wrap it in curly braces `{}` and then use the key value syntax for selecting labels. Multiple label expressions are separated by a comma:
`{app="mysql",name="mysql-backup"}`
The following label matching operators are currently supported:
- `=` exactly equal.
- `!=` not equal.
- `=~` regex-match.
- `!~` do not regex-match.
Examples:
- `{name=~"mysql.+"}`
- `{name!~"mysql.+"}`
The [same rules that apply for Prometheus Label Selectors](https://prometheus.io/docs/prometheus/latest/querying/basics/#instant-vector-selectors) apply for Loki Log Stream Selectors.
Another way to add a label selector, is in the table section, clicking on the **Filter** button beside a label will add the label to the query expression. This even works for multiple queries and will the label selector to each query.
#### Search Expression
After writing the Log Stream Selector, you can filter the results further by writing a search expression. The search expression can be just text or a regex expression.
Example queries:
- `{job="mysql"} error`
- `{name="kafka"} tsdb-ops.*io:2003`
- `{instance=~"kafka-[23]",name="kafka"} kafka.server:type=ReplicaManager`
### Deduping
Log data can be very repetitive and Explore can help by hiding duplicate log lines. There are a few different deduplication algorithms that you can use:
- `exact` Exact matches are done on the whole line, except for date fields.
- `numbers` Matches on the line after stripping out numbers (durations, IP addresses etc.).
- `signature` The most aggressive deduping - strips all letters and numbers, and matches on the remaining whitespace and punctuation.
### Timestamp, Local time and Labels
There are some other check boxes under the logging graph apart from the Deduping options.
- Timestamp: shows/hides the Timestamp column
- Local time: shows/hides the Local time column
- Labels: shows/hides the label filters column

View File

@@ -1,4 +1,4 @@
{
"stable": "5.4.0",
"testing": "5.4.0"
"stable": "5.4.2",
"testing": "5.4.2"
}

View File

@@ -333,12 +333,12 @@ func (fr *fileReader) resolvePath(path string) string {
copy := path
path, err := filepath.Abs(path)
if err != nil {
fr.log.Error("Could not create absolute path ", "path", path)
fr.log.Error("Could not create absolute path", "path", copy, "error", err)
}
path, err = filepath.EvalSymlinks(path)
if err != nil {
fr.log.Error("Failed to read content of symlinked path: %s", path)
fr.log.Error("Failed to read content of symlinked path", "path", copy, "error", err)
}
if path == "" {

View File

@@ -127,4 +127,7 @@ func addDataSourceMigration(mg *Migrator) {
mg.AddMigration("Add read_only data column", NewAddColumnMigration(tableV2, &Column{
Name: "read_only", Type: DB_Bool, Nullable: true,
}))
const migrateLoggingToLoki = `UPDATE data_source SET type = 'loki' WHERE type = 'logging'`
mg.AddMigration("Migrate logging ds to loki ds", NewRawSqlMigration(migrateLoggingToLoki))
}

View File

@@ -73,5 +73,8 @@ func isPipelineAgg(metricType string) bool {
func describeMetric(metricType, field string) string {
text := metricAggType[metricType]
if metricType == countType {
return text
}
return text + " " + field
}

View File

@@ -89,15 +89,29 @@ func (e *timeSeriesQuery) execute() (*tsdb.Response, error) {
}
for _, m := range q.Metrics {
if m.Type == "count" {
if m.Type == countType {
continue
}
if isPipelineAgg(m.Type) {
if _, err := strconv.Atoi(m.PipelineAggregate); err == nil {
aggBuilder.Pipeline(m.ID, m.Type, m.PipelineAggregate, func(a *es.PipelineAggregation) {
a.Settings = m.Settings.MustMap()
})
var appliedAgg *MetricAgg
for _, pipelineMetric := range q.Metrics {
if pipelineMetric.ID == m.PipelineAggregate {
appliedAgg = pipelineMetric
break
}
}
if appliedAgg != nil {
bucketPath := m.PipelineAggregate
if appliedAgg.Type == countType {
bucketPath = "_count"
}
aggBuilder.Pipeline(m.ID, m.Type, bucketPath, func(a *es.PipelineAggregation) {
a.Settings = m.Settings.MustMap()
})
}
} else {
continue
}

View File

@@ -418,6 +418,38 @@ func TestExecuteTimeSeriesQuery(t *testing.T) {
So(pl.BucketPath, ShouldEqual, "3")
})
Convey("With moving average doc count", func() {
c := newFakeClient(5)
_, err := executeTsdbQuery(c, `{
"timeField": "@timestamp",
"bucketAggs": [
{ "type": "date_histogram", "field": "@timestamp", "id": "4" }
],
"metrics": [
{ "id": "3", "type": "count", "field": "select field" },
{
"id": "2",
"type": "moving_avg",
"field": "3",
"pipelineAgg": "3"
}
]
}`, from, to, 15*time.Second)
So(err, ShouldBeNil)
sr := c.multisearchRequests[0].Requests[0]
firstLevel := sr.Aggs[0]
So(firstLevel.Key, ShouldEqual, "4")
So(firstLevel.Aggregation.Type, ShouldEqual, "date_histogram")
So(firstLevel.Aggregation.Aggs, ShouldHaveLength, 1)
movingAvgAgg := firstLevel.Aggregation.Aggs[0]
So(movingAvgAgg.Key, ShouldEqual, "2")
So(movingAvgAgg.Aggregation.Type, ShouldEqual, "moving_avg")
pl := movingAvgAgg.Aggregation.Aggregation.(*es.PipelineAggregation)
So(pl.BucketPath, ShouldEqual, "_count")
})
Convey("With broken moving average", func() {
c := newFakeClient(5)
_, err := executeTsdbQuery(c, `{
@@ -483,6 +515,34 @@ func TestExecuteTimeSeriesQuery(t *testing.T) {
So(plAgg.BucketPath, ShouldEqual, "3")
})
Convey("With derivative doc count", func() {
c := newFakeClient(5)
_, err := executeTsdbQuery(c, `{
"timeField": "@timestamp",
"bucketAggs": [
{ "type": "date_histogram", "field": "@timestamp", "id": "4" }
],
"metrics": [
{ "id": "3", "type": "count", "field": "select field" },
{
"id": "2",
"type": "derivative",
"pipelineAgg": "3"
}
]
}`, from, to, 15*time.Second)
So(err, ShouldBeNil)
sr := c.multisearchRequests[0].Requests[0]
firstLevel := sr.Aggs[0]
So(firstLevel.Key, ShouldEqual, "4")
So(firstLevel.Aggregation.Type, ShouldEqual, "date_histogram")
derivativeAgg := firstLevel.Aggregation.Aggs[0]
So(derivativeAgg.Key, ShouldEqual, "2")
plAgg := derivativeAgg.Aggregation.Aggregation.(*es.PipelineAggregation)
So(plAgg.BucketPath, ShouldEqual, "_count")
})
})
}

View File

@@ -51,6 +51,10 @@ export class TagFilter extends React.Component<Props, any> {
getOptionLabel: i => i.label,
value: tags,
styles: ResetStyles,
filterOption: (option, searchQuery) => {
const regex = RegExp(searchQuery, 'i');
return regex.test(option.value);
},
components: {
Option: TagOption,
IndicatorsContainer,

View File

@@ -108,11 +108,21 @@ export interface LogsParser {
* Used to filter rows, and first capture group contains the value.
*/
buildMatcher: (label: string) => RegExp;
/**
* Regex to find a field in the log line.
* First capture group contains the label value, second capture group the value.
* Returns all parsable substrings from a line, used for highlighting
*/
fieldRegex: RegExp;
getFields: (line: string) => string[];
/**
* Gets the label name from a parsable substring of a line
*/
getLabelFromField: (field: string) => string;
/**
* Gets the label value from a parsable substring of a line
*/
getValueFromField: (field: string) => string;
/**
* Function to verify if this is a valid parser for the given line.
* The parser accepts the line unless it returns undefined.
@@ -120,20 +130,48 @@ export interface LogsParser {
test: (line: string) => any;
}
const LOGFMT_REGEXP = /(?:^|\s)(\w+)=("[^"]*"|\S+)/;
export const LogsParsers: { [name: string]: LogsParser } = {
JSON: {
buildMatcher: label => new RegExp(`(?:{|,)\\s*"${label}"\\s*:\\s*"([^"]*)"`),
fieldRegex: /"(\w+)"\s*:\s*"([^"]*)"/,
buildMatcher: label => new RegExp(`(?:{|,)\\s*"${label}"\\s*:\\s*"?([\\d\\.]+|[^"]*)"?`),
getFields: line => {
const fields = [];
try {
const parsed = JSON.parse(line);
_.map(parsed, (value, key) => {
const fieldMatcher = new RegExp(`"${key}"\\s*:\\s*"?${_.escapeRegExp(JSON.stringify(value))}"?`);
const match = line.match(fieldMatcher);
if (match) {
fields.push(match[0]);
}
});
} catch {}
return fields;
},
getLabelFromField: field => (field.match(/^"(\w+)"\s*:/) || [])[1],
getValueFromField: field => (field.match(/:\s*(.*)$/) || [])[1],
test: line => {
try {
return JSON.parse(line);
} catch (error) {}
},
},
logfmt: {
buildMatcher: label => new RegExp(`(?:^|\\s)${label}=("[^"]*"|\\S+)`),
fieldRegex: /(?:^|\s)(\w+)=("[^"]*"|\S+)/,
test: line => LogsParsers.logfmt.fieldRegex.test(line),
getFields: line => {
const fields = [];
line.replace(new RegExp(LOGFMT_REGEXP, 'g'), substring => {
fields.push(substring.trim());
return '';
});
return fields;
},
getLabelFromField: field => (field.match(LOGFMT_REGEXP) || [])[1],
getValueFromField: field => (field.match(LOGFMT_REGEXP) || [])[2],
test: line => LOGFMT_REGEXP.test(line),
},
};

View File

@@ -240,11 +240,16 @@ describe('LogsParsers', () => {
expect(parser.test('foo=bar')).toBeTruthy();
});
test('should have a valid fieldRegex', () => {
const match = 'foo=bar'.match(parser.fieldRegex);
expect(match).toBeDefined();
expect(match[1]).toBe('foo');
expect(match[2]).toBe('bar');
test('should return parsed fields', () => {
expect(parser.getFields('foo=bar baz="42 + 1"')).toEqual(['foo=bar', 'baz="42 + 1"']);
});
test('should return label for field', () => {
expect(parser.getLabelFromField('foo=bar')).toBe('foo');
});
test('should return value for field', () => {
expect(parser.getValueFromField('foo=bar')).toBe('bar');
});
test('should build a valid value matcher', () => {
@@ -263,18 +268,36 @@ describe('LogsParsers', () => {
expect(parser.test('{"foo":"bar"}')).toBeTruthy();
});
test('should have a valid fieldRegex', () => {
const match = '{"foo":"bar"}'.match(parser.fieldRegex);
expect(match).toBeDefined();
expect(match[1]).toBe('foo');
expect(match[2]).toBe('bar');
test('should return parsed fields', () => {
expect(parser.getFields('{ "foo" : "bar", "baz" : 42 }')).toEqual(['"foo" : "bar"', '"baz" : 42']);
});
test('should build a valid value matcher', () => {
test('should return parsed fields for nested quotes', () => {
expect(parser.getFields(`{"foo":"bar: '[value=\\"42\\"]'"}`)).toEqual([`"foo":"bar: '[value=\\"42\\"]'"`]);
});
test('should return label for field', () => {
expect(parser.getLabelFromField('"foo" : "bar"')).toBe('foo');
});
test('should return value for field', () => {
expect(parser.getValueFromField('"foo" : "bar"')).toBe('"bar"');
expect(parser.getValueFromField('"foo" : 42')).toBe('42');
expect(parser.getValueFromField('"foo" : 42.1')).toBe('42.1');
});
test('should build a valid value matcher for strings', () => {
const matcher = parser.buildMatcher('foo');
const match = '{"foo":"bar"}'.match(matcher);
expect(match).toBeDefined();
expect(match[1]).toBe('bar');
});
test('should build a valid value matcher for integers', () => {
const matcher = parser.buildMatcher('foo');
const match = '{"foo":42.1}'.match(matcher);
expect(match).toBeDefined();
expect(match[1]).toBe('42.1');
});
});
});

View File

@@ -191,7 +191,7 @@ export function deleteDataSource(): ThunkResult<void> {
export function nameExits(dataSources, name) {
return (
dataSources.filter(dataSource => {
return dataSource.name === name;
return dataSource.name.toLowerCase() === name.toLowerCase();
}).length > 0
);
}

View File

@@ -73,7 +73,7 @@ interface RowState {
fieldStats: LogsLabelStat[];
fieldValue: string;
parsed: boolean;
parser: LogsParser;
parser?: LogsParser;
parsedFieldHighlights: string[];
showFieldStats: boolean;
}
@@ -94,7 +94,7 @@ class Row extends PureComponent<RowProps, RowState> {
fieldStats: null,
fieldValue: null,
parsed: false,
parser: null,
parser: undefined,
parsedFieldHighlights: [],
showFieldStats: false,
};
@@ -110,19 +110,16 @@ class Row extends PureComponent<RowProps, RowState> {
onClickHighlight = (fieldText: string) => {
const { getRows } = this.props;
const { parser } = this.state;
const allRows = getRows();
const fieldMatch = fieldText.match(parser.fieldRegex);
if (fieldMatch) {
const allRows = getRows();
// Build value-agnostic row matcher based on the field label
const fieldLabel = fieldMatch[1];
const fieldValue = fieldMatch[2];
const matcher = parser.buildMatcher(fieldLabel);
const fieldStats = calculateFieldStats(allRows, matcher);
const fieldCount = fieldStats.reduce((sum, stat) => sum + stat.count, 0);
// Build value-agnostic row matcher based on the field label
const fieldLabel = parser.getLabelFromField(fieldText);
const fieldValue = parser.getValueFromField(fieldText);
const matcher = parser.buildMatcher(fieldLabel);
const fieldStats = calculateFieldStats(allRows, matcher);
const fieldCount = fieldStats.reduce((sum, stat) => sum + stat.count, 0);
this.setState({ fieldCount, fieldLabel, fieldStats, fieldValue, showFieldStats: true });
}
this.setState({ fieldCount, fieldLabel, fieldStats, fieldValue, showFieldStats: true });
};
onMouseOverMessage = () => {
@@ -141,11 +138,7 @@ class Row extends PureComponent<RowProps, RowState> {
const parser = getParser(row.entry);
if (parser) {
// Use parser to highlight detected fields
const parsedFieldHighlights = [];
this.props.row.entry.replace(new RegExp(parser.fieldRegex, 'g'), substring => {
parsedFieldHighlights.push(substring.trim());
return '';
});
const parsedFieldHighlights = parser.getFields(this.props.row.entry);
this.setState({ parsedFieldHighlights, parsed: true, parser });
}
}

View File

@@ -0,0 +1,57 @@
import React, { createRef, PureComponent } from 'react';
import { connect } from 'react-redux';
import { Invitee } from 'app/types';
import { revokeInvite } from './state/actions';
export interface Props {
invitee: Invitee;
revokeInvite: typeof revokeInvite;
}
class InviteeRow extends PureComponent<Props> {
private copyUrlRef = createRef<HTMLTextAreaElement>();
copyToClipboard = () => {
const node = this.copyUrlRef.current;
if (node) {
node.select();
document.execCommand('copy');
}
};
render() {
const { invitee, revokeInvite } = this.props;
return (
<tr>
<td>{invitee.email}</td>
<td>{invitee.name}</td>
<td className="text-right">
<button className="btn btn-inverse btn-mini" onClick={this.copyToClipboard}>
<textarea
readOnly={true}
value={invitee.url}
style={{ position: 'absolute', right: -1000 }}
ref={this.copyUrlRef}
/>
<i className="fa fa-clipboard" /> Copy Invite
</button>
&nbsp;
</td>
<td>
<button className="btn btn-danger btn-mini" onClick={() => revokeInvite(invitee.code)}>
<i className="fa fa-remove" />
</button>
</td>
</tr>
);
}
}
const mapDispatchToProps = {
revokeInvite,
};
export default connect(() => {
return {};
}, mapDispatchToProps)(InviteeRow);

View File

@@ -7,7 +7,6 @@ import { getMockInvitees } from './__mocks__/userMocks';
const setup = (propOverrides?: object) => {
const props: Props = {
invitees: [] as Invitee[],
onRevokeInvite: jest.fn(),
};
Object.assign(props, propOverrides);

View File

@@ -1,25 +1,14 @@
import React, { createRef, PureComponent } from 'react';
import React, { PureComponent } from 'react';
import { Invitee } from 'app/types';
import InviteeRow from './InviteeRow';
export interface Props {
invitees: Invitee[];
onRevokeInvite: (code: string) => void;
}
export default class InviteesTable extends PureComponent<Props> {
private copyUrlRef = createRef<HTMLTextAreaElement>();
copyToClipboard = () => {
const node = this.copyUrlRef.current;
if (node) {
node.select();
document.execCommand('copy');
}
};
render() {
const { invitees, onRevokeInvite } = this.props;
const { invitees } = this.props;
return (
<table className="filter-table form-inline">
@@ -33,29 +22,7 @@ export default class InviteesTable extends PureComponent<Props> {
</thead>
<tbody>
{invitees.map((invitee, index) => {
return (
<tr key={`${invitee.id}-${index}`}>
<td>{invitee.email}</td>
<td>{invitee.name}</td>
<td className="text-right">
<button className="btn btn-inverse btn-mini" onClick={this.copyToClipboard}>
<textarea
readOnly={true}
value={invitee.url}
style={{ position: 'absolute', right: -1000 }}
ref={this.copyUrlRef}
/>
<i className="fa fa-clipboard" /> Copy Invite
</button>
&nbsp;
</td>
<td>
<button className="btn btn-danger btn-mini" onClick={() => onRevokeInvite(invitee.code)}>
<i className="fa fa-remove" />
</button>
</td>
</tr>
);
return <InviteeRow key={`${invitee.id}-${index}`} invitee={invitee} />;
})}
</tbody>
</table>

View File

@@ -16,7 +16,6 @@ const setup = (propOverrides?: object) => {
invitees: [] as Invitee[],
searchQuery: '',
externalUserMngInfo: '',
revokeInvite: jest.fn(),
loadInvitees: jest.fn(),
loadUsers: jest.fn(),
updateUser: jest.fn(),

View File

@@ -9,7 +9,7 @@ import UsersTable from './UsersTable';
import InviteesTable from './InviteesTable';
import { Invitee, NavModel, OrgUser } from 'app/types';
import appEvents from 'app/core/app_events';
import { loadUsers, loadInvitees, revokeInvite, setUsersSearchQuery, updateUser, removeUser } from './state/actions';
import { loadUsers, loadInvitees, setUsersSearchQuery, updateUser, removeUser } from './state/actions';
import { getNavModel } from '../../core/selectors/navModel';
import { getInvitees, getUsers, getUsersSearchQuery } from './state/selectors';
@@ -25,7 +25,6 @@ export interface Props {
setUsersSearchQuery: typeof setUsersSearchQuery;
updateUser: typeof updateUser;
removeUser: typeof removeUser;
revokeInvite: typeof revokeInvite;
}
export interface State {
@@ -79,10 +78,6 @@ export class UsersListPage extends PureComponent<Props, State> {
});
};
onRevokeInvite = code => {
this.props.revokeInvite(code);
};
onShowInvites = () => {
this.setState(prevState => ({
showInvites: !prevState.showInvites,
@@ -93,7 +88,7 @@ export class UsersListPage extends PureComponent<Props, State> {
const { invitees, users } = this.props;
if (this.state.showInvites) {
return <InviteesTable invitees={invitees} onRevokeInvite={code => this.onRevokeInvite(code)} />;
return <InviteesTable invitees={invitees} />;
} else {
return (
<UsersTable
@@ -141,7 +136,6 @@ const mapDispatchToProps = {
setUsersSearchQuery,
updateUser,
removeUser,
revokeInvite,
};
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(UsersListPage));

View File

@@ -48,7 +48,7 @@ export const getMockInvitees = (amount: number) => {
orgId: 1,
role: 'viewer',
status: 'not accepted',
url: `localhost/invite/$${i}`,
url: `localhost/invite/${i}`,
});
}

View File

@@ -49,270 +49,132 @@ exports[`Render should render invitees 1`] = `
</tr>
</thead>
<tbody>
<tr
<Connect(InviteeRow)
invitee={
Object {
"code": "asdfasdfsadf-0",
"createdOn": "2018-10-02",
"email": "invitee-0@test.com",
"emailSent": true,
"emailSentOn": "2018-10-02",
"id": 0,
"invitedByEmail": "admin@grafana.com",
"invitedByLogin": "admin",
"invitedByName": "admin",
"name": "invitee-0",
"orgId": 1,
"role": "viewer",
"status": "not accepted",
"url": "localhost/invite/0",
}
}
key="0-0"
>
<td>
invitee-0@test.com
</td>
<td>
invitee-0
</td>
<td
className="text-right"
>
<button
className="btn btn-inverse btn-mini"
onClick={[Function]}
>
<textarea
readOnly={true}
style={
Object {
"position": "absolute",
"right": -1000,
}
}
value="localhost/invite/$0"
/>
<i
className="fa fa-clipboard"
/>
Copy Invite
</button>
 
</td>
<td>
<button
className="btn btn-danger btn-mini"
onClick={[Function]}
>
<i
className="fa fa-remove"
/>
</button>
</td>
</tr>
<tr
/>
<Connect(InviteeRow)
invitee={
Object {
"code": "asdfasdfsadf-1",
"createdOn": "2018-10-02",
"email": "invitee-1@test.com",
"emailSent": true,
"emailSentOn": "2018-10-02",
"id": 1,
"invitedByEmail": "admin@grafana.com",
"invitedByLogin": "admin",
"invitedByName": "admin",
"name": "invitee-1",
"orgId": 1,
"role": "viewer",
"status": "not accepted",
"url": "localhost/invite/1",
}
}
key="1-1"
>
<td>
invitee-1@test.com
</td>
<td>
invitee-1
</td>
<td
className="text-right"
>
<button
className="btn btn-inverse btn-mini"
onClick={[Function]}
>
<textarea
readOnly={true}
style={
Object {
"position": "absolute",
"right": -1000,
}
}
value="localhost/invite/$1"
/>
<i
className="fa fa-clipboard"
/>
Copy Invite
</button>
 
</td>
<td>
<button
className="btn btn-danger btn-mini"
onClick={[Function]}
>
<i
className="fa fa-remove"
/>
</button>
</td>
</tr>
<tr
/>
<Connect(InviteeRow)
invitee={
Object {
"code": "asdfasdfsadf-2",
"createdOn": "2018-10-02",
"email": "invitee-2@test.com",
"emailSent": true,
"emailSentOn": "2018-10-02",
"id": 2,
"invitedByEmail": "admin@grafana.com",
"invitedByLogin": "admin",
"invitedByName": "admin",
"name": "invitee-2",
"orgId": 1,
"role": "viewer",
"status": "not accepted",
"url": "localhost/invite/2",
}
}
key="2-2"
>
<td>
invitee-2@test.com
</td>
<td>
invitee-2
</td>
<td
className="text-right"
>
<button
className="btn btn-inverse btn-mini"
onClick={[Function]}
>
<textarea
readOnly={true}
style={
Object {
"position": "absolute",
"right": -1000,
}
}
value="localhost/invite/$2"
/>
<i
className="fa fa-clipboard"
/>
Copy Invite
</button>
 
</td>
<td>
<button
className="btn btn-danger btn-mini"
onClick={[Function]}
>
<i
className="fa fa-remove"
/>
</button>
</td>
</tr>
<tr
/>
<Connect(InviteeRow)
invitee={
Object {
"code": "asdfasdfsadf-3",
"createdOn": "2018-10-02",
"email": "invitee-3@test.com",
"emailSent": true,
"emailSentOn": "2018-10-02",
"id": 3,
"invitedByEmail": "admin@grafana.com",
"invitedByLogin": "admin",
"invitedByName": "admin",
"name": "invitee-3",
"orgId": 1,
"role": "viewer",
"status": "not accepted",
"url": "localhost/invite/3",
}
}
key="3-3"
>
<td>
invitee-3@test.com
</td>
<td>
invitee-3
</td>
<td
className="text-right"
>
<button
className="btn btn-inverse btn-mini"
onClick={[Function]}
>
<textarea
readOnly={true}
style={
Object {
"position": "absolute",
"right": -1000,
}
}
value="localhost/invite/$3"
/>
<i
className="fa fa-clipboard"
/>
Copy Invite
</button>
 
</td>
<td>
<button
className="btn btn-danger btn-mini"
onClick={[Function]}
>
<i
className="fa fa-remove"
/>
</button>
</td>
</tr>
<tr
/>
<Connect(InviteeRow)
invitee={
Object {
"code": "asdfasdfsadf-4",
"createdOn": "2018-10-02",
"email": "invitee-4@test.com",
"emailSent": true,
"emailSentOn": "2018-10-02",
"id": 4,
"invitedByEmail": "admin@grafana.com",
"invitedByLogin": "admin",
"invitedByName": "admin",
"name": "invitee-4",
"orgId": 1,
"role": "viewer",
"status": "not accepted",
"url": "localhost/invite/4",
}
}
key="4-4"
>
<td>
invitee-4@test.com
</td>
<td>
invitee-4
</td>
<td
className="text-right"
>
<button
className="btn btn-inverse btn-mini"
onClick={[Function]}
>
<textarea
readOnly={true}
style={
Object {
"position": "absolute",
"right": -1000,
}
}
value="localhost/invite/$4"
/>
<i
className="fa fa-clipboard"
/>
Copy Invite
</button>
 
</td>
<td>
<button
className="btn btn-danger btn-mini"
onClick={[Function]}
>
<i
className="fa fa-remove"
/>
</button>
</td>
</tr>
<tr
/>
<Connect(InviteeRow)
invitee={
Object {
"code": "asdfasdfsadf-5",
"createdOn": "2018-10-02",
"email": "invitee-5@test.com",
"emailSent": true,
"emailSentOn": "2018-10-02",
"id": 5,
"invitedByEmail": "admin@grafana.com",
"invitedByLogin": "admin",
"invitedByName": "admin",
"name": "invitee-5",
"orgId": 1,
"role": "viewer",
"status": "not accepted",
"url": "localhost/invite/5",
}
}
key="5-5"
>
<td>
invitee-5@test.com
</td>
<td>
invitee-5
</td>
<td
className="text-right"
>
<button
className="btn btn-inverse btn-mini"
onClick={[Function]}
>
<textarea
readOnly={true}
style={
Object {
"position": "absolute",
"right": -1000,
}
}
value="localhost/invite/$5"
/>
<i
className="fa fa-clipboard"
/>
Copy Invite
</button>
 
</td>
<td>
<button
className="btn btn-danger btn-mini"
onClick={[Function]}
>
<i
className="fa fa-remove"
/>
</button>
</td>
</tr>
/>
</tbody>
</table>
`;

View File

@@ -270,7 +270,14 @@ export class ElasticQueryBuilder {
if (queryDef.isPipelineAgg(metric.type)) {
if (metric.pipelineAgg && /^\d*$/.test(metric.pipelineAgg)) {
metricAgg = { buckets_path: metric.pipelineAgg };
const appliedAgg = queryDef.findMetricById(target.metrics, metric.pipelineAgg);
if (appliedAgg) {
if (appliedAgg.type === 'count') {
metricAgg = { buckets_path: '_count' };
} else {
metricAgg = { buckets_path: metric.pipelineAgg };
}
}
} else {
continue;
}

View File

@@ -213,6 +213,9 @@ export function describeOrder(order) {
export function describeMetric(metric) {
const def = _.find(metricAggTypes, { value: metric.type });
if (!def.requiresField && !isPipelineAgg(metric.type)) {
return def.text;
}
return def.text + ' ' + metric.field;
}
@@ -236,3 +239,7 @@ export function defaultMetricAgg() {
export function defaultBucketAgg() {
return { type: 'date_histogram', id: '2', settings: { interval: 'auto' } };
}
export const findMetricById = (metrics: any[], id: any) => {
return _.find(metrics, { id: id });
};

View File

@@ -250,6 +250,31 @@ describe('ElasticQueryBuilder', () => {
expect(firstLevel.aggs['2'].moving_avg.buckets_path).toBe('3');
});
it('with moving average doc count', () => {
const query = builder.build({
metrics: [
{
id: '3',
type: 'count',
field: 'select field',
},
{
id: '2',
type: 'moving_avg',
field: '3',
pipelineAgg: '3',
},
],
bucketAggs: [{ type: 'date_histogram', field: '@timestamp', id: '4' }],
});
const firstLevel = query.aggs['4'];
expect(firstLevel.aggs['2']).not.toBe(undefined);
expect(firstLevel.aggs['2'].moving_avg).not.toBe(undefined);
expect(firstLevel.aggs['2'].moving_avg.buckets_path).toBe('_count');
});
it('with broken moving average', () => {
const query = builder.build({
metrics: [
@@ -304,6 +329,30 @@ describe('ElasticQueryBuilder', () => {
expect(firstLevel.aggs['2'].derivative.buckets_path).toBe('3');
});
it('with derivative doc count', () => {
const query = builder.build({
metrics: [
{
id: '3',
type: 'count',
field: 'select field',
},
{
id: '2',
type: 'derivative',
pipelineAgg: '3',
},
],
bucketAggs: [{ type: 'date_histogram', field: '@timestamp', id: '4' }],
});
const firstLevel = query.aggs['4'];
expect(firstLevel.aggs['2']).not.toBe(undefined);
expect(firstLevel.aggs['2'].derivative).not.toBe(undefined);
expect(firstLevel.aggs['2'].derivative.buckets_path).toBe('_count');
});
it('with histogram', () => {
const query = builder.build({
metrics: [{ id: '1', type: 'count' }],

View File

@@ -2,7 +2,8 @@
<!-- Generator: Adobe Illustrator 19.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="200px" height="200px" viewBox="0 0 200 200" style="enable-background:new 0 0 200 200;" xml:space="preserve">
width="264.2px" height="318px" viewBox="-181.1 -67 264.2 318" style="enable-background:new -181.1 -67 264.2 318;"
xml:space="preserve">
<style type="text/css">
.st0{fill:url(#SVGID_1_);}
.st1{fill:url(#SVGID_2_);}
@@ -19,198 +20,97 @@
.st12{fill:url(#SVGID_13_);}
.st13{fill:url(#SVGID_14_);}
.st14{fill:url(#SVGID_15_);}
.st15{fill:url(#SVGID_16_);}
.st16{fill:url(#SVGID_17_);}
.st17{fill:url(#SVGID_18_);}
.st18{fill:url(#SVGID_19_);}
.st19{fill:url(#SVGID_20_);}
.st20{fill:url(#SVGID_21_);}
.st21{fill:url(#SVGID_22_);}
.st22{fill:url(#SVGID_23_);}
.st23{fill:url(#SVGID_24_);}
.st24{fill:url(#SVGID_25_);}
.st25{fill:url(#SVGID_26_);}
.st26{fill:url(#SVGID_27_);}
.st27{fill:url(#SVGID_28_);}
.st28{fill:url(#SVGID_29_);}
.st29{fill:url(#SVGID_30_);}
.st30{fill:url(#SVGID_31_);}
.st31{fill:url(#SVGID_32_);}
</style>
<g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="135.0285" y1="238.7858" x2="135.0285" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="342.6804" y1="897.3058" x2="342.6804" y2="547.4434" gradientTransform="matrix(0.9805 -0.1964 0.1964 0.9805 -567.5302 -509.0906)">
<stop offset="0" style="stop-color:#F9EC1C"/>
<stop offset="1" style="stop-color:#F05A2B"/>
</linearGradient>
<path class="st0" d="M179.5,130c-6.9-9.5-18.6-16.1-30.2-17.9l-38.1-4.6l0,22.4l34.7,4c5.8,0.9,12.3,4.3,15.8,9.1
c3.5,4.7,4.9,10.5,4,16.3c-1.7,10.8-11,18.5-21.6,18.5c-1.1,0-2.3-0.1-3.4-0.3l-37.9-4.7c-5.1,8-12.2,14.7-20.6,19.2l55.2,7.4
c2.3,0.4,4.6,0.5,6.8,0.5c21.3,0,40-15.6,43.4-37.3C189.3,151.1,186.4,139.5,179.5,130z"/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="56.0866" y1="238.7858" x2="56.0866" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
<polygon class="st0" points="-127.3,-58.2 -127.5,-59.1 -128.3,-58.9 "/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="295.8044" y1="887.3397" x2="295.8044" y2="537.4772" gradientTransform="matrix(0.9805 -0.1964 0.1964 0.9805 -567.5302 -509.0906)">
<stop offset="0" style="stop-color:#F9EC1C"/>
<stop offset="1" style="stop-color:#F05A2B"/>
</linearGradient>
<path class="st1" d="M90.5,171c1.3-1.6,2.4-3.3,3.5-5.1c1-1.7,1.9-3.4,2.7-5.2c2.3-5.3,3.5-11.2,3.5-17.3l0-4l0-5.6l0-5.6l0-22.4
l0-5.6l0-5.6L100,43.9C100,19.7,80.2,0,55.9,0S12,19.8,12,44.1l0.1,66.7c5.7-7.6,13.3-13.7,22.1-17.6L34.1,44
c0-12.1,9.8-21.9,21.8-21.9c12.1,0,21.9,9.8,21.9,21.8L78,91.2l0,5.6l0,5.6l0,22.4l0,5.6l0,5.6l0,7.5c0,5.2-1.8,9.9-4.8,13.7
c-1.5,1.9-3.3,3.5-5.3,4.8c-3.4,2.2-7.4,3.5-11.7,3.5c-0.7,0-1.4,0-2,0l-1.4-0.2c-10.8-1.7-18.6-11.1-18.5-21.8
c0-1.1,0.1-2.1,0.2-3.2c0.7-4.3,2.6-8.1,5.3-11.1c1.6-1.8,3.5-3.3,5.5-4.5c3.2-1.8,6.9-2.9,10.8-2.9c1.1,0,2.3,0.1,3.4,0.3l7.5,1.2
l0-22.4l-4-0.6c-2.3-0.4-4.6-0.5-6.8-0.5c-3.7,0-7.3,0.5-10.8,1.4c-1.9,0.5-3.7,1.1-5.5,1.8c-1.9,0.8-3.8,1.7-5.5,2.7
c-11.2,6.4-19.4,17.7-21.6,31.4c-0.4,2.4-0.5,4.9-0.5,7.3c0,1.2,0.1,2.3,0.2,3.5c0,0.3,0.1,0.6,0.1,0.9c0.1,1.1,0.3,2.3,0.5,3.4
c0.1,0.3,0.1,0.7,0.2,1c0.2,1.1,0.5,2.1,0.8,3.2c0.1,0.4,0.2,0.7,0.3,1.1c0.3,1,0.7,2,1.1,3c0.1,0.3,0.3,0.7,0.4,1
c0.4,1,0.9,1.9,1.4,2.9c0.2,0.3,0.3,0.6,0.5,0.9c0.5,1,1.1,1.9,1.7,2.8c0.2,0.2,0.3,0.5,0.5,0.7c0.7,1,1.4,1.9,2.1,2.9
c0.1,0.1,0.2,0.3,0.4,0.4c0.8,1,1.7,1.9,2.6,2.8c0.1,0.1,0.1,0.1,0.2,0.2c1,1,2,1.9,3,2.7c0,0,0.1,0,0.1,0.1
c1.1,0.9,2.2,1.7,3.3,2.5c0,0,0,0,0.1,0.1c1.1,0.8,2.3,1.5,3.5,2.1c0.1,0,0.1,0.1,0.2,0.1c1.1,0.6,2.3,1.2,3.5,1.7
c0.2,0.1,0.3,0.1,0.5,0.2c1.1,0.5,2.2,0.9,3.3,1.2c0.3,0.1,0.6,0.2,0.9,0.3c1,0.3,2.1,0.6,3.2,0.8c0.4,0.1,0.8,0.2,1.2,0.2
c2.7,0.5,5.5,0.8,8.3,0.8C70.1,187.5,82.4,181.1,90.5,171z"/>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="26.7057" y1="238.7858" x2="26.7057" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
<polygon class="st1" points="-108.3,219.3 -130.7,223.8 -126.2,246.3 -103.8,241.8 "/>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="442.4363" y1="887.3397" x2="442.4363" y2="537.4772" gradientTransform="matrix(0.9805 -0.1964 0.1964 0.9805 -567.5302 -509.0906)">
<stop offset="0" style="stop-color:#F9EC1C"/>
<stop offset="1" style="stop-color:#F05A2B"/>
</linearGradient>
<path class="st2" d="M28.2,177.5c-1-0.9-2-1.8-3-2.7"/>
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="12.7354" y1="238.7858" x2="12.7354" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
<polygon class="st2" points="-27.8,190 71.3,170.1 66.8,147.7 -32.3,167.5 "/>
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="367.5056" y1="887.3397" x2="367.5056" y2="537.4772" gradientTransform="matrix(0.9805 -0.1964 0.1964 0.9805 -567.5302 -509.0906)">
<stop offset="0" style="stop-color:#F9EC1C"/>
<stop offset="1" style="stop-color:#F05A2B"/>
</linearGradient>
<path class="st3" d="M13,151.9c-0.2-1.1-0.4-2.2-0.5-3.4"/>
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="14.8849" y1="238.7858" x2="14.8849" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
<polygon class="st3" points="-67.5,174.6 -63,197 -40.5,192.5 -45,170.1 "/>
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="331.6549" y1="887.3397" x2="331.6549" y2="537.4772" gradientTransform="matrix(0.9805 -0.1964 0.1964 0.9805 -567.5302 -509.0906)">
<stop offset="0" style="stop-color:#F9EC1C"/>
<stop offset="1" style="stop-color:#F05A2B"/>
</linearGradient>
<path class="st4" d="M15.4,160.1c-0.4-1-0.8-2-1.1-3"/>
<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="18.6023" y1="238.7858" x2="18.6023" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
<polygon class="st4" points="-68.6,234.7 -73.1,212.3 -95.6,216.8 -91.1,239.2 "/>
<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="295.8044" y1="887.3397" x2="295.8044" y2="537.4772" gradientTransform="matrix(0.9805 -0.1964 0.1964 0.9805 -567.5302 -509.0906)">
<stop offset="0" style="stop-color:#F9EC1C"/>
<stop offset="1" style="stop-color:#F05A2B"/>
</linearGradient>
<path class="st5" d="M19.5,167.8c-0.6-0.9-1.2-1.9-1.7-2.8"/>
<linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="16.5561" y1="238.7858" x2="16.5561" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
<polygon class="st5" points="-133.3,211.1 -110.8,206.6 -115.3,184.2 -137.8,188.7 "/>
<linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="442.4363" y1="887.3397" x2="442.4363" y2="537.4772" gradientTransform="matrix(0.9805 -0.1964 0.1964 0.9805 -567.5302 -509.0906)">
<stop offset="0" style="stop-color:#F9EC1C"/>
<stop offset="1" style="stop-color:#F05A2B"/>
</linearGradient>
<path class="st6" d="M17.2,164c-0.5-0.9-1-1.9-1.4-2.9"/>
<linearGradient id="SVGID_8_" gradientUnits="userSpaceOnUse" x1="12.2907" y1="238.7858" x2="12.2907" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
<polygon class="st6" points="73.8,182.8 -25.3,202.7 -20.8,225.1 78.3,205.3 "/>
<linearGradient id="SVGID_8_" gradientUnits="userSpaceOnUse" x1="367.5056" y1="887.3397" x2="367.5056" y2="537.4772" gradientTransform="matrix(0.9805 -0.1964 0.1964 0.9805 -567.5302 -509.0906)">
<stop offset="0" style="stop-color:#F9EC1C"/>
<stop offset="1" style="stop-color:#F05A2B"/>
</linearGradient>
<path class="st7" d="M12.2,144.1c0,1.2,0.1,2.3,0.2,3.5"/>
<linearGradient id="SVGID_9_" gradientUnits="userSpaceOnUse" x1="23.7117" y1="238.7858" x2="23.7117" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
<polygon class="st7" points="-60.4,209.7 -55.9,232.2 -33.5,227.7 -38,205.2 "/>
<linearGradient id="SVGID_9_" gradientUnits="userSpaceOnUse" x1="331.6549" y1="887.3397" x2="331.6549" y2="537.4772" gradientTransform="matrix(0.9805 -0.1964 0.1964 0.9805 -567.5302 -509.0906)">
<stop offset="0" style="stop-color:#F9EC1C"/>
<stop offset="1" style="stop-color:#F05A2B"/>
</linearGradient>
<path class="st8" d="M25,174.6c-0.9-0.9-1.8-1.9-2.6-2.8"/>
<linearGradient id="SVGID_10_" gradientUnits="userSpaceOnUse" x1="20.9974" y1="238.7858" x2="20.9974" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
<polygon class="st8" points="-98.1,204.1 -75.7,199.6 -80.2,177.1 -102.6,181.6 "/>
<linearGradient id="SVGID_10_" gradientUnits="userSpaceOnUse" x1="289.1909" y1="880.5443" x2="289.1909" y2="548.7296" gradientTransform="matrix(0.9805 -0.1964 0.1964 0.9805 -567.5302 -509.0906)">
<stop offset="0" style="stop-color:#F9EC1C"/>
<stop offset="1" style="stop-color:#F05A2B"/>
</linearGradient>
<path class="st9" d="M22.1,171.3c-0.8-0.9-1.5-1.9-2.1-2.9"/>
<linearGradient id="SVGID_11_" gradientUnits="userSpaceOnUse" x1="13.6059" y1="238.7858" x2="13.6059" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
<polygon class="st9" points="-140.3,176 -130.8,174.1 -166.8,-5.6 -176.3,-3.7 "/>
<linearGradient id="SVGID_11_" gradientUnits="userSpaceOnUse" x1="302.4872" y1="889.7463" x2="302.4872" y2="533.4922" gradientTransform="matrix(0.9805 -0.1964 0.1964 0.9805 -567.5302 -509.0906)">
<stop offset="0" style="stop-color:#F9EC1C"/>
<stop offset="1" style="stop-color:#F05A2B"/>
</linearGradient>
<path class="st10" d="M14,156.1c-0.3-1-0.6-2.1-0.8-3.2"/>
<linearGradient id="SVGID_12_" gradientUnits="userSpaceOnUse" x1="37.1094" y1="238.7858" x2="37.1094" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
<polygon class="st10" points="-127.3,173.4 -117.8,171.5 -156.4,-21.4 -165.9,-19.5 "/>
<linearGradient id="SVGID_12_" gradientUnits="userSpaceOnUse" x1="325.1889" y1="908.8145" x2="325.1889" y2="501.9178" gradientTransform="matrix(0.9805 -0.1964 0.1964 0.9805 -567.5302 -509.0906)">
<stop offset="0" style="stop-color:#F9EC1C"/>
<stop offset="1" style="stop-color:#F05A2B"/>
</linearGradient>
<path class="st11" d="M38.8,184c-1.2-0.5-2.3-1.1-3.5-1.7"/>
<linearGradient id="SVGID_13_" gradientUnits="userSpaceOnUse" x1="45.1619" y1="238.7858" x2="45.1619" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
<polygon class="st11" points="-105,168.9 -95.5,167 -139.7,-53.3 -149.2,-51.4 "/>
<linearGradient id="SVGID_13_" gradientUnits="userSpaceOnUse" x1="338.4852" y1="896.2529" x2="338.4852" y2="522.7181" gradientTransform="matrix(0.9805 -0.1964 0.1964 0.9805 -567.5302 -509.0906)">
<stop offset="0" style="stop-color:#F9EC1C"/>
<stop offset="1" style="stop-color:#F05A2B"/>
</linearGradient>
<path class="st12" d="M46.8,186.5c-1.1-0.2-2.1-0.5-3.2-0.8"/>
<linearGradient id="SVGID_14_" gradientUnits="userSpaceOnUse" x1="29.9487" y1="238.7858" x2="29.9487" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
<polygon class="st12" points="-92,166.3 -82.5,164.4 -123,-37.9 -132.5,-36 "/>
<linearGradient id="SVGID_14_" gradientUnits="userSpaceOnUse" x1="360.8988" y1="870.7903" x2="360.8988" y2="564.8808" gradientTransform="matrix(0.9805 -0.1964 0.1964 0.9805 -567.5302 -509.0906)">
<stop offset="0" style="stop-color:#F9EC1C"/>
<stop offset="1" style="stop-color:#F05A2B"/>
</linearGradient>
<path class="st13" d="M31.6,180c-1.1-0.8-2.2-1.6-3.3-2.5"/>
<linearGradient id="SVGID_15_" gradientUnits="userSpaceOnUse" x1="41.0239" y1="238.7858" x2="41.0239" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
<polygon class="st13" points="-70,161.9 -60.5,160 -93.7,-5.7 -103.2,-3.8 "/>
<linearGradient id="SVGID_15_" gradientUnits="userSpaceOnUse" x1="374.1951" y1="875.2039" x2="374.1951" y2="557.5726" gradientTransform="matrix(0.9805 -0.1964 0.1964 0.9805 -567.5302 -509.0906)">
<stop offset="0" style="stop-color:#F9EC1C"/>
<stop offset="1" style="stop-color:#F05A2B"/>
</linearGradient>
<path class="st14" d="M42.7,185.4c-1.1-0.4-2.3-0.8-3.3-1.2"/>
<linearGradient id="SVGID_16_" gradientUnits="userSpaceOnUse" x1="33.4189" y1="238.7858" x2="33.4189" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
</linearGradient>
<path class="st15" d="M35.2,182.2c-1.2-0.7-2.4-1.4-3.5-2.1"/>
<linearGradient id="SVGID_17_" gradientUnits="userSpaceOnUse" x1="53.9595" y1="238.7858" x2="53.9595" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
</linearGradient>
<path class="st16" d="M54.1,154.2c-0.1,0-0.1,0-0.2-0.1"/>
<linearGradient id="SVGID_18_" gradientUnits="userSpaceOnUse" x1="21.1405" y1="238.7858" x2="21.1405" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
</linearGradient>
<path class="st17" d="M21.4,178.8c-0.2-0.2-0.3-0.3-0.5-0.5"/>
<linearGradient id="SVGID_19_" gradientUnits="userSpaceOnUse" x1="35.2646" y1="238.7858" x2="35.2646" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
</linearGradient>
<path class="st18" d="M35.2,182.2c0.1,0,0.1,0.1,0.2,0.1"/>
<linearGradient id="SVGID_20_" gradientUnits="userSpaceOnUse" x1="39.0979" y1="238.7858" x2="39.0979" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
</linearGradient>
<path class="st19" d="M39.3,184.2c-0.2-0.1-0.3-0.1-0.5-0.2"/>
<linearGradient id="SVGID_21_" gradientUnits="userSpaceOnUse" x1="31.6434" y1="238.7858" x2="31.6434" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
</linearGradient>
<path class="st20" d="M31.7,180.1C31.7,180.1,31.6,180.1,31.7,180.1"/>
<linearGradient id="SVGID_22_" gradientUnits="userSpaceOnUse" x1="28.2485" y1="238.7858" x2="28.2485" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
</linearGradient>
<path class="st21" d="M28.3,177.6C28.3,177.5,28.2,177.5,28.3,177.6"/>
<linearGradient id="SVGID_23_" gradientUnits="userSpaceOnUse" x1="43.1314" y1="238.7858" x2="43.1314" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
</linearGradient>
<path class="st22" d="M43.6,185.7c-0.3-0.1-0.6-0.2-0.9-0.3"/>
<linearGradient id="SVGID_24_" gradientUnits="userSpaceOnUse" x1="47.3468" y1="238.7858" x2="47.3468" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
</linearGradient>
<path class="st23" d="M46.8,186.5c0.4,0.1,0.8,0.2,1.2,0.2"/>
<linearGradient id="SVGID_25_" gradientUnits="userSpaceOnUse" x1="19.6975" y1="238.7858" x2="19.6975" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
</linearGradient>
<path class="st24" d="M19.9,168.4c-0.2-0.2-0.3-0.5-0.5-0.7"/>
<linearGradient id="SVGID_26_" gradientUnits="userSpaceOnUse" x1="17.4923" y1="238.7858" x2="17.4923" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
</linearGradient>
<path class="st25" d="M17.7,164.9c-0.2-0.3-0.3-0.6-0.5-0.9"/>
<linearGradient id="SVGID_27_" gradientUnits="userSpaceOnUse" x1="12.4278" y1="238.7858" x2="12.4278" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
</linearGradient>
<path class="st26" d="M12.5,148.5c0-0.3-0.1-0.6-0.1-0.9"/>
<linearGradient id="SVGID_28_" gradientUnits="userSpaceOnUse" x1="13.0965" y1="238.7858" x2="13.0965" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
</linearGradient>
<path class="st27" d="M13.2,152.9c-0.1-0.3-0.1-0.7-0.2-1"/>
<linearGradient id="SVGID_29_" gradientUnits="userSpaceOnUse" x1="14.1769" y1="238.7858" x2="14.1769" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
</linearGradient>
<path class="st28" d="M14.3,157.1c-0.1-0.3-0.2-0.7-0.3-1.1"/>
<linearGradient id="SVGID_30_" gradientUnits="userSpaceOnUse" x1="15.6479" y1="238.7858" x2="15.6479" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
</linearGradient>
<path class="st29" d="M15.9,161.1c-0.2-0.3-0.3-0.7-0.4-1"/>
<linearGradient id="SVGID_31_" gradientUnits="userSpaceOnUse" x1="22.2436" y1="238.7858" x2="22.2436" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
</linearGradient>
<path class="st30" d="M22.4,171.7c-0.1-0.1-0.2-0.3-0.4-0.4"/>
<linearGradient id="SVGID_32_" gradientUnits="userSpaceOnUse" x1="25.1051" y1="238.7858" x2="25.1051" y2="2.4079">
<stop offset="0" style="stop-color:#FBED1D"/>
<stop offset="1" style="stop-color:#F05A2A"/>
</linearGradient>
<path class="st31" d="M25.2,174.8c-0.1-0.1-0.1-0.1-0.2-0.2"/>
<polygon class="st14" points="-57,159.3 -47.5,157.4 -81.9,-14.6 -91.4,-12.7 "/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB