Merge branch 'main' into 20230331_add_kerberos_support
This commit is contained in:
+16
-9
@@ -200,9 +200,6 @@ exports[`better eslint`] = {
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "6"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "7"]
|
||||
],
|
||||
"packages/grafana-data/src/field/templateProxies.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
],
|
||||
"packages/grafana-data/src/geo/layer.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
],
|
||||
@@ -2523,8 +2520,7 @@ exports[`better eslint`] = {
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "3"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "4"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "5"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "6"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "7"]
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "6"]
|
||||
],
|
||||
"public/app/features/dashboard/state/DashboardModel.test.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
@@ -3353,6 +3349,9 @@ exports[`better eslint`] = {
|
||||
"public/app/features/teams/state/selectors.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
],
|
||||
"public/app/features/templating/fieldAccessorCache.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
],
|
||||
"public/app/features/templating/formatVariableValue.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"],
|
||||
@@ -3361,6 +3360,9 @@ exports[`better eslint`] = {
|
||||
"public/app/features/templating/macroRegistry.test.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
],
|
||||
"public/app/features/templating/templateProxies.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
],
|
||||
"public/app/features/templating/template_srv.mock.ts:5381": [
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"]
|
||||
],
|
||||
@@ -3377,11 +3379,9 @@ exports[`better eslint`] = {
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "9"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "10"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "11"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "12"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "12"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "13"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "14"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "15"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "16"]
|
||||
[0, 0, 0, "Do not use any type assertions.", "14"]
|
||||
],
|
||||
"public/app/features/transformers/FilterByValueTransformer/ValueMatchers/BasicMatcherEditor.tsx:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||
@@ -5264,6 +5264,9 @@ exports[`better eslint`] = {
|
||||
[0, 0, 0, "Do not use any type assertions.", "1"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "2"]
|
||||
],
|
||||
"public/app/plugins/panel/flamegraph/components/FlameGraphTopWrapper.tsx:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
],
|
||||
"public/app/plugins/panel/gauge/GaugeMigrations.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
],
|
||||
@@ -6010,6 +6013,10 @@ exports[`better eslint`] = {
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
|
||||
],
|
||||
"public/app/plugins/panel/trend/suggestions.ts:5381": [
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
|
||||
],
|
||||
"public/app/plugins/panel/xychart/AutoEditor.tsx:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
],
|
||||
|
||||
+111
-11
@@ -797,6 +797,12 @@ services:
|
||||
volumes:
|
||||
- name: mysql
|
||||
path: /var/lib/mysql
|
||||
- environment: {}
|
||||
image: redis:6.2.11-alpine
|
||||
name: redis
|
||||
- environment: {}
|
||||
image: memcached:1.6.9-alpine
|
||||
name: memcached
|
||||
steps:
|
||||
- commands:
|
||||
- is_fork=$(curl "https://$GITHUB_TOKEN@api.github.com/repos/grafana/grafana/pulls/$DRONE_PULL_REQUEST"
|
||||
@@ -892,6 +898,26 @@ steps:
|
||||
MYSQL_HOST: mysql
|
||||
image: grafana/build-container:1.7.2
|
||||
name: mysql-integration-tests
|
||||
- commands:
|
||||
- dockerize -wait tcp://redis:6379/0 -timeout 120s
|
||||
- go clean -testcache
|
||||
- go test -run IntegrationRedis -covermode=atomic -timeout=2m ./pkg/...
|
||||
depends_on:
|
||||
- wire-install
|
||||
environment:
|
||||
REDIS_URL: redis://redis:6379/0
|
||||
image: grafana/build-container:1.7.2
|
||||
name: redis-integration-tests
|
||||
- commands:
|
||||
- dockerize -wait tcp://memcached:11211 -timeout 120s
|
||||
- go clean -testcache
|
||||
- go test -run IntegrationMemcached -covermode=atomic -timeout=2m ./pkg/...
|
||||
depends_on:
|
||||
- wire-install
|
||||
environment:
|
||||
MEMCACHED_HOSTS: memcached:11211
|
||||
image: grafana/build-container:1.7.2
|
||||
name: memcached-integration-tests
|
||||
trigger:
|
||||
event:
|
||||
- pull_request
|
||||
@@ -1797,6 +1823,12 @@ services:
|
||||
volumes:
|
||||
- name: mysql
|
||||
path: /var/lib/mysql
|
||||
- environment: {}
|
||||
image: redis:6.2.11-alpine
|
||||
name: redis
|
||||
- environment: {}
|
||||
image: memcached:1.6.9-alpine
|
||||
name: memcached
|
||||
steps:
|
||||
- commands:
|
||||
- mkdir -p bin
|
||||
@@ -1870,6 +1902,26 @@ steps:
|
||||
MYSQL_HOST: mysql
|
||||
image: grafana/build-container:1.7.2
|
||||
name: mysql-integration-tests
|
||||
- commands:
|
||||
- dockerize -wait tcp://redis:6379/0 -timeout 120s
|
||||
- go clean -testcache
|
||||
- go test -run IntegrationRedis -covermode=atomic -timeout=2m ./pkg/...
|
||||
depends_on:
|
||||
- wire-install
|
||||
environment:
|
||||
REDIS_URL: redis://redis:6379/0
|
||||
image: grafana/build-container:1.7.2
|
||||
name: redis-integration-tests
|
||||
- commands:
|
||||
- dockerize -wait tcp://memcached:11211 -timeout 120s
|
||||
- go clean -testcache
|
||||
- go test -run IntegrationMemcached -covermode=atomic -timeout=2m ./pkg/...
|
||||
depends_on:
|
||||
- wire-install
|
||||
environment:
|
||||
MEMCACHED_HOSTS: memcached:11211
|
||||
image: grafana/build-container:1.7.2
|
||||
name: memcached-integration-tests
|
||||
trigger:
|
||||
branch: main
|
||||
event:
|
||||
@@ -4956,6 +5008,12 @@ services:
|
||||
volumes:
|
||||
- name: mysql
|
||||
path: /var/lib/mysql
|
||||
- environment: {}
|
||||
image: redis:6.2.11-alpine
|
||||
name: redis
|
||||
- environment: {}
|
||||
image: memcached:1.6.9-alpine
|
||||
name: memcached
|
||||
steps:
|
||||
- commands:
|
||||
- mkdir -p bin
|
||||
@@ -5022,6 +5080,26 @@ steps:
|
||||
MYSQL_HOST: mysql
|
||||
image: grafana/build-container:1.7.2
|
||||
name: mysql-integration-tests
|
||||
- commands:
|
||||
- dockerize -wait tcp://redis:6379/0 -timeout 120s
|
||||
- go clean -testcache
|
||||
- go test -run IntegrationRedis -covermode=atomic -timeout=2m ./pkg/...
|
||||
depends_on:
|
||||
- wire-install
|
||||
environment:
|
||||
REDIS_URL: redis://redis:6379/0
|
||||
image: grafana/build-container:1.7.2
|
||||
name: redis-integration-tests
|
||||
- commands:
|
||||
- dockerize -wait tcp://memcached:11211 -timeout 120s
|
||||
- go clean -testcache
|
||||
- go test -run IntegrationMemcached -covermode=atomic -timeout=2m ./pkg/...
|
||||
depends_on:
|
||||
- wire-install
|
||||
environment:
|
||||
MEMCACHED_HOSTS: memcached:11211
|
||||
image: grafana/build-container:1.7.2
|
||||
name: memcached-integration-tests
|
||||
trigger:
|
||||
ref:
|
||||
- refs/heads/v[0-9]*
|
||||
@@ -5617,7 +5695,7 @@ services:
|
||||
- name: mysql
|
||||
path: /var/lib/mysql
|
||||
- environment: {}
|
||||
image: redis:6.2.1-alpine
|
||||
image: redis:6.2.11-alpine
|
||||
name: redis
|
||||
- environment: {}
|
||||
image: memcached:1.6.9-alpine
|
||||
@@ -5718,8 +5796,7 @@ steps:
|
||||
- commands:
|
||||
- dockerize -wait tcp://redis:6379/0 -timeout 120s
|
||||
- go clean -testcache
|
||||
- go list './pkg/...' | xargs -I {} sh -c 'go test -run Integration -covermode=atomic
|
||||
-timeout=5m {}'
|
||||
- go test -run IntegrationRedis -covermode=atomic -timeout=2m ./pkg/...
|
||||
depends_on:
|
||||
- wire-install
|
||||
environment:
|
||||
@@ -5729,8 +5806,7 @@ steps:
|
||||
- commands:
|
||||
- dockerize -wait tcp://memcached:11211 -timeout 120s
|
||||
- go clean -testcache
|
||||
- go list './pkg/...' | xargs -I {} sh -c 'go test -run Integration -covermode=atomic
|
||||
-timeout=5m {}'
|
||||
- go test -run IntegrationMemcached -covermode=atomic -timeout=2m ./pkg/...
|
||||
depends_on:
|
||||
- wire-install
|
||||
environment:
|
||||
@@ -6112,6 +6188,12 @@ services:
|
||||
volumes:
|
||||
- name: mysql
|
||||
path: /var/lib/mysql
|
||||
- environment: {}
|
||||
image: redis:6.2.11-alpine
|
||||
name: redis
|
||||
- environment: {}
|
||||
image: memcached:1.6.9-alpine
|
||||
name: memcached
|
||||
steps:
|
||||
- commands:
|
||||
- mkdir -p bin
|
||||
@@ -6178,6 +6260,26 @@ steps:
|
||||
MYSQL_HOST: mysql
|
||||
image: grafana/build-container:1.7.2
|
||||
name: mysql-integration-tests
|
||||
- commands:
|
||||
- dockerize -wait tcp://redis:6379/0 -timeout 120s
|
||||
- go clean -testcache
|
||||
- go test -run IntegrationRedis -covermode=atomic -timeout=2m ./pkg/...
|
||||
depends_on:
|
||||
- wire-install
|
||||
environment:
|
||||
REDIS_URL: redis://redis:6379/0
|
||||
image: grafana/build-container:1.7.2
|
||||
name: redis-integration-tests
|
||||
- commands:
|
||||
- dockerize -wait tcp://memcached:11211 -timeout 120s
|
||||
- go clean -testcache
|
||||
- go test -run IntegrationMemcached -covermode=atomic -timeout=2m ./pkg/...
|
||||
depends_on:
|
||||
- wire-install
|
||||
environment:
|
||||
MEMCACHED_HOSTS: memcached:11211
|
||||
image: grafana/build-container:1.7.2
|
||||
name: memcached-integration-tests
|
||||
trigger:
|
||||
event:
|
||||
- promote
|
||||
@@ -6230,7 +6332,7 @@ services:
|
||||
- name: mysql
|
||||
path: /var/lib/mysql
|
||||
- environment: {}
|
||||
image: redis:6.2.1-alpine
|
||||
image: redis:6.2.11-alpine
|
||||
name: redis
|
||||
- environment: {}
|
||||
image: memcached:1.6.9-alpine
|
||||
@@ -6332,8 +6434,7 @@ steps:
|
||||
- commands:
|
||||
- dockerize -wait tcp://redis:6379/0 -timeout 120s
|
||||
- go clean -testcache
|
||||
- go list './pkg/...' | xargs -I {} sh -c 'go test -run Integration -covermode=atomic
|
||||
-timeout=5m {}'
|
||||
- go test -run IntegrationRedis -covermode=atomic -timeout=2m ./pkg/...
|
||||
depends_on:
|
||||
- wire-install
|
||||
environment:
|
||||
@@ -6343,8 +6444,7 @@ steps:
|
||||
- commands:
|
||||
- dockerize -wait tcp://memcached:11211 -timeout 120s
|
||||
- go clean -testcache
|
||||
- go list './pkg/...' | xargs -I {} sh -c 'go test -run Integration -covermode=atomic
|
||||
-timeout=5m {}'
|
||||
- go test -run IntegrationMemcached -covermode=atomic -timeout=2m ./pkg/...
|
||||
depends_on:
|
||||
- wire-install
|
||||
environment:
|
||||
@@ -6653,6 +6753,6 @@ kind: secret
|
||||
name: enterprise2_security_prefix
|
||||
---
|
||||
kind: signature
|
||||
hmac: 675c90070f9b68e15f349d079fbafa5288c3e5c30c345a4c9678d69afd1cc5a7
|
||||
hmac: 54bded4dc7c3ffbbf3859a4f8f6364f59f3b6e0696152a0b835211eca7119e50
|
||||
|
||||
...
|
||||
|
||||
@@ -407,6 +407,7 @@ lerna.json @grafana/frontend-ops
|
||||
/public/app/plugins/panel/table/ @grafana/grafana-bi-squad
|
||||
/public/app/plugins/panel/table-old/ @grafana/grafana-bi-squad
|
||||
/public/app/plugins/panel/timeseries/ @grafana/dataviz-squad
|
||||
/public/app/plugins/panel/trend/ @grafana/dataviz-squad
|
||||
/public/app/plugins/panel/geomap/ @grafana/dataviz-squad
|
||||
/public/app/plugins/panel/canvas/ @grafana/dataviz-squad
|
||||
/public/app/plugins/panel/candlestick/ @grafana/dataviz-squad
|
||||
|
||||
@@ -322,5 +322,157 @@
|
||||
"addToProject": {
|
||||
"url": "https://github.com/orgs/grafana/projects/78"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "area/panel/candlestick",
|
||||
"action": "addToProject",
|
||||
"addToProject": {
|
||||
"url": "https://github.com/orgs/grafana/projects/56"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "area/panel/canvas",
|
||||
"action": "addToProject",
|
||||
"addToProject": {
|
||||
"url": "https://github.com/orgs/grafana/projects/56"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "area/panel/barchart",
|
||||
"action": "addToProject",
|
||||
"addToProject": {
|
||||
"url": "https://github.com/orgs/grafana/projects/56"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "area/panel/bargauge",
|
||||
"action": "addToProject",
|
||||
"addToProject": {
|
||||
"url": "https://github.com/orgs/grafana/projects/72"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "area/panel/gauge",
|
||||
"action": "addToProject",
|
||||
"addToProject": {
|
||||
"url": "https://github.com/orgs/grafana/projects/72"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "area/panel/geomap",
|
||||
"action": "addToProject",
|
||||
"addToProject": {
|
||||
"url": "https://github.com/orgs/grafana/projects/56"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "area/panel/graph",
|
||||
"action": "addToProject",
|
||||
"addToProject": {
|
||||
"url": "https://github.com/orgs/grafana/projects/56"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "area/panel/heatmap",
|
||||
"action": "addToProject",
|
||||
"addToProject": {
|
||||
"url": "https://github.com/orgs/grafana/projects/56"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "area/panel/histogram",
|
||||
"action": "addToProject",
|
||||
"addToProject": {
|
||||
"url": "https://github.com/orgs/grafana/projects/56"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "area/panel/icon",
|
||||
"action": "addToProject",
|
||||
"addToProject": {
|
||||
"url": "https://github.com/orgs/grafana/projects/56"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "area/panel/piechart",
|
||||
"action": "addToProject",
|
||||
"addToProject": {
|
||||
"url": "https://github.com/orgs/grafana/projects/72"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "area/panel/stat",
|
||||
"action": "addToProject",
|
||||
"addToProject": {
|
||||
"url": "https://github.com/orgs/grafana/projects/72"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "area/panel/state-timeline",
|
||||
"action": "addToProject",
|
||||
"addToProject": {
|
||||
"url": "https://github.com/orgs/grafana/projects/56"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "area/panel/status-history",
|
||||
"action": "addToProject",
|
||||
"addToProject": {
|
||||
"url": "https://github.com/orgs/grafana/projects/56"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "area/panel/timeseries",
|
||||
"action": "addToProject",
|
||||
"addToProject": {
|
||||
"url": "https://github.com/orgs/grafana/projects/56"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "area/panel/xychart",
|
||||
"action": "addToProject",
|
||||
"addToProject": {
|
||||
"url": "https://github.com/orgs/grafana/projects/56"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "area/panel/oss-dataviz",
|
||||
"action": "addToProject",
|
||||
"addToProject": {
|
||||
"url": "https://github.com/orgs/grafana/projects/56"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "area/panel/oss-bi",
|
||||
"action": "addToProject",
|
||||
"addToProject": {
|
||||
"url": "https://github.com/orgs/grafana/projects/72"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "area/panel/table",
|
||||
"action": "addToProject",
|
||||
"addToProject": {
|
||||
"url": "https://github.com/orgs/grafana/projects/72"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -17,13 +17,13 @@ jobs:
|
||||
id: regex-match
|
||||
with:
|
||||
text: ${{ github.event.inputs.version }}
|
||||
regex: '^(\d+.\d+).\d+(?:-beta\d+)?$'
|
||||
regex: '^(\d+.\d+).\d+(?:-(?:(beta\d+)|(pre)))?$'
|
||||
- uses: actions-ecosystem/action-regex-match@v2.0.2
|
||||
if: ${{ inputs.version_call != '' }}
|
||||
id: regex-match-version-call
|
||||
with:
|
||||
text: ${{ inputs.version_call }}
|
||||
regex: '^(\d+.\d+).\d+(?:-beta\d+)?$'
|
||||
regex: '^(\d+.\d+).\d+(?:-(?:(beta\d+)|(pre)))?$'
|
||||
- name: Validate input version
|
||||
if: ${{ steps.regex-match.outputs.match == '' && github.event.inputs.version != '' }}
|
||||
run: |
|
||||
@@ -50,7 +50,7 @@ jobs:
|
||||
echo "branch_exist=$(git ls-remote --heads https://github.com/grafana/grafana.git v${{ steps.regex-match.outputs.group1 }}.x | wc -l)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Check input version is aligned with branch(main)
|
||||
if: ${{ github.event.inputs.version != '' && steps.intermedia.outputs.branch_exist == '0' && !contains(steps.intermedia.outputs.short_ref, 'main') }}
|
||||
if: ${{ github.event.inputs.version != '' && steps.intermedia.outputs.branch_exist == '0' && !contains(github.event.inputs.version, 'pre') && !contains(steps.intermedia.outputs.short_ref, 'main') }}
|
||||
run: |
|
||||
echo "When you want to deliver a new new minor version, you might want to create a new branch first \
|
||||
with naming convention v[major].[minor].x, and just run the workflow on that branch. \
|
||||
|
||||
@@ -7,7 +7,7 @@ jobs:
|
||||
doc-validator:
|
||||
runs-on: "ubuntu-latest"
|
||||
container:
|
||||
image: "grafana/doc-validator:v1.9.0"
|
||||
image: "grafana/doc-validator:v1.10.0"
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: "actions/checkout@v3"
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ You can contribute to Grafana in several ways. Here are some examples:
|
||||
- Organize meetups and user groups in your local area.
|
||||
- Help others by answering questions about Grafana.
|
||||
|
||||
**Please note:** We do not currently accept contributions for translations. Please do not submit pull requests for messages.po files - they will be rejected.
|
||||
**Please note:** We do not currently accept contributions for translations. Please do not submit pull requests translating grafana.json files - they will be rejected. We do accept contributions to mark up phrases for translation. See [Internationalization](contribute/internationalization.md).
|
||||
|
||||
For more ways to contribute, check out the [Open Source Guides](https://opensource.guide/how-to-contribute/).
|
||||
|
||||
|
||||
@@ -143,6 +143,18 @@ test-go-integration-mysql: devenv-mysql ## Run integration tests for mysql backe
|
||||
$(GO) clean -testcache
|
||||
$(GO) list './pkg/...' | xargs -I {} sh -c 'GRAFANA_TEST_DB=mysql go test -run Integration -covermode=atomic -timeout=2m {}'
|
||||
|
||||
.PHONY: test-go-integration-redis
|
||||
test-go-integration-redis: ## Run integration tests for redis cache.
|
||||
@echo "test backend integration redis tests"
|
||||
$(GO) clean -testcache
|
||||
REDIS_URL=localhost:6379 $(GO) test -run IntegrationRedis -covermode=atomic -timeout=2m ./pkg/...
|
||||
|
||||
.PHONY: test-go-integration-memcached
|
||||
test-go-integration-memcached: ## Run integration tests for memcached cache.
|
||||
@echo "test backend integration memcached tests"
|
||||
$(GO) clean -testcache
|
||||
MEMCACHED_HOSTS=localhost:11211 $(GO) test -run IntegrationMemcached -covermode=atomic -timeout=2m ./pkg/...
|
||||
|
||||
test-js: ## Run tests for frontend.
|
||||
@echo "test frontend"
|
||||
yarn test
|
||||
|
||||
@@ -124,6 +124,7 @@ datasources:
|
||||
|
||||
- name: gdev-elasticsearch
|
||||
type: elasticsearch
|
||||
uid: gdev-elasticsearch
|
||||
access: proxy
|
||||
database: "[logs-]YYYY.MM.DD"
|
||||
url: http://localhost:9200
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,736 +0,0 @@
|
||||
{
|
||||
"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": "gdev-elasticsearch-v7-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": 1591027717495,
|
||||
"links": [
|
||||
{
|
||||
"asDropdown": true,
|
||||
"icon": "external link",
|
||||
"tags": ["gdev", "elasticsearch", "datasource-test"],
|
||||
"title": "Dashboards",
|
||||
"type": "dashboards"
|
||||
}
|
||||
],
|
||||
"panels": [
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "gdev-elasticsearch-v7-metrics",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"custom": {}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"fill": 1,
|
||||
"fillGradient": 0,
|
||||
"grid": {},
|
||||
"gridPos": {
|
||||
"h": 7,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"hiddenSeries": false,
|
||||
"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",
|
||||
"options": {
|
||||
"dataLinks": []
|
||||
},
|
||||
"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-v7-metrics",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"custom": {}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"fill": 1,
|
||||
"fillGradient": 0,
|
||||
"grid": {},
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 12,
|
||||
"x": 0,
|
||||
"y": 7
|
||||
},
|
||||
"hiddenSeries": false,
|
||||
"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",
|
||||
"options": {
|
||||
"dataLinks": []
|
||||
},
|
||||
"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-v7-metrics",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"custom": {}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"fill": 1,
|
||||
"fillGradient": 0,
|
||||
"grid": {},
|
||||
"gridPos": {
|
||||
"h": 6,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 7
|
||||
},
|
||||
"hiddenSeries": false,
|
||||
"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",
|
||||
"options": {
|
||||
"dataLinks": []
|
||||
},
|
||||
"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-v7-metrics",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"custom": {}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"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": [
|
||||
{
|
||||
"align": "auto",
|
||||
"dateFormat": "YYYY-MM-DD HH:mm:ss",
|
||||
"pattern": "@timestamp",
|
||||
"type": "date"
|
||||
},
|
||||
{
|
||||
"align": "auto",
|
||||
"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-old"
|
||||
},
|
||||
{
|
||||
"columns": [
|
||||
{
|
||||
"text": "@timestamp",
|
||||
"value": "@timestamp"
|
||||
},
|
||||
{
|
||||
"text": "@message",
|
||||
"value": "@message"
|
||||
},
|
||||
{
|
||||
"text": "tags",
|
||||
"value": "tags"
|
||||
},
|
||||
{
|
||||
"text": "description",
|
||||
"value": "description"
|
||||
}
|
||||
],
|
||||
"datasource": "gdev-elasticsearch-v7-logs",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"custom": {}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"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": [
|
||||
{
|
||||
"align": "auto",
|
||||
"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-old"
|
||||
},
|
||||
{
|
||||
"circleMaxSize": 30,
|
||||
"circleMinSize": 2,
|
||||
"colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"],
|
||||
"datasource": "gdev-elasticsearch-v7-metrics",
|
||||
"decimals": 0,
|
||||
"esGeoPoint": "@location",
|
||||
"esMetric": "Average",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"custom": {}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 12,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 27
|
||||
},
|
||||
"hideEmpty": false,
|
||||
"hideZero": false,
|
||||
"id": 8,
|
||||
"initialZoom": "1",
|
||||
"links": [],
|
||||
"locationData": "geohash",
|
||||
"mapCenter": "(0°, 0°)",
|
||||
"mapCenterLatitude": 0,
|
||||
"mapCenterLongitude": 0,
|
||||
"maxDataPoints": 1,
|
||||
"mouseWheelZoom": false,
|
||||
"showLegend": true,
|
||||
"stickyLabels": false,
|
||||
"tableQueryOptions": {
|
||||
"geohashField": "geohash",
|
||||
"latitudeField": "latitude",
|
||||
"longitudeField": "longitude",
|
||||
"metricField": "metric",
|
||||
"queryType": "geohash"
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"bucketAggs": [
|
||||
{
|
||||
"fake": true,
|
||||
"field": "@location",
|
||||
"id": "3",
|
||||
"settings": {
|
||||
"precision": 2
|
||||
},
|
||||
"type": "geohash_grid"
|
||||
}
|
||||
],
|
||||
"metrics": [
|
||||
{
|
||||
"field": "@value",
|
||||
"id": "1",
|
||||
"meta": {},
|
||||
"settings": {},
|
||||
"type": "avg"
|
||||
}
|
||||
],
|
||||
"refId": "A",
|
||||
"target": "",
|
||||
"timeField": "@timestamp"
|
||||
}
|
||||
],
|
||||
"thresholds": "0,10",
|
||||
"title": "World map panel",
|
||||
"type": "grafana-worldmap-panel",
|
||||
"unitPlural": "",
|
||||
"unitSingle": "",
|
||||
"valueName": "total"
|
||||
}
|
||||
],
|
||||
"schemaVersion": 25,
|
||||
"style": "dark",
|
||||
"tags": ["elasticsearch", "gdev", "datasource-test"],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"datasource": "gdev-elasticsearch-v7-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 v7",
|
||||
"uid": "Y-RvmuRWk",
|
||||
"version": 1
|
||||
}
|
||||
@@ -1,241 +0,0 @@
|
||||
{
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": "-- Grafana --",
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"gnetId": null,
|
||||
"graphTooltip": 0,
|
||||
"iteration": 1591027736516,
|
||||
"links": [
|
||||
{
|
||||
"asDropdown": true,
|
||||
"icon": "external link",
|
||||
"tags": ["gdev", "elasticsearch", "datasource-test"],
|
||||
"title": "Dashboards",
|
||||
"type": "dashboards"
|
||||
}
|
||||
],
|
||||
"panels": [
|
||||
{
|
||||
"aliasColors": {
|
||||
"error": "red"
|
||||
},
|
||||
"bars": true,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "gdev-elasticsearch-v7-filebeat",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"custom": {}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"fill": 1,
|
||||
"fillGradient": 0,
|
||||
"gridPos": {
|
||||
"h": 5,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"hiddenSeries": false,
|
||||
"id": 4,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
"max": false,
|
||||
"min": false,
|
||||
"show": true,
|
||||
"total": false,
|
||||
"values": false
|
||||
},
|
||||
"lines": false,
|
||||
"linewidth": 1,
|
||||
"nullPointMode": "null",
|
||||
"options": {
|
||||
"dataLinks": []
|
||||
},
|
||||
"percentage": false,
|
||||
"pointradius": 2,
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"stack": true,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"bucketAggs": [
|
||||
{
|
||||
"fake": true,
|
||||
"field": "fields.level",
|
||||
"id": "3",
|
||||
"settings": {
|
||||
"min_doc_count": 1,
|
||||
"order": "desc",
|
||||
"orderBy": "_term",
|
||||
"size": "10"
|
||||
},
|
||||
"type": "terms"
|
||||
},
|
||||
{
|
||||
"field": "@timestamp",
|
||||
"id": "2",
|
||||
"settings": {
|
||||
"interval": "5m",
|
||||
"min_doc_count": 1,
|
||||
"trimEdges": 0
|
||||
},
|
||||
"type": "date_histogram"
|
||||
}
|
||||
],
|
||||
"metrics": [
|
||||
{
|
||||
"field": "select field",
|
||||
"id": "1",
|
||||
"type": "count"
|
||||
}
|
||||
],
|
||||
"query": "fields.app:grafana",
|
||||
"refId": "A",
|
||||
"timeField": "@timestamp"
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeRegions": [],
|
||||
"timeShift": null,
|
||||
"title": "Panel Title",
|
||||
"tooltip": {
|
||||
"shared": true,
|
||||
"sort": 0,
|
||||
"value_type": "individual"
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
"format": "short",
|
||||
"label": null,
|
||||
"logBase": 1,
|
||||
"max": null,
|
||||
"min": null,
|
||||
"show": true
|
||||
},
|
||||
{
|
||||
"format": "short",
|
||||
"label": null,
|
||||
"logBase": 1,
|
||||
"max": null,
|
||||
"min": null,
|
||||
"show": true
|
||||
}
|
||||
],
|
||||
"yaxis": {
|
||||
"align": false,
|
||||
"alignLevel": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"datasource": "gdev-elasticsearch-v7-filebeat",
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"custom": {}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 22,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"y": 5
|
||||
},
|
||||
"id": 2,
|
||||
"links": [],
|
||||
"options": {
|
||||
"showLabels": false,
|
||||
"showTime": true,
|
||||
"sortOrder": "Descending",
|
||||
"wrapLogMessage": true
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"bucketAggs": [
|
||||
{
|
||||
"$$hashKey": "object:522",
|
||||
"field": "@timestamp",
|
||||
"id": "2",
|
||||
"settings": {
|
||||
"interval": "auto",
|
||||
"min_doc_count": 0,
|
||||
"trimEdges": 0
|
||||
},
|
||||
"type": "date_histogram"
|
||||
}
|
||||
],
|
||||
"metrics": [
|
||||
{
|
||||
"$$hashKey": "object:484",
|
||||
"field": "select field",
|
||||
"id": "1",
|
||||
"meta": {},
|
||||
"settings": {},
|
||||
"type": "logs"
|
||||
}
|
||||
],
|
||||
"query": "fields.app:grafana",
|
||||
"refId": "A",
|
||||
"timeField": "@timestamp"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Panel Title",
|
||||
"type": "logs"
|
||||
}
|
||||
],
|
||||
"schemaVersion": 25,
|
||||
"style": "dark",
|
||||
"tags": ["elasticsearch", "gdev", "datasource-test"],
|
||||
"templating": {
|
||||
"list": [
|
||||
{
|
||||
"datasource": "gdev-elasticsearch-v7-filebeat",
|
||||
"filters": [],
|
||||
"hide": 0,
|
||||
"label": "",
|
||||
"name": "Filters",
|
||||
"skipUrlSync": false,
|
||||
"type": "adhoc"
|
||||
}
|
||||
]
|
||||
},
|
||||
"time": {
|
||||
"from": "now-1h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {
|
||||
"refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"],
|
||||
"time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"]
|
||||
},
|
||||
"timezone": "",
|
||||
"title": "Datasource tests - Elasticsearch v7 Filebeat",
|
||||
"uid": "M94gguRWz",
|
||||
"version": 1
|
||||
}
|
||||
@@ -3,7 +3,10 @@
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": "-- Grafana --",
|
||||
"datasource": {
|
||||
"type": "datasource",
|
||||
"uid": "grafana"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
@@ -13,17 +16,69 @@
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"gnetId": null,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"panels": [
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"fill": 0,
|
||||
"fillGradient": 6,
|
||||
"datasource": {
|
||||
"type": "testdata",
|
||||
"uid": "PD8C576611E62080A"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 60,
|
||||
"gradientMode": "opacity",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 6,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "always",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"links": [],
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "short"
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 15,
|
||||
"w": 12,
|
||||
@@ -31,89 +86,79 @@
|
||||
"y": 0
|
||||
},
|
||||
"id": 2,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
"max": false,
|
||||
"min": false,
|
||||
"show": true,
|
||||
"total": false,
|
||||
"values": false
|
||||
},
|
||||
"lines": true,
|
||||
"linewidth": 1,
|
||||
"nullPointMode": "null",
|
||||
"options": {
|
||||
"dataLinks": []
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "multi",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"percentage": false,
|
||||
"pointradius": 2,
|
||||
"points": true,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"pluginVersion": "9.5.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "testdata",
|
||||
"uid": "PD8C576611E62080A"
|
||||
},
|
||||
"refId": "A",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "1,20,90,30,5,0,100"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "testdata",
|
||||
"uid": "PD8C576611E62080A"
|
||||
},
|
||||
"refId": "B",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "1,20,90,30,5,-100,200"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "testdata",
|
||||
"uid": "PD8C576611E62080A"
|
||||
},
|
||||
"refId": "C",
|
||||
"scenarioId": "csv_metric_values",
|
||||
"stringInput": "2.5,3.5,4.5,10.5,20.5,21.5,19.5"
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeRegions": [],
|
||||
"timeShift": null,
|
||||
"title": "Raw Data Graph",
|
||||
"tooltip": {
|
||||
"shared": true,
|
||||
"sort": 0,
|
||||
"value_type": "individual"
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
"format": "short",
|
||||
"label": null,
|
||||
"logBase": 1,
|
||||
"max": null,
|
||||
"min": null,
|
||||
"show": true
|
||||
},
|
||||
{
|
||||
"format": "short",
|
||||
"label": null,
|
||||
"logBase": 1,
|
||||
"max": null,
|
||||
"min": null,
|
||||
"show": true
|
||||
}
|
||||
],
|
||||
"yaxis": {
|
||||
"align": false,
|
||||
"alignLevel": null
|
||||
}
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": "-- Dashboard --",
|
||||
"datasource": {
|
||||
"type": "datasource",
|
||||
"uid": "-- Dashboard --"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 5,
|
||||
"w": 12,
|
||||
@@ -122,44 +167,59 @@
|
||||
},
|
||||
"id": 4,
|
||||
"options": {
|
||||
"fieldOptions": {
|
||||
"calcs": ["lastNotNull"],
|
||||
"defaults": {
|
||||
"mappings": [],
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"thresholds": [
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"lastNotNull"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": true
|
||||
},
|
||||
"pluginVersion": "9.5.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "datasource",
|
||||
"uid": "-- Dashboard --"
|
||||
},
|
||||
"panelId": 2,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Last non-null",
|
||||
"type": "gauge"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "datasource",
|
||||
"uid": "-- Dashboard --"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"override": {},
|
||||
"values": false
|
||||
}
|
||||
},
|
||||
"orientation": "auto",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": true
|
||||
"overrides": []
|
||||
},
|
||||
"pluginVersion": "6.4.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"panelId": 2,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Last non-null",
|
||||
"type": "gauge"
|
||||
},
|
||||
{
|
||||
"datasource": "-- Dashboard --",
|
||||
"gridPos": {
|
||||
"h": 5,
|
||||
"w": 12,
|
||||
@@ -168,63 +228,49 @@
|
||||
},
|
||||
"id": 6,
|
||||
"options": {
|
||||
"fieldOptions": {
|
||||
"calcs": ["min"],
|
||||
"defaults": {
|
||||
"mappings": [],
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"thresholds": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"override": {},
|
||||
"orientation": "auto",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"min"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"orientation": "auto",
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": true
|
||||
},
|
||||
"pluginVersion": "6.4.0-pre",
|
||||
"pluginVersion": "9.5.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "datasource",
|
||||
"uid": "-- Dashboard --"
|
||||
},
|
||||
"panelId": 2,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "min",
|
||||
"type": "gauge"
|
||||
},
|
||||
{
|
||||
"datasource": "-- Dashboard --",
|
||||
"gridPos": {
|
||||
"h": 5,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 10
|
||||
"datasource": {
|
||||
"type": "datasource",
|
||||
"uid": "-- Dashboard --"
|
||||
},
|
||||
"id": 5,
|
||||
"options": {
|
||||
"displayMode": "basic",
|
||||
"fieldOptions": {
|
||||
"calcs": ["max"],
|
||||
"defaults": {
|
||||
"mappings": [],
|
||||
"max": 200,
|
||||
"min": 0,
|
||||
"thresholds": [
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"mappings": [],
|
||||
"max": 200,
|
||||
"min": 0,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "blue",
|
||||
@@ -235,28 +281,102 @@
|
||||
"value": 120
|
||||
}
|
||||
]
|
||||
},
|
||||
"override": {},
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 5,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 10
|
||||
},
|
||||
"id": 5,
|
||||
"options": {
|
||||
"displayMode": "basic",
|
||||
"minVizHeight": 10,
|
||||
"minVizWidth": 0,
|
||||
"orientation": "vertical",
|
||||
"reduceOptions": {
|
||||
"calcs": [
|
||||
"max"
|
||||
],
|
||||
"fields": "",
|
||||
"values": false
|
||||
},
|
||||
"orientation": "vertical"
|
||||
"showUnfilled": true,
|
||||
"valueMode": "color"
|
||||
},
|
||||
"pluginVersion": "6.4.0-pre",
|
||||
"pluginVersion": "9.5.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "datasource",
|
||||
"uid": "-- Dashboard --"
|
||||
},
|
||||
"panelId": 2,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Max",
|
||||
"type": "bargauge"
|
||||
},
|
||||
{
|
||||
"columns": [],
|
||||
"datasource": "-- Dashboard --",
|
||||
"fontSize": "100%",
|
||||
"datasource": {
|
||||
"type": "datasource",
|
||||
"uid": "-- Dashboard --"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "thresholds"
|
||||
},
|
||||
"custom": {
|
||||
"align": "auto",
|
||||
"cellOptions": {
|
||||
"type": "auto"
|
||||
},
|
||||
"inspect": false
|
||||
},
|
||||
"decimals": 2,
|
||||
"displayName": "",
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
},
|
||||
"unit": "short"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"matcher": {
|
||||
"id": "byName",
|
||||
"options": "Time"
|
||||
},
|
||||
"properties": [
|
||||
{
|
||||
"id": "displayName",
|
||||
"value": "Time"
|
||||
},
|
||||
{
|
||||
"id": "unit",
|
||||
"value": "time: YYYY-MM-DD HH:mm:ss"
|
||||
},
|
||||
{
|
||||
"id": "custom.align"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 10,
|
||||
"w": 24,
|
||||
@@ -264,47 +384,49 @@
|
||||
"y": 15
|
||||
},
|
||||
"id": 8,
|
||||
"options": {},
|
||||
"pageSize": null,
|
||||
"showHeader": true,
|
||||
"sort": {
|
||||
"col": 0,
|
||||
"desc": true
|
||||
},
|
||||
"styles": [
|
||||
{
|
||||
"alias": "Time",
|
||||
"dateFormat": "YYYY-MM-DD HH:mm:ss",
|
||||
"pattern": "Time",
|
||||
"type": "date"
|
||||
"options": {
|
||||
"cellHeight": "sm",
|
||||
"footer": {
|
||||
"countRows": false,
|
||||
"fields": "",
|
||||
"reducer": [
|
||||
"sum"
|
||||
],
|
||||
"show": false
|
||||
},
|
||||
{
|
||||
"alias": "",
|
||||
"colorMode": null,
|
||||
"colors": ["rgba(245, 54, 54, 0.9)", "rgba(237, 129, 40, 0.89)", "rgba(50, 172, 45, 0.97)"],
|
||||
"decimals": 2,
|
||||
"pattern": "/.*/",
|
||||
"thresholds": [],
|
||||
"type": "number",
|
||||
"unit": "short"
|
||||
}
|
||||
],
|
||||
"showHeader": true,
|
||||
"showRowNums": false
|
||||
},
|
||||
"pluginVersion": "9.5.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "datasource",
|
||||
"uid": "-- Dashboard --"
|
||||
},
|
||||
"panelId": 2,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Panel Title",
|
||||
"transform": "timeseries_to_columns",
|
||||
"title": "The data from graph above with seriesToColumns transform",
|
||||
"transformations": [
|
||||
{
|
||||
"id": "seriesToColumns",
|
||||
"options": {
|
||||
"reducers": []
|
||||
}
|
||||
}
|
||||
],
|
||||
"type": "table"
|
||||
}
|
||||
],
|
||||
"schemaVersion": 19,
|
||||
"refresh": "",
|
||||
"schemaVersion": 38,
|
||||
"style": "dark",
|
||||
"tags": ["gdev", "datasource-test"],
|
||||
"tags": [
|
||||
"gdev",
|
||||
"datasource-test"
|
||||
],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
@@ -313,10 +435,22 @@
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {
|
||||
"refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"]
|
||||
"refresh_intervals": [
|
||||
"5s",
|
||||
"10s",
|
||||
"30s",
|
||||
"1m",
|
||||
"5m",
|
||||
"15m",
|
||||
"30m",
|
||||
"1h",
|
||||
"2h",
|
||||
"1d"
|
||||
]
|
||||
},
|
||||
"timezone": "",
|
||||
"title": "Datasource tests - Shared Queries",
|
||||
"uid": "ZqZnVvFZz",
|
||||
"version": 10
|
||||
}
|
||||
"version": 8,
|
||||
"weekStart": ""
|
||||
}
|
||||
@@ -81,6 +81,18 @@ async function elasticSetupIndexTemplate() {
|
||||
},
|
||||
shapes: {
|
||||
type: 'nested',
|
||||
},
|
||||
hostname: {
|
||||
type: 'keyword',
|
||||
},
|
||||
value: {
|
||||
type: 'integer',
|
||||
},
|
||||
metric: {
|
||||
type: 'keyword',
|
||||
},
|
||||
description: {
|
||||
type: 'text',
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -119,6 +131,10 @@ function getRandomLogItem(counter, timestamp) {
|
||||
{"type": "triangle"},
|
||||
{"type": "square"},
|
||||
],
|
||||
hostname: chooseRandomElement(['hostname1', 'hostname2', 'hostname3', 'hostname4', 'hostname5', 'hostname6']),
|
||||
value: counter,
|
||||
metric: chooseRandomElement(['cpu', 'memory', 'latency']),
|
||||
description: "this is description"
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -163,21 +163,21 @@ local dashboard = grafana.dashboard;
|
||||
id: 0,
|
||||
}
|
||||
},
|
||||
dashboard.new('elasticsearch_compare', import '../dev-dashboards/datasource-elasticsearch/elasticsearch_compare.json') +
|
||||
dashboard.new('elasticsearch_complex', import '../dev-dashboards/datasource-elasticsearch/elasticsearch_complex.json') +
|
||||
resource.addMetadata('folder', 'dev-dashboards') +
|
||||
{
|
||||
spec+: {
|
||||
id: 0,
|
||||
}
|
||||
},
|
||||
dashboard.new('elasticsearch_v7', import '../dev-dashboards/datasource-elasticsearch/elasticsearch_v7.json') +
|
||||
dashboard.new('elasticsearch_migration', import '../dev-dashboards/datasource-elasticsearch/elasticsearch_migration.json') +
|
||||
resource.addMetadata('folder', 'dev-dashboards') +
|
||||
{
|
||||
spec+: {
|
||||
id: 0,
|
||||
}
|
||||
},
|
||||
dashboard.new('elasticsearch_v7_filebeat', import '../dev-dashboards/datasource-elasticsearch/elasticsearch_v7_filebeat.json') +
|
||||
dashboard.new('elasticsearch_simple', import '../dev-dashboards/datasource-elasticsearch/elasticsearch_simple.json') +
|
||||
resource.addMetadata('folder', 'dev-dashboards') +
|
||||
{
|
||||
spec+: {
|
||||
|
||||
@@ -46,7 +46,8 @@ By default, data sources in an organization can be queried by any user in that o
|
||||
|
||||
You can assign data source permissions to users, teams, and roles which will allow access to query or edit the data source.
|
||||
|
||||
1. Navigate to **Administration > Data sources**.
|
||||
1. Click **Connections** in the left-side menu.
|
||||
1. Under Your connections, click **Data sources**.
|
||||
1. Select the data source to which you want to assign permissions.
|
||||
1. On the Permissions tab, click **Add a permission**.
|
||||
1. Select **User**, **Team**, or **Role**.
|
||||
@@ -58,7 +59,8 @@ You can assign data source permissions to users, teams, and roles which will all
|
||||
|
||||
### Edit data source permissions for users, teams, or roles
|
||||
|
||||
1. Navigate to **Administration > Data sources**.
|
||||
1. Click **Connections** in the left-side menu.
|
||||
1. Under Your connections, click **Data sources**.
|
||||
1. Select the data source for which you want to edit permissions.
|
||||
1. On the Permissions tab, find the user, team, or role permission you want to update.
|
||||
1. Select a different option in the **Permission** dropdown.
|
||||
@@ -67,7 +69,8 @@ You can assign data source permissions to users, teams, and roles which will all
|
||||
|
||||
### Remove data source permissions for users, teams, or roles
|
||||
|
||||
1. Navigate to **Administration > Data sources**.
|
||||
1. Click **Connections** in the left-side menu.
|
||||
1. Under Your connections, click **Data sources**.
|
||||
1. Select the data source from which you want to remove permissions.
|
||||
1. On the Permissions tab, find the user, team, or role permission you want to remove.
|
||||
1. Click the **X** next to the permission.
|
||||
@@ -122,9 +125,10 @@ You must be an Org admin or Grafana admin to enable query caching for a data sou
|
||||
|
||||
By default, data source queries are not cached. To enable query caching for a single data source:
|
||||
|
||||
1. On the left-side menu, click **Administration > Data sources**.
|
||||
1. Click **Connections** in the left-side menu.
|
||||
1. Under Your Connections, click **Data sources**.
|
||||
1. In the data source list, click the data source that you want to turn on caching for.
|
||||
1. Open the Cache tab.
|
||||
1. Go to the Cache tab.
|
||||
1. Click **Enable**.
|
||||
1. (Optional) Choose custom TTLs for the data source's queries and resources caching. If you skip this step, then Grafana uses the default TTL.
|
||||
|
||||
@@ -140,9 +144,10 @@ To configure global settings for query caching, refer to the [Query caching sect
|
||||
|
||||
To disable query caching for a single data source:
|
||||
|
||||
1. On the left-side menu, click **Administration > Data sources**.
|
||||
1. Click **Connections** in the left-side menu.
|
||||
1. Under Your Connections, click **Data sources**.
|
||||
1. In the data source list, click the data source that you want to turn off caching for.
|
||||
1. In the Cache tab, click **Disable**.
|
||||
1. On the Cache tab, click **Disable**.
|
||||
|
||||
To disable query caching for an entire Grafana instance, set the `enabled` flag to `false` in the [Query caching section of Enterprise Configuration]({{< relref "../../setup-grafana/configure-grafana/enterprise-configuration/#caching" >}}). You will no longer see the Cache tab on any data sources, and no data source queries will be cached.
|
||||
|
||||
@@ -152,7 +157,8 @@ If you experience performance issues or repeated queries become slower to execut
|
||||
|
||||
> **Note:** This action impacts all cache-enabled data sources. If you are using Memcached, the system clears all data from the Memcached instance.
|
||||
|
||||
1. On the left-side menu, click **Administration > Data sources**.
|
||||
1. Click **Connections** in the left-side menu.
|
||||
1. Under Your Connections, click **Data sources**.
|
||||
1. In the data source list, click the data source that you want to clear the cache for.
|
||||
1. In the Cache tab, click **Clear cache**.
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ Before following the steps below, make sure you are logged in as a Grafana admin
|
||||
|
||||
<a id="#plugin-catalog-entry"></a>
|
||||
|
||||
- Administrators can find the Plugin catalog at **Configuration > Plugins**.
|
||||
- Administrators can find the Plugin catalog at **Administration > Plugins**.
|
||||
|
||||
### Browse plugins
|
||||
|
||||
|
||||
+1
@@ -207,3 +207,4 @@ The following list contains role-based access control scopes.
|
||||
| `settings:*` | Restrict an action to a subset of settings. For example, `settings:*` matches all settings, `settings:auth.saml:*` matches all SAML settings, and `settings:auth.saml:enabled` matches the enable property on the SAML settings. |
|
||||
| `teams:*` <br> `teams:id:*` | Restrict an action to a set of teams from an organization. For example, `teams:*` matches any team and `teams:id:1` matches the team whose ID is `1`. |
|
||||
| `users:*` <br> `users:id:*` | Restrict an action to a set of users from an organization. For example, `users:*` matches any user and `users:id:1` matches the user whose ID is `1`. |
|
||||
| `n/a` | `n/a` means not applicable. If an action has `n/a` specified for the scope, then the action does not require a scope. For example, the `teams:create` action does not require a scope and allows users to create teams. |
|
||||
|
||||
+10
@@ -71,6 +71,16 @@ The name of the annotation is {{ .Name }}, and the value is {{ .Value }}
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
## The index function
|
||||
|
||||
To print a specific annotation or label use the `index` function.
|
||||
|
||||
```
|
||||
{{ range .Alerts }}
|
||||
The name of the alert is {{ index .Labels "alertname" }}
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
## If statements
|
||||
|
||||
You can use if statements in templates. For example, to print `There are no alerts` if there are no alerts in `.Alerts` you would write the following:
|
||||
|
||||
@@ -25,8 +25,8 @@ When you create a library panel, the panel on the source dashboard is converted
|
||||
|
||||
1. Open a panel in edit mode.
|
||||
1. In the panel display options, click the down arrow option to bring changes to the visualization.
|
||||
{{< figure src="/static/img/docs/library-panels/create-lib-panel-from-edit-8-0.png" class="docs-image--no-shadow" max-width= "800px" caption="Screenshot of the edit panel" >}}
|
||||
1. Click the **Library panels** option, and then click **Create library panel** to open the create dialog.
|
||||
{{< figure src="/media/docs/grafana/panels-visualizations/screenshot-create-lib-panel-from-edit-9-5.png" class="docs-image--no-shadow" max-width= "800px" >}}
|
||||
1. Click **Library panels**, and then click **+ Create library panel** to open the create dialog.
|
||||
1. In **Library panel name**, enter the name.
|
||||
1. In **Save in folder**, select the folder to save the library panel.
|
||||
1. Click **Create library panel** to save your changes.
|
||||
@@ -34,14 +34,16 @@ When you create a library panel, the panel on the source dashboard is converted
|
||||
|
||||
Once created, you can modify the library panel using any dashboard on which it appears. After you save the changes, all instances of the library panel reflect these modifications.
|
||||
|
||||
{{< figure src="/static/img/docs/library-panels/create-from-more-8-0.png" class="docs-image--no-shadow" max-width= "900px" caption="Screenshot of the edit panel" >}}
|
||||
You can also create a library panel directly from the edit menu of any panel.
|
||||
|
||||
{{< figure src="/media/docs/grafana/panels-visualizations/screenshot-create-from-more-9-5.png" class="docs-image--no-shadow" max-width= "900px" >}}
|
||||
|
||||
## Add a library panel to a dashboard
|
||||
|
||||
Add a Grafana library panel to a dashboard when you want to provide visualizations to other dashboard users.
|
||||
|
||||
1. Click **Dashboards** in the left-side menu.
|
||||
1. Click **New** and select **New Dashboard**.
|
||||
1. Click **New** and select **New Dashboard** in the dropdown.
|
||||
1. On the empty dashboard, click **+ Import library panel**.
|
||||
|
||||
You will see a list of your library panels.
|
||||
@@ -60,6 +62,7 @@ Unlink a library panel when you want to make a change to the panel and not affec
|
||||
1. Hover over any part of the panel to display the actions menu on the top right corner.
|
||||
1. Click the menu and select **Edit**.
|
||||
1. Click **Unlink** on the top right corner of the page.
|
||||
1. Click **Yes, unlink**.
|
||||
|
||||
## View a list of library panels
|
||||
|
||||
@@ -69,7 +72,7 @@ You can view a list of available library panels and search for a library panel.
|
||||
1. Click **Library panels**.
|
||||
|
||||
You can see a list of previously defined library panels.
|
||||
{{< figure src="/static/img/docs/library-panels/library-panel-list-8-0.png" class="docs-image--no-shadow" max-width= "900px" caption="Screenshot of the edit panel" >}}
|
||||
{{< figure src="/media/docs/grafana/panels-visualizations/screenshot-library-panel-list-9-5.png" class="docs-image--no-shadow" max-width= "900px" >}}
|
||||
|
||||
1. Search for a specific library panel if you know its name.
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ weight: 400
|
||||
|
||||
Whenever you save a version of your dashboard, a copy of that version is saved so that previous versions of your dashboard are never lost. A list of these versions is available by entering the dashboard settings and then selecting "Versions" in the left side menu.
|
||||
|
||||
<img class="no-shadow" src="/static/img/docs/v50/dashboard_versions_list.png">
|
||||

|
||||
|
||||
The dashboard version history feature lets you compare and restore to previously saved dashboard versions.
|
||||
|
||||
@@ -25,20 +25,18 @@ The dashboard version history feature lets you compare and restore to previously
|
||||
|
||||
To compare two dashboard versions, select the two versions from the list that you wish to compare. Once selected, the "Compare versions" button will become clickable. Click the button to view the diff between the two versions.
|
||||
|
||||
<img class="no-shadow" src="/static/img/docs/v50/dashboard_versions_select.png">
|
||||

|
||||
|
||||
Upon clicking the button, you'll be brought to the diff view. By default, you'll see a textual summary of the changes, like in the image below.
|
||||
|
||||
<img class="no-shadow" src="/static/img/docs/v50/dashboard_versions_diff_basic.png">
|
||||

|
||||
|
||||
If you want to view the diff of the raw JSON that represents your dashboard, you can do that as well by clicking the "View JSON Diff" button at the bottom.
|
||||
|
||||
If you want to restore to the version you are diffing against, you can do so by clicking the "Restore to version \<x\>" button in the top right.
|
||||
If you want to view the diff of the raw JSON that represents your dashboard, you can do that as well by clicking the expand icon for the View JSON Diff section at the bottom.
|
||||
|
||||
## Restoring to a previously saved dashboard version
|
||||
|
||||
If you need to restore to a previously saved dashboard version, you can do so by either clicking the "Restore" button on the right of a row in the dashboard version list, or by clicking the "Restore to version \<x\>" button appearing in the diff view. Clicking the button will bring up the following popup prompting you to confirm the restoration.
|
||||
If you need to restore to a previously saved dashboard version, you can do so by either clicking the "Restore" button on the right of a row in the dashboard version list, or by clicking the **Restore to version \<x\>** button appearing in the diff view. Clicking the button will bring up the following popup prompting you to confirm the restoration.
|
||||
|
||||
<img class="no-shadow" src="/static/img/docs/v50/dashboard_versions_restore.png">
|
||||

|
||||
|
||||
After restoring to a previous version, a new version will be created containing the same exact data as the previous version, only with a different version number. This is indicated in the "Notes column" for the row in the new dashboard version. This is done simply to ensure your previous dashboard versions are not affected by the change.
|
||||
|
||||
@@ -26,21 +26,22 @@ Use the information in this section to access existing playlists. Start and cont
|
||||
|
||||
### Access a playlist
|
||||
|
||||
1. Hover your cursor over Grafana’s side menu.
|
||||
1. Click **Playlists**. You will see a list of existing playlists.
|
||||
1. Click **Dashboards** in the left-side menu.
|
||||
1. Click **Playlists** to see a list of existing playlists.
|
||||
|
||||
### Start a playlist
|
||||
|
||||
You can start a playlist in five different view modes. View mode determine how the menus and navigation bar appear on the dashboards.
|
||||
You can start a playlist in five different view modes. View modes determine how the menus and navigation bar appear on the dashboards.
|
||||
|
||||
By default, each dashboard is displayed for the amount of time entered in the Interval field, which you set when you create or edit a playlist. After you start a playlist, you can control it with the navbar at the top of the page.
|
||||
|
||||
1. [Access](#access-playlist) the playlist page to see a list of existing playlists.
|
||||
1. Find the playlist you want to start, then click **Start playlist**. The start playlist dialog opens.
|
||||
1. Select one of the five playlist modes available based on the information in the following table.
|
||||
1. Click **Start <playlist name>**.
|
||||
1. Click **Dashboards** in the left-side menu.
|
||||
1. Click **Playlists** to see a list of existing playlists.
|
||||
1. Find the playlist you want to start, then click **Start playlist**.
|
||||
1. In the modal that opens, select one of the five playlist modes available, based on the information in the table below.
|
||||
1. Click **Start \<playlist name\>**.
|
||||
|
||||
The playlist displays each dashboard for the time specified in the `Interval` field, set when creating or editing a playlist. Once a playlist starts, you can [control](#control-a-playlist) it using the navbar at the top of your screen.
|
||||
The playlist displays each dashboard for the time specified in the **Interval** field, set when creating or editing a playlist. Once a playlist starts, you can [control](#control-a-playlist) it using the navbar at the top of your screen.
|
||||
|
||||
| Mode | Description |
|
||||
| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
@@ -67,7 +68,9 @@ You can control a playlist in **Normal** or **TV** mode after it's started, usin
|
||||
|
||||
You can create a playlist to present dashboards in a sequence, with a set order and time interval between dashboards.
|
||||
|
||||
1. In the playlist page, click **New playlist**. The New playlist page opens.
|
||||
1. Click **Dashboards** in the left-side menu.
|
||||
1. Click **Playlists** to see a list of existing playlists.
|
||||
1. Click **New playlist**. The New playlist page opens.
|
||||
1. In the **Name** text box, enter a descriptive name.
|
||||
1. In the **Interval** text box, enter a time interval. Grafana displays a particular dashboard for the interval of time specified here before moving on to the next dashboard.
|
||||
1. In Dashboards, add existing dashboards to the playlist using **Add by title** and **Add by tag** drop-down options. The dashboards you add are listed in a sequential order.
|
||||
@@ -82,8 +85,8 @@ You can create a playlist to present dashboards in a sequence, with a set order
|
||||
|
||||
You can save a playlist and add it to your **Playlists** page, where you can start it. Be sure that all the dashboards you want to appear in your playlist are added when creating or editing the playlist before saving it.
|
||||
|
||||
1. To access the Playlist feature, hover your cursor over Grafana's side menu.
|
||||
1. Click **Playlists**.
|
||||
1. Click **Dashboards** in the left-side menu.
|
||||
1. Click **Playlists** to see a list of existing playlists.
|
||||
1. Click on the playlist.
|
||||
1. Edit the playlist.
|
||||
1. Ensure that your playlist has a **Name**, **Interval**, and at least one **Dashboard** added to it.
|
||||
@@ -95,36 +98,47 @@ You can edit a playlist by updating its name, interval time, and by adding, remo
|
||||
|
||||
### Edit a playlist
|
||||
|
||||
1. In the playlist page, click **Edit playlist**. The Edit playlist page opens.
|
||||
1. Click **Dashboards** in the left-side menu.
|
||||
1. Click **Playlists** to see a list of existing playlists.
|
||||
1. Find the playlist you want to update and click **Edit playlist**.
|
||||
1. Update the name and time interval, then add or remove dashboards from the playlist using instructions in [Create a playlist](#create-a-playlist).
|
||||
1. Click **Save** to save your changes.
|
||||
|
||||
### Delete a playlist
|
||||
|
||||
1. Click **Playlists**.
|
||||
1. Next to the Playlist you want to delete, click **Remove[x]**.
|
||||
1. Click **Dashboards** in the left-side menu.
|
||||
1. Click **Playlists** to see a list of existing playlists.
|
||||
1. Find the playlist you want to remove.
|
||||
1. Click **Delete playlist**.
|
||||
|
||||
### Rearrange dashboard order
|
||||
|
||||
1. Next to the dashboard you want to move, click the up or down arrow.
|
||||
1. Click **Dashboards** in the left-side menu.
|
||||
1. Click **Playlists** to see a list of existing playlists.
|
||||
1. Find the playlist you want to update and click **Edit playlist**.
|
||||
1. Click and drag the dashboards into your desired order.
|
||||
1. Click **Save** to save your changes.
|
||||
|
||||
### Remove a dashboard
|
||||
|
||||
1. Click **Remove[x]** to remove a dashboard from the playlist.
|
||||
1. Click **Dashboards** in the left-side menu.
|
||||
1. Click **Playlists** to see a list of existing playlists.
|
||||
1. Find the playlist you want to update and click **Edit playlist**.
|
||||
1. Click **\[x\]** on the name of the dashboard you want to remove from the playlist.
|
||||
1. Click **Save** to save your changes.
|
||||
|
||||
## Share a playlist in a view mode
|
||||
|
||||
You can share a playlist by copying the link address on the view mode you prefer, and pasting the URL to your destination.
|
||||
|
||||
1. From the Dashboards submenu, click **Playlists**.
|
||||
1. Next to the playlist you want to share, click **Start playlist**.
|
||||
1. In the dropdown, right click the view mode you prefer.
|
||||
1. Click **Copy Link Address** to copy the URL to your clipboard.
|
||||
1. Click **Dashboards** in the left-side menu.
|
||||
1. Click **Playlists** to see a list of existing playlists.
|
||||
1. Click the share icon of the playlist you want to share.
|
||||
1. Select the view mode you prefer.
|
||||
1. Click **Copy** next to the Link URL to copy it to your clipboard.
|
||||
|
||||
Example: The URL for the first playlist on the Grafana Play site in Kiosk mode will look like this:
|
||||
For example, the URL for the first playlist on the Grafana Play site in Kiosk mode will look like this:
|
||||
|
||||
[https://play.grafana.org/playlists/play/1?kiosk](https://play.grafana.org/playlists/play/1?kiosk).
|
||||
[https://play.grafana.org/playlists/play/1?kiosk](https://play.grafana.org/playlists/play/1?kiosk).
|
||||
|
||||
1. Paste the URL to your destination.
|
||||
1. Paste the URL to your destination.
|
||||
|
||||
@@ -48,14 +48,16 @@ Folders help you organize and group dashboards, which is useful when you have ma
|
||||
|
||||
**To create a dashboard folder:**
|
||||
|
||||
1. Sign in to Grafana and on the side menu, click **Dashboards > New folder**.
|
||||
1. Sign in to Grafana.
|
||||
1. Click **Dashboards** in the left-side menu.
|
||||
1. On the Dashboards page, click **New** and select **New folder** in the dropdown.
|
||||
1. Enter a unique name and click **Create**.
|
||||
|
||||
When you save a dashboard, you can either select a folder for the dashboard to be saved in or create a new folder.
|
||||
|
||||
## Manage dashboards
|
||||
|
||||
On the **Manage dashboards and folders** page, you can:
|
||||
On the Dashboards page, you can:
|
||||
|
||||
- create a folder
|
||||
- create a dashboard
|
||||
@@ -65,17 +67,17 @@ On the **Manage dashboards and folders** page, you can:
|
||||
|
||||
### Dashboard folder page
|
||||
|
||||
You can complete the following tasks on the **Dashboard Folder** page:
|
||||
You can complete the following tasks on a dashboard folder page:
|
||||
|
||||
- Move or delete dashboards in a folder
|
||||
- Rename a folder (available under the **Settings** tab)
|
||||
- Rename a folder (available on the Settings tab)
|
||||
- Assign permissions to folders (which are inherited by the dashboards in the folder)
|
||||
|
||||
To navigate to the dashboard folder page, click the cog appears when you hover over a folder in the dashboard search result list or the **Manage dashboards and folders** page.
|
||||
To navigate to the dashboard folder page, hover over the name of the folder and click **Go to folder** in the dashboard search result list or on the Dashboards page.
|
||||
|
||||
### Dashboard permissions
|
||||
|
||||
You can assign permissions to a folder. Any permissions you assign are inherited by the dashboards in the folder. An Access Control List (ACL) is used where **Organization Role**, **Team** and a **User** can be assigned permissions.
|
||||
You can assign permissions to a folder. Any permissions you assign are inherited by the dashboards in the folder. An Access Control List (ACL) is used where **Organization Role**, **Team**, and a **User** can be assigned permissions.
|
||||
|
||||
For more information about dashboard permissions, refer to [Dashboard permissions]({{< relref "../../administration/roles-and-permissions/#dashboard-permissions" >}}).
|
||||
|
||||
@@ -87,10 +89,11 @@ You can use the Grafana UI or the [HTTP API]({{< relref "../../developers/http_a
|
||||
|
||||
The dashboard export action creates a Grafana JSON file that contains everything you need, including layout, variables, styles, data sources, queries, and so on, so that you can later import the dashboard.
|
||||
|
||||
1. Click **Dashboards** in the left-side menu.
|
||||
1. Open the dashboard you want to export.
|
||||
2. Click the **Share** icon.
|
||||
3. Click **Export**.
|
||||
4. Click **Save to file**.
|
||||
1. Click the **Share** icon.
|
||||
1. Click **Export**.
|
||||
1. Click **Save to file**.
|
||||
|
||||
Grafana downloads a JSON file to your local machine.
|
||||
|
||||
@@ -102,7 +105,8 @@ A template variable of the type `Constant` will automatically be hidden in the d
|
||||
|
||||
### Import a dashboard
|
||||
|
||||
1. Click **Dashboards > Import** in the side menu.
|
||||
1. Click **Dashboards** in the left-side menu.
|
||||
1. Click **New** and select **Import** in the dropdown menu.
|
||||
1. Perform one of the following steps:
|
||||
|
||||
- Upload a dashboard JSON file
|
||||
@@ -118,7 +122,7 @@ The import process enables you to change the name of the dashboard, pick the dat
|
||||
|
||||
Find dashboards for common server applications at [Grafana.com/dashboards](https://grafana.com/dashboards).
|
||||
|
||||
{{< figure src="/static/img/docs/v50/gcom_dashboard_list.png" max-width="700px" >}}
|
||||
{{< figure src="/media/docs/grafana/dashboards/screenshot-gcom-dashboards.png" >}}
|
||||
|
||||
## Troubleshoot dashboards
|
||||
|
||||
|
||||
@@ -52,10 +52,11 @@ You can share a dashboard as a direct link or as a snapshot. You can also export
|
||||
|
||||
> **Note:** If you change a dashboard, ensure that you save the changes before sharing.
|
||||
|
||||
1. Navigate to the home page of your Grafana instance.
|
||||
1. Click on the share icon in the top navigation.
|
||||
1. Click **Dashboards** in the left-side menu.
|
||||
1. Click the dashboard you want to share.
|
||||
1. Click the share icon at the top of the screen.
|
||||
|
||||
The share dialog opens and shows the **Link** tab.
|
||||
The share dialog opens and shows the Link tab.
|
||||
|
||||
### Share a direct link
|
||||
|
||||
@@ -73,7 +74,8 @@ A dashboard snapshot shares an interactive dashboard publicly. Grafana strips se
|
||||
|
||||
You can publish snapshots to your local instance or to [snapshots.raintank.io](http://snapshots.raintank.io). The latter is a free service provided by Grafana Labs that enables you to publish dashboard snapshots to an external Grafana instance. Anyone with the link can view it. You can set an expiration time if you want the snapshot removed after a certain time period.
|
||||
|
||||
1. Click **Local Snapshot** or **Publish to snapshots.raintank.io**.
|
||||
1. Click the **Snapshot** tab.
|
||||
1. Click **Publish to snapshots.raintank.io** or **Local Snapshot**.
|
||||
|
||||
Grafana generates a link of the snapshot.
|
||||
|
||||
@@ -91,7 +93,9 @@ You can generate and save PDF files of any dashboard.
|
||||
|
||||
> **Note:** Available in [Grafana Enterprise]({{< relref "../../introduction/grafana-enterprise/" >}}).
|
||||
|
||||
1. In the upper-right corner of the dashboard that you want to export as PDF, click the **Share dashboard** icon.
|
||||
1. Click **Dashboards** in the left-side menu.
|
||||
1. Click the dashboard you want to share.
|
||||
1. Click the share icon at the top of the screen.
|
||||
1. On the PDF tab, select a layout option for the exported dashboard: **Portrait** or **Landscape**.
|
||||
1. Click **Save as PDF** to render the dashboard as a PDF file.
|
||||
|
||||
@@ -101,8 +105,8 @@ You can generate and save PDF files of any dashboard.
|
||||
|
||||
You can share a panel as a direct link, as a snapshot, or as an embedded link. You can also create library panels using the **Share** option on any panel.
|
||||
|
||||
1. Click a panel title to open the panel menu.
|
||||
1. Click **Share**.
|
||||
1. Hover over any part of the panel to display the actions menu on the top right corner.
|
||||
1. Click the menu and select **Share**.
|
||||
|
||||
The share dialog opens and shows the **Link** tab.
|
||||
|
||||
@@ -139,8 +143,8 @@ A panel snapshot shares an interactive panel publicly. Grafana strips sensitive
|
||||
|
||||
You can publish snapshots to your local instance or to [snapshots.raintank.io](http://snapshots.raintank.io). The latter is a free service provided by [Grafana Labs](https://grafana.com), that enables you to publish dashboard snapshots to an external Grafana instance. You can optionally set an expiration time if you want the snapshot to be removed after a certain time period.
|
||||
|
||||
1. In the **Share Panel** dialog, click **Snapshot** to open the tab.
|
||||
1. Click **Local Snapshot** or **Publish to snapshots.raintank.io**.
|
||||
1. In the **Share Panel** dialog, click **Snapshot** to go to the tab.
|
||||
1. Click **Publish to snapshots.raintank.io** or **Local Snapshot**.
|
||||
|
||||
Grafana generates the link of the snapshot.
|
||||
|
||||
|
||||
@@ -27,27 +27,28 @@ The dashboard user interface provides a number of features that you can use to c
|
||||
|
||||
The following image and descriptions highlights all dashboards features.
|
||||
|
||||
{{< figure src="/static/img/docs/v91/dashboard-features/dashboard-features.png" width="700px" >}}
|
||||
{{< figure src="/media/docs/grafana/dashboards/screenshot-dashboard-annotated-9-5-0.png" width="700px" >}}
|
||||
|
||||
- **Grafana home** (1): Click the Grafana home icon to be redirected to the home page configured in the Grafana instance.
|
||||
- **Grafana home** (1): Click **Home** in the breadcrumb to be redirected to the home page configured in the Grafana instance.
|
||||
- **Dashboard title** (2): When you click the dashboard title you can search for dashboard contained in the current folder.
|
||||
- **Share dashboard** (3): Use this option to share the current dashboard by link or snapshot. You can also export the dashboard definition from the share modal.
|
||||
- **Add a new panel** (4): Use this option to add a panel, dashboard row, or library panel to the current dashboard.
|
||||
- **Dashboard settings** (5): Use this option to change dashboard name, folder, and tags and manage variables and annotation queries. For more information about dashboard settings, refer to [Modify dashboard settings]({{< relref "../build-dashboards/modify-dashboard-settings/" >}}).
|
||||
- **Time picker dropdown** (6): Click to select relative time range options and set custom absolute time ranges.
|
||||
- **Share dashboard or panel** (3): Use this option to share the current dashboard or panel by link or snapshot. You can also export the dashboard definition from the share modal.
|
||||
- **Add** (4): Use this option to add a panel, dashboard row, or library panel to the current dashboard.
|
||||
- **Save dashboard** (5): Click to save changes to your dashboard.
|
||||
- **Dashboard insights** (6): Click to view analytics about your dashboard including information about users, activity, query counts.
|
||||
- **Dashboard settings** (7): Use this option to change dashboard name, folder, and tags and manage variables and annotation queries. For more information about dashboard settings, refer to [Modify dashboard settings]({{< relref "../build-dashboards/modify-dashboard-settings/" >}}).
|
||||
- **Time picker dropdown** (8): Click to select relative time range options and set custom absolute time ranges.
|
||||
- You can change the **Timezone** and **fiscal year** settings from the time range controls by clicking the **Change time settings** button.
|
||||
- Time settings are saved on a per-dashboard basis.
|
||||
- **Zoom out time range** (7): Click to zoom out the time range. For more information about how to use time range controls, refer to [Common time range controls]({{< relref "#common-time-range-controls" >}}).
|
||||
- **Refresh dashboard** (8): Click to immediately trigger queries and refresh dashboard data.
|
||||
- **Refresh dashboard time interval** (9): Click to select a dashboard auto refresh time interval.
|
||||
- **View mode** (10): Click to display the dashboard on a large screen such as a TV or a kiosk. View mode hides irrelevant information such as navigation menus. For more information about view mode, refer to [How to Create Kiosks to Display Dashboards on a TV](https://grafana.com/blog/2019/05/02/grafana-tutorial-how-to-create-kiosks-to-display-dashboards-on-a-tv/).
|
||||
- **Dashboard panel** (11): The primary building block of a dashboard is the panel. To add a new panel, dashboard row, or library panel, click **Add panel**.
|
||||
- **Zoom out time range** (9): Click to zoom out the time range. For more information about how to use time range controls, refer to [Common time range controls]({{< relref "#common-time-range-controls" >}}).
|
||||
- **Refresh dashboard** (10): Click to immediately trigger queries and refresh dashboard data.
|
||||
- **Refresh dashboard time interval** (11): Click to select a dashboard auto refresh time interval.
|
||||
- **View mode** (12): Click to display the dashboard on a large screen such as a TV or a kiosk. View mode hides irrelevant information such as navigation menus. For more information about view mode, refer to [How to Create Kiosks to Display Dashboards on a TV](https://grafana.com/blog/2019/05/02/grafana-tutorial-how-to-create-kiosks-to-display-dashboards-on-a-tv/).
|
||||
- **Dashboard panel** (13): The primary building block of a dashboard is the panel. To add a new panel, dashboard row, or library panel, click **Add panel**.
|
||||
- Library panels can be shared among many dashboards.
|
||||
- To move a panel, drag the panel header to another location.
|
||||
- To resize a panel, click and drag the lower right corner of the panel.
|
||||
- **Graph legend** (12): Change series colors, y-axis and series visibility directly from the legend.
|
||||
- **Search** (13): Click **Search** to search for dashboards by name or panel title.
|
||||
- **Dashboard row** (14): A dashboard row is a logical divider within a dashboard that groups panels together.
|
||||
- **Graph legend** (14): Change series colors, y-axis and series visibility directly from the legend.
|
||||
- **Dashboard row** (15): A dashboard row is a logical divider within a dashboard that groups panels together.
|
||||
- Rows can be collapsed or expanded allowing you to hide parts of the dashboard.
|
||||
- Panels inside a collapsed row do not issue queries.
|
||||
- Use [repeating rows]({{< relref "../build-dashboards/create-dashboard/#configure-repeating-rows" >}}) to dynamically create rows based on a template variable.
|
||||
@@ -129,7 +130,7 @@ Hover your cursor over the field to see the exact time stamps in the range and t
|
||||
|
||||
Click the current time range to change it. You can change the current time using a _relative time range_, such as the last 15 minutes, or an _absolute time range_, such as `2020-05-14 00:00:00 to 2020-05-15 23:59:59`.
|
||||
|
||||
<img class="no-shadow" src="/static/img/docs/time-range-controls/change-current-time-range-7-0.png" max-width="900px">
|
||||
<img class="no-shadow" src="/media/docs/grafana/dashboards/screenshot-change-current-time-range.png" max-width="900px">
|
||||
|
||||
#### Relative time range
|
||||
|
||||
|
||||
@@ -44,17 +44,17 @@ weight: 100
|
||||
|
||||
The following table lists the types of variables shipped with Grafana.
|
||||
|
||||
| Variable type | Description |
|
||||
| :---------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Query | Query-generated list of values such as metric names, server names, sensor IDs, data centers, and so on. [Add a query variable]({{< relref "#add-a-query-variable" >}}). |
|
||||
| Custom | Define the variable options manually using a comma-separated list. [Add a custom variable]({{< relref "#add-a-custom-variable" >}}). |
|
||||
| Text box | Display a free text input field with an optional default value. [Add a text box variable]({{< relref "#add-a-text-box-variable" >}}). |
|
||||
| Constant | Define a hidden constant. [Add a constant variable]({{< relref "#add-a-constant-variable" >}}). |
|
||||
| Data source | Quickly change the data source for an entire dashboard. [Add a data source variable]({{< relref "#add-a-data-source-variable" >}}). |
|
||||
| Interval | Interval variables represent time spans. [Add an interval variable]({{< relref "#add-an-interval-variable" >}}). |
|
||||
| Ad hoc filters | Key/value filters that are automatically added to all metric queries for a data source (InfluxDB, Prometheus, and Elasticsearch only). [Add ad hoc filters]({{< relref "#add-ad-hoc-filters" >}}). |
|
||||
| Global variables | Built-in variables that can be used in expressions in the query editor. Refer to [Global variables]({{< relref "#global-variables" >}}). |
|
||||
| Chained variables | Variable queries can contain other variables. Refer to [Chained variables]({{< relref "#chained-variables" >}}). |
|
||||
| Variable type | Description |
|
||||
| :---------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Query | Query-generated list of values such as metric names, server names, sensor IDs, data centers, and so on. [Add a query variable]({{< relref "#add-a-query-variable" >}}). |
|
||||
| Custom | Define the variable options manually using a comma-separated list. [Add a custom variable]({{< relref "#add-a-custom-variable" >}}). |
|
||||
| Text box | Display a free text input field with an optional default value. [Add a text box variable]({{< relref "#add-a-text-box-variable" >}}). |
|
||||
| Constant | Define a hidden constant. [Add a constant variable]({{< relref "#add-a-constant-variable" >}}). |
|
||||
| Data source | Quickly change the data source for an entire dashboard. [Add a data source variable]({{< relref "#add-a-data-source-variable" >}}). |
|
||||
| Interval | Interval variables represent time spans. [Add an interval variable]({{< relref "#add-an-interval-variable" >}}). |
|
||||
| Ad hoc filters | Key/value filters that are automatically added to all metric queries for a data source (Prometheus, Loki, InfluxDB, and Elasticsearch only). [Add ad hoc filters]({{< relref "#add-ad-hoc-filters" >}}). |
|
||||
| Global variables | Built-in variables that can be used in expressions in the query editor. Refer to [Global variables]({{< relref "#global-variables" >}}). |
|
||||
| Chained variables | Variable queries can contain other variables. Refer to [Chained variables]({{< relref "#chained-variables" >}}). |
|
||||
|
||||
## Enter General options
|
||||
|
||||
@@ -194,7 +194,7 @@ Ad hoc filters are one of the most complex and flexible variable options availab
|
||||
|
||||
Interpolating a variable with multiple values selected is tricky as it is not straight forward how to format the multiple values into a string that is valid in the given context where the variable is used. Grafana tries to solve this by allowing each data source plugin to inform the templating interpolation engine what format to use for multiple values.
|
||||
|
||||
> **Note:** The **Custom all value** option on the variable must be blank for Grafana to format all values into a single string. If leave it blank, then the Grafana concatenates (adds together) all the values in the query. Something like `value1,value2,value3`. If a custom `all` value is used, then instead the value will be something like `*` or `all`.
|
||||
> **Note:** The **Custom all value** option on the variable must be blank for Grafana to format all values into a single string. If it is left blank, then Grafana concatenates (adds together) all the values in the query. Something like `value1,value2,value3`. If a custom `all` value is used, then instead the value will be something like `*` or `all`.
|
||||
|
||||
#### Multi-value variables with a Graphite data source
|
||||
|
||||
@@ -281,6 +281,8 @@ This variable is the `$__interval` variable in milliseconds, not a time interval
|
||||
|
||||
This variable is only available in the Singlestat panel and can be used in the prefix or suffix fields on the Options tab. The variable will be replaced with the series name or alias.
|
||||
|
||||
> **Note:** The Singlestat panel is no longer available from Grafana 8.0.
|
||||
|
||||
### $\_\_org
|
||||
|
||||
This variable is the ID of the current organization.
|
||||
@@ -398,7 +400,7 @@ apps.fakesite.web_server_01.cpu.*
|
||||
|
||||
#### InfluxDB example
|
||||
|
||||
In this example, you have several data centers. Each data center has a different subset of hosts. It is based on the [InfluxDB Templated](https://play.grafana.org/d/000000002/influxdb-templated?orgId=1).
|
||||
In this example, you have several data centers. Each data center has a different subset of hosts. It is based on the [InfluxDB Templated](https://play.grafana.org/d/000000002/influxdb-templated?orgId=1) dashboard.
|
||||
|
||||
In this example, when the user changes the value of the `datacenter` variable, it changes the dropdown options returned by the `host` variable. The `host` variable uses the **Multi-value** option and **Include all option**, allowing users to select some or all options presented at any time. The `datacenter` does not use either option, so you can only select one data center at a time.
|
||||
|
||||
@@ -407,7 +409,7 @@ In this example, when the user changes the value of the `datacenter` variable, i
|
||||
The query for this variable basically says, "Give me all the data centers that exist."
|
||||
|
||||
```
|
||||
SHOW TAG VALUES WITH KEY = "datacenter"
|
||||
SHOW TAG VALUES WITH KEY = "datacenter"
|
||||
```
|
||||
|
||||
The values returned are `America`, `Africa`, `Asia`, and `Europe`.
|
||||
|
||||
@@ -28,24 +28,25 @@ When using Prometheus, contact points and notification policies are read-only in
|
||||
|
||||
## Configure the data source
|
||||
|
||||
**To access the data source configuration page:**
|
||||
To configure basic settings for the data source, complete the following steps:
|
||||
|
||||
1. Select the **Data sources** section from the **Administration** menu
|
||||
2. Select the **Alertmanager** data source
|
||||
1. Click **Connections** in the left-side menu.
|
||||
1. Under Your connections, click **Data sources**.
|
||||
1. Enter `Alertmanager` in the search bar.
|
||||
1. Click **Alertmanager**.
|
||||
|
||||
Set the data source's basic configuration options carefully:
|
||||
The **Settings** tab of the data source is displayed.
|
||||
|
||||
| Name | Description |
|
||||
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **Name** | Sets the name you use to refer to the data source |
|
||||
| **Default** | Sets whether the data source is pre-selected for new panels and queries |
|
||||
| **Alertmanager** | |
|
||||
| **Implementation** | Alertmanager implementation. **Mimir**, **Cortex,** and **Prometheus** are supported |
|
||||
| **Receive Grafana Alerts** | When enabled the Alertmanager receives alert instances from Grafana-managed alert rules. **Important:** It works only if Grafana alerting is configured to send its alert instances to external Alertmanagers |
|
||||
| **HTTP** | |
|
||||
| **URL** | Sets the HTTP protocol, IP, and port of your Alertmanager instance, such as `https://alertmanager.example.org:9093` |
|
||||
| **Access** | Only **Server** access mode is functional |
|
||||
| | |
|
||||
1. Set the data source's basic configuration options:
|
||||
|
||||
| Name | Description |
|
||||
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **Name** | Sets the name you use to refer to the data source |
|
||||
| **Default** | Sets whether the data source is pre-selected for new panels and queries |
|
||||
| **Alertmanager Implementation** | Alertmanager implementation. **Mimir**, **Cortex,** and **Prometheus** are supported |
|
||||
| **Receive Grafana Alerts** | When enabled the Alertmanager receives alert instances from Grafana-managed alert rules. **Important:** It works only if Grafana alerting is configured to send its alert instances to external Alertmanagers |
|
||||
| **HTTP URL** | Sets the HTTP protocol, IP, and port of your Alertmanager instance, such as `https://alertmanager.example.org:9093` |
|
||||
| **Access** | Only **Server** access mode is functional |
|
||||
|
||||
## Provision the Alertmanager data source
|
||||
|
||||
|
||||
@@ -31,11 +31,12 @@ Once you've added the data source, you can [configure it]({{< relref "#configure
|
||||
|
||||
## Configure the data source
|
||||
|
||||
**To access the data source configuration page:**
|
||||
1. Click **Connections** in the left-side menu.
|
||||
1. Under Your connections, click **Data sources**.
|
||||
1. Enter `CloudWatch` in the search bar.
|
||||
1. Click **CloudWatch**.
|
||||
|
||||
1. Hover the cursor over the **Configuration** (gear) icon.
|
||||
1. Select **Data Sources**.
|
||||
1. Select the CloudWatch data source.
|
||||
The **Settings** tab of the data source is displayed.
|
||||
|
||||
### Configure AWS authentication
|
||||
|
||||
@@ -49,7 +50,7 @@ For authentication options and configuration details, refer to [AWS authenticati
|
||||
To read CloudWatch metrics and EC2 tags, instances, regions, and alarms, you must grant Grafana permissions via IAM.
|
||||
You can attach these permissions to the IAM role or IAM user you configured in [AWS authentication]({{< relref "./aws-authentication/" >}}).
|
||||
|
||||
**Metrics-only:**
|
||||
##### Metrics-only permissions
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -84,7 +85,7 @@ You can attach these permissions to the IAM role or IAM user you configured in [
|
||||
}
|
||||
```
|
||||
|
||||
**Logs-only:**
|
||||
##### Logs-only permissions
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -119,7 +120,7 @@ You can attach these permissions to the IAM role or IAM user you configured in [
|
||||
}
|
||||
```
|
||||
|
||||
**Metrics and Logs:**
|
||||
##### Metrics and logs permissions
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -167,7 +168,7 @@ You can attach these permissions to the IAM role or IAM user you configured in [
|
||||
}
|
||||
```
|
||||
|
||||
**Cross-account observability: (see below) **
|
||||
##### Cross-account observability permissions
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -234,7 +235,7 @@ For more information about provisioning, and for available configuration options
|
||||
|
||||
#### Provisioning examples
|
||||
|
||||
**Using AWS SDK (default):**
|
||||
##### Using AWS SDK (default)
|
||||
|
||||
```yaml
|
||||
apiVersion: 1
|
||||
@@ -246,7 +247,7 @@ datasources:
|
||||
defaultRegion: eu-west-2
|
||||
```
|
||||
|
||||
**Using credentials' profile name (non-default):**
|
||||
##### Using credentials' profile name (non-default)
|
||||
|
||||
```yaml
|
||||
apiVersion: 1
|
||||
@@ -261,7 +262,7 @@ datasources:
|
||||
profile: secondary
|
||||
```
|
||||
|
||||
**Using accessKey and secretKey:**
|
||||
##### Using accessKey and secretKey
|
||||
|
||||
```yaml
|
||||
apiVersion: 1
|
||||
@@ -277,7 +278,7 @@ datasources:
|
||||
secretKey: '<your secret key>'
|
||||
```
|
||||
|
||||
**Using AWS SDK Default and ARN of IAM Role to Assume:**
|
||||
##### Using AWS SDK Default and ARN of IAM Role to Assume
|
||||
|
||||
```yaml
|
||||
apiVersion: 1
|
||||
@@ -375,3 +376,7 @@ For more information, refer to the AWS documentation for [Service Quotas](https:
|
||||
The CloudWatch plugin enables you to monitor and troubleshoot applications across multiple regional accounts. Using cross-account observability, you can seamlessly search, visualize and analyze metrics and logs without worrying about account boundaries.
|
||||
|
||||
To use this feature, configure in the [AWS console under Cloudwatch Settings](https://aws.amazon.com/blogs/aws/new-amazon-cloudwatch-cross-account-observability/), a monitoring and source account, and then add the necessary IAM permissions as described above.
|
||||
|
||||
## CloudWatch Logs data protection
|
||||
|
||||
CloudWatch Logs can safeguard data by using log group data protection policies. If you have data protection enabled for a log group, then any sensitive data that matches the data identifiers you've selected will be masked. In order to view masked data you will need to have the `logs:Unmask` IAM permission enabled. See the AWS documentation on how to [help protect sensitive log data with masking](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/mask-sensitive-log-data.html) to learn more about this.
|
||||
|
||||
@@ -92,7 +92,7 @@ For example, to apply arithmetic operations to a metric, apply a unique string i
|
||||
|
||||
> **Note:** If you use the expression field to reference another query, like `queryA * 2`, you can't create an alert rule based on that query.
|
||||
|
||||
##### Period macro
|
||||
#### Period macro
|
||||
|
||||
If you're using a CloudWatch [`SEARCH`](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/search-expression-syntax.html) expression, you may want to use the `$__period_auto` macro rather than specifying a period explicitly. The `$__period_auto` macro will resolve to a [CloudWatch period](https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_GetMetricData.html) that is suitable for the chosen time range.
|
||||
|
||||
@@ -218,9 +218,17 @@ When making `stats` queries in [Explore]({{< relref "../../../explore/" >}}), ma
|
||||
|
||||
{{< figure src="/static/img/docs/v70/explore-mode-switcher.png" max-width="500px" class="docs-image--right" caption="Explore mode switcher" >}}
|
||||
|
||||
### Getting started
|
||||
## Cross-account observability
|
||||
|
||||
To enable cross-account observability, first enable it in CloudWatch using the official [CloudWatch docs](http://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Unified-Cross-Account.html), then add [two new API actions]({{< relref "../#cross-account-observability" >}}) to the IAM policy attached to the role/user running the plugin.
|
||||
The CloudWatch plugin allows monitoring and troubleshooting applications that span multiple accounts within a region. Using cross-account observability, you can seamlessly search, visualize, and analyze metrics and logs without worrying about account boundaries.
|
||||
|
||||
### Get started
|
||||
|
||||
To enable cross-account observability, complete the following steps:
|
||||
|
||||
1. Go to the [Amazon CloudWatch docs](http://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Unified-Cross-Account.html) and follow the instructions on enabling cross-account observability.
|
||||
|
||||
1. Add [two API actions](/docs/grafana/latest/datasources/aws-cloudwatch/#cross-account-observability-permissions) to the IAM policy attached to the role/user running the plugin.
|
||||
|
||||
Cross-account querying is available in the plugin through the `Logs` mode and the `Metric search` mode. Once you have it configured correctly, you'll see a "Monitoring account" badge displayed in the query editor header.
|
||||
|
||||
|
||||
@@ -24,26 +24,29 @@ Once you've added the Graphite data source, you can [configure it]({{< relref "#
|
||||
|
||||
## Configure the data source
|
||||
|
||||
**To access the data source configuration page:**
|
||||
To configure basic settings for the data source, complete the following steps:
|
||||
|
||||
1. Hover the cursor over the **Configuration** (gear) icon.
|
||||
1. Select **Data Sources**.
|
||||
1. Select the Graphite data source.
|
||||
1. Click **Connections** in the left-side menu.
|
||||
1. Under Your connections, click **Data sources**.
|
||||
1. Enter `Graphite` in the search bar.
|
||||
1. Click **Graphite**.
|
||||
|
||||
Set the data source's basic configuration options carefully:
|
||||
The **Settings** tab of the data source is displayed.
|
||||
|
||||
| Name | Description |
|
||||
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| **Name** | Sets the name you use to refer to the data source in panels and queries. |
|
||||
| **Default** | Sets whether the data source is pre-selected for new panels. You can set only one default data source per organization. |
|
||||
| **URL** | Sets the HTTP protocol, IP, and port of your graphite-web or graphite-api installation. |
|
||||
| **Auth** | For details, refer to [Configure Authentication]({{< relref "../../setup-grafana/configure-security/configure-authentication/" >}}). |
|
||||
| **Basic Auth** | Enables basic authentication to the data source. |
|
||||
| **User** | Sets the user name for basic authentication. |
|
||||
| **Password** | Sets the password for basic authentication. |
|
||||
| **Custom HTTP Headers** | Click **Add header** to add a custom HTTP header. |
|
||||
| **Header** | Defines the custom header name. |
|
||||
| **Value** | Defines the custom header value. |
|
||||
1. Set the data source's basic configuration options:
|
||||
|
||||
| Name | Description |
|
||||
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| **Name** | Sets the name you use to refer to the data source in panels and queries. |
|
||||
| **Default** | Sets whether the data source is pre-selected for new panels. You can set only one default data source per organization. |
|
||||
| **URL** | Sets the HTTP protocol, IP, and port of your graphite-web or graphite-api installation. |
|
||||
| **Auth** | For details, refer to [Configure Authentication]({{< relref "../../setup-grafana/configure-security/configure-authentication/" >}}). |
|
||||
| **Basic Auth** | Enables basic authentication to the data source. |
|
||||
| **User** | Sets the user name for basic authentication. |
|
||||
| **Password** | Sets the password for basic authentication. |
|
||||
| **Custom HTTP Headers** | Click **Add header** to add a custom HTTP header. |
|
||||
| **Header** | Defines the custom header name. |
|
||||
| **Value** | Defines the custom header value. |
|
||||
|
||||
You can also configure settings specific to the Graphite data source:
|
||||
|
||||
|
||||
@@ -41,14 +41,13 @@ To configure basic settings for the data source, complete the following steps:
|
||||
|
||||
1. Set the data source's basic configuration options carefully:
|
||||
|
||||
| Name | Description |
|
||||
|
||||
| Name | Description |
|
||||
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| **Name** | Sets the name you use to refer to the data source in panels and queries. We recommend something like `InfluxDB-InfluxQL`. |
|
||||
| **Default** | Sets whether the data source is pre-selected for new panels. |
|
||||
| **URL** | The HTTP protocol, IP address, and port of your InfluxDB API. InfluxDB's default API port is 8086. |
|
||||
| **Min time interval** | _(Optional)_ Refer to [Min time interval]({{< relref "#configure-min-time-interval" >}}). |
|
||||
| **Max series** | _(Optional)_ Limits the number of series and tables that Grafana processes. Lower this number to prevent abuse, and increase it if you have many small time series and not all are shown. Defaults to 1,000. |
|
||||
| **Name** | Sets the name you use to refer to the data source in panels and queries. We recommend something like `InfluxDB-InfluxQL`. |
|
||||
| **Default** | Sets whether the data source is pre-selected for new panels. |
|
||||
| **URL** | The HTTP protocol, IP address, and port of your InfluxDB API. InfluxDB's default API port is 8086. |
|
||||
| **Min time interval** | _(Optional)_ Refer to [Min time interval]({{< relref "#configure-min-time-interval" >}}). |
|
||||
| **Max series** | _(Optional)_ Limits the number of series and tables that Grafana processes. Lower this number to prevent abuse, and increase it if you have many small time series and not all are shown. Defaults to 1,000. |
|
||||
|
||||
You can also configure settings specific to the InfluxDB data source. These options are described in the sections below.
|
||||
|
||||
|
||||
@@ -54,45 +54,10 @@ Code mode's autocompletion feature works automatically while typing.
|
||||
The query editor can autocomplete static functions, aggregations, and keywords, and also dynamic items like labels.
|
||||
The autocompletion dropdown includes documentation for the suggested items where available.
|
||||
|
||||
### Label browser
|
||||
|
||||
You can use the Loki label browser to navigate through your labels and values, and build queries.
|
||||
|
||||
**To navigate Loki and build a query:**
|
||||
|
||||
1. Choose labels to locate.
|
||||
1. Search for the values of your selected labels.
|
||||
|
||||
The search field supports fuzzy search, and the label browser also supports faceting to list only possible label combinations.
|
||||
|
||||
1. Choose a query type between [**logs query**]({{< relref "#create-a-log-query" >}}) and [**rate metrics query**]({{< relref "#create-a-metric-query" >}}).
|
||||
You can also validate the selector.
|
||||
|
||||
{{< figure src="/static/img/docs/v75/loki_label_browser.png" class="docs-image--no-shadow" max-width="800px" caption="The Loki label browser" >}}
|
||||
|
||||
### Configure query settings
|
||||
|
||||
| Name | Description |
|
||||
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| **Type** | Selects the query type to run. The `instant` type queries against a single point in time. We use the "To" time from the time range. The `range` type queries over the selected range of time. |
|
||||
| **Line limit** | Defines the upper limit for the number of log lines returned by a query. The default is Loki's configured maximum lines limit. |
|
||||
| **Legend** | _(Available only in a dashboard)_ Controls the time series name, using a name or pattern. For example, `{{hostname}}` is replaced with the label value for the label `hostname`. |
|
||||
| **Resolution** | Sets the step parameter of Loki metrics range queries. With a resolution of `1/1`, each pixel corresponds to one data point. `1/2` retrieves one data point for every other pixel, `1/10` retrieves one data point per 10 pixels, and so on. Lower resolutions perform better. |
|
||||
|
||||
## Builder mode
|
||||
|
||||
Use Builder mode to visually construct queries, without needing to manually enter LogQL.
|
||||
|
||||
### Review toolbar features
|
||||
|
||||
In addition to the **Run query** button and mode switcher, Builder mode provides additional elements:
|
||||
|
||||
| Name | Description |
|
||||
| ------------------------- | ----------------------------------------------------------------------------------------- |
|
||||
| **Kick start your query** | A list of useful operation patterns you can use to add multiple operations to your query. |
|
||||
| **Label browser** | Used to navigate through your labels and values, and also build queries. |
|
||||
| **Explain query** | Displays a step-by-step explanation of all query components and operations. |
|
||||
|
||||
### Use the Labels selector
|
||||
|
||||
Select labels and their values from the dropdown list.
|
||||
@@ -108,11 +73,11 @@ The query editor groups operations into related sections, and you can type while
|
||||
The query editor displays a query's operations as boxes in the operations section.
|
||||
Each operation's header displays its name, and additional action buttons appear when you hover your cursor over the header:
|
||||
|
||||
| Button | Action |
|
||||
| ------ | ----------------------------------------------------------------- |
|
||||
| `v` | Replaces the operation with different operation of the same type. |
|
||||
| `info` | Opens the operation's description tooltip. |
|
||||
| `x` | Removes the operation. |
|
||||
| Button | Action |
|
||||
| ----------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
|
||||
| {{< figure src="/static/img/docs/v95/loki_operation_replace.png" class="docs-image--no-shadow" max-width="30px" >}} | Replaces the operation with different operation of the same type. |
|
||||
| {{< figure src="/static/img/docs/v95/loki_operation_description.png" class="docs-image--no-shadow" max-width="30px" >}} | Opens the operation's description tooltip. |
|
||||
| {{< figure src="/static/img/docs/v95/loki_operation_remove.png" class="docs-image--no-shadow" max-width="30px" >}} | Removes the operation. |
|
||||
|
||||
Some operations have additional parameters under the operation header.
|
||||
For details about each operation, use the `info` button to view the operation's description, or refer to the [Loki documentation](/docs/loki/latest/operations/).
|
||||
@@ -125,10 +90,6 @@ To re-order operations manually, drag the operation box by its name and drop it
|
||||
|
||||
In same cases the query editor can detect which operations would be most appropriate for a selected log stream. In such cases it will show a hint next to the `+ Operations` button. Click on the hint to add the operations to your query.
|
||||
|
||||
### Explain query
|
||||
|
||||
This section is only shown if the `Explain query` switch from the query editor top toolbar is set to `on`. It shows a step by step explanation of all query parts and the operations.
|
||||
|
||||
## Create a log query
|
||||
|
||||
Loki log queries return the contents of the log lines.
|
||||
@@ -205,6 +166,45 @@ You can use LogQL to wrap a log query with functions that create metrics from yo
|
||||
|
||||
For more information about metric queries, refer to the [Loki metric queries documentation](/docs/loki/latest/logql/metric_queries/).
|
||||
|
||||
## Review toolbar features
|
||||
|
||||
In addition to the **Run query** button and mode switcher, Builder mode provides additional elements:
|
||||
|
||||
| Name | Description |
|
||||
| ------------------------- | ----------------------------------------------------------------------------------------- |
|
||||
| **Kick start your query** | A list of useful operation patterns you can use to add multiple operations to your query. |
|
||||
| **Label browser** | Used to navigate through your labels and values, and also build queries. |
|
||||
| **Explain query** | Displays a step-by-step explanation of all query components and operations. |
|
||||
|
||||
### Label browser
|
||||
|
||||
You can use the Loki label browser to navigate through your labels and values, and build queries.
|
||||
|
||||
**To navigate Loki and build a query:**
|
||||
|
||||
1. Choose labels to locate.
|
||||
1. Search for the values of your selected labels.
|
||||
|
||||
The search field supports fuzzy search, and the label browser also supports faceting to list only possible label combinations.
|
||||
|
||||
1. Choose a query type between [**logs query**]({{< relref "#create-a-log-query" >}}) and [**rate metrics query**]({{< relref "#create-a-metric-query" >}}).
|
||||
You can also validate the selector.
|
||||
|
||||
{{< figure src="/static/img/docs/v75/loki_label_browser.png" class="docs-image--no-shadow" max-width="800px" caption="The Loki label browser" >}}
|
||||
|
||||
### Explain query
|
||||
|
||||
This section is only shown if the `Explain query` switch from the query editor top toolbar is set to `on`. It shows a step by step explanation of all query parts and the operations.
|
||||
|
||||
## Configure query settings
|
||||
|
||||
| Name | Description |
|
||||
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| **Type** | Selects the query type to run. The `instant` type queries against a single point in time. We use the "To" time from the time range. The `range` type queries over the selected range of time. |
|
||||
| **Line limit** | Defines the upper limit for the number of log lines returned by a query. The default is Loki's configured maximum lines limit. |
|
||||
| **Legend** | _(Available only in a dashboard)_ Controls the time series name, using a name or pattern. For example, `{{hostname}}` is replaced with the label value for the label `hostname`. |
|
||||
| **Resolution** | Sets the step parameter of Loki metrics range queries. With a resolution of `1/1`, each pixel corresponds to one data point. `1/2` retrieves one data point for every other pixel, `1/10` retrieves one data point per 10 pixels, and so on. Lower resolutions perform better. |
|
||||
|
||||
## Apply annotations
|
||||
|
||||
[Annotations]({{< relref "../../../dashboards/build-dashboards/annotate-visualizations" >}}) overlay rich event information on top of graphs.
|
||||
|
||||
@@ -18,16 +18,25 @@ Grafana ships with built-in support for Parca, a continuous profiling OSS databa
|
||||
|
||||
## Configure the Parca data source
|
||||
|
||||
To access Parca settings, click the **Configuration** (gear) icon, then click **Data Sources** > **Parca**.
|
||||
To configure basic settings for the data source, complete the following steps:
|
||||
|
||||
| Name | Description |
|
||||
| ------------ | ------------------------------------------------------------------ |
|
||||
| `Name` | A name to specify the data source in panels, queries, and Explore. |
|
||||
| `Default` | The default data source will be pre-selected for new panels. |
|
||||
| `URL` | The URL of the Parca instance, e.g., `http://localhost:4100` |
|
||||
| `Basic Auth` | Enable basic authentication to the Parca data source. |
|
||||
| `User` | User name for basic authentication. |
|
||||
| `Password` | Password for basic authentication. |
|
||||
1. Click **Connections** in the left-side menu.
|
||||
1. Under Your connections, click **Data sources**.
|
||||
1. Enter `Parca` in the search bar.
|
||||
1. Click **Parca**.
|
||||
|
||||
The **Settings** tab of the data source is displayed.
|
||||
|
||||
1. Set the data source's basic configuration options:
|
||||
|
||||
| Name | Description |
|
||||
| ------------ | ------------------------------------------------------------------ |
|
||||
| `Name` | A name to specify the data source in panels, queries, and Explore. |
|
||||
| `Default` | The default data source will be pre-selected for new panels. |
|
||||
| `URL` | The URL of the Parca instance, e.g., `http://localhost:4100` |
|
||||
| `Basic Auth` | Enable basic authentication to the Parca data source. |
|
||||
| `User` | User name for basic authentication. |
|
||||
| `Password` | Password for basic authentication. |
|
||||
|
||||
## Querying
|
||||
|
||||
|
||||
@@ -18,17 +18,26 @@ Grafana ships with built-in support for Phlare, a horizontally scalable, highly-
|
||||
|
||||
## Configure the Phlare data source
|
||||
|
||||
To access Phlare settings, click the **Configuration** (gear) icon, then click **Data Sources** > **Phlare**.
|
||||
To configure basic settings for the data source, complete the following steps:
|
||||
|
||||
| Name | Description |
|
||||
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `Name` | A name to specify the data source in panels, queries, and Explore. |
|
||||
| `Default` | The default data source will be pre-selected for new panels. |
|
||||
| `URL` | The URL of the Phlare instance, e.g., `http://localhost:4100` |
|
||||
| `Basic Auth` | Enable basic authentication to the Phlare data source. |
|
||||
| `User` | User name for basic authentication. |
|
||||
| `Password` | Password for basic authentication. |
|
||||
| `Minimal step` | Similar to Prometheus, Phlare scrapes profiles at certain intervals. To prevent querying at smaller interval use Minimal step same or higher than your Phlare scrape interval. |
|
||||
1. Click **Connections** in the left-side menu.
|
||||
1. Under Your connections, click **Data sources**.
|
||||
1. Enter `Phlare` in the search bar.
|
||||
1. Click **Phlare**.
|
||||
|
||||
The **Settings** tab of the data source is displayed.
|
||||
|
||||
1. Set the data source's basic configuration options:
|
||||
|
||||
| Name | Description |
|
||||
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `Name` | A name to specify the data source in panels, queries, and Explore. |
|
||||
| `Default` | The default data source will be pre-selected for new panels. |
|
||||
| `URL` | The URL of the Phlare instance, e.g., `http://localhost:4100` |
|
||||
| `Basic Auth` | Enable basic authentication to the Phlare data source. |
|
||||
| `User` | User name for basic authentication. |
|
||||
| `Password` | Password for basic authentication. |
|
||||
| `Minimal step` | Similar to Prometheus, Phlare scrapes profiles at certain intervals. To prevent querying at smaller interval use Minimal step same or higher than your Phlare scrape interval. |
|
||||
|
||||
## Querying
|
||||
|
||||
|
||||
@@ -45,40 +45,38 @@ To configure basic settings for the data source, complete the following steps:
|
||||
|
||||
1. Set the data source's basic configuration options:
|
||||
|
||||
| Name | Description |
|
||||
|
||||
| Name | Description |
|
||||
| ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `Name` | The data source name. This is how you refer to the data source in panels and queries. |
|
||||
| `Default` | Default data source that is pre-selected for new panels. |
|
||||
| `URL` | The URL of your Prometheus server, for example, `http://prometheus.example.org:9090`. |
|
||||
| `Access` | Only Server access mode is functional. If Server mode is already selected this option is hidden. Otherwise change to Server mode to prevent errors. |
|
||||
| `Basic Auth` | Enable basic authentication to the Prometheus data source. |
|
||||
| `User` | User name for basic authentication. |
|
||||
| `Password` | Password for basic authentication. |
|
||||
| `Manage alerts via Alerting UI` | Toggle whether to enable Alertmanager integration for this data source. |
|
||||
| `Scrape interval` | Set this to the typical scrape and evaluation interval configured in Prometheus. Defaults to 15s. |
|
||||
| `HTTP method` | Use either POST or GET HTTP method to query your data source. POST is the recommended and pre-selected method as it allows bigger queries. Change this to GET if you have a Prometheus version older than 2.1 or if POST requests are restricted in your network. |
|
||||
| `Type` | The type of your Prometheus server; `Prometheus`, `Cortex`, `Thanos`, `Mimir`. When selected, the **Version** field attempts to populate automatically using the Prometheus [buildinfo](https://semver.org/) API. Some Prometheus types, such as Cortex, don't support this API and must be manually populated. |
|
||||
| `Version` | The version of your Prometheus server, note that this field is not visible until the Prometheus type is selected. |
|
||||
| `Disable metrics lookup` | Checking this option will disable the metrics chooser and metric/label support in the query field's autocomplete. This helps if you have performance issues with bigger Prometheus instances. |
|
||||
| `Custom query parameters` | Add custom parameters to the Prometheus query URL. For example `timeout`, `partial_response`, `dedup`, or `max_source_resolution`. Multiple parameters should be concatenated together with an '&'. |
|
||||
| **Exemplars configuration** | |
|
||||
| `Internal link` | Enable this option is you have an internal link. When you enable this option, you will see a data source selector. Select the backend tracing data store for your exemplar data. |
|
||||
| `Data source` | You will see this option only if you enable `Internal link` option. Select the backend tracing data store for your exemplar data. |
|
||||
| `URL` | You will see this option only if the `Internal link` option is disabled. Enter the full URL of the external link. You can interpolate the value from the field with `${__value.raw }` macro. |
|
||||
| `URL Label` | (Optional) add a custom display label to override the value of the `Label name` field. |
|
||||
| `Label name` | Add a name for the exemplar traceID property. |
|
||||
| `Name` | The data source name. This is how you refer to the data source in panels and queries. |
|
||||
| `Default` | Default data source that is pre-selected for new panels. |
|
||||
| `URL` | The URL of your Prometheus server, for example, `http://prometheus.example.org:9090`. |
|
||||
| `Access` | Only Server access mode is functional. If Server mode is already selected this option is hidden. Otherwise change to Server mode to prevent errors. |
|
||||
| `Basic Auth` | Enable basic authentication to the Prometheus data source. |
|
||||
| `User` | User name for basic authentication. |
|
||||
| `Password` | Password for basic authentication. |
|
||||
| `Manage alerts via Alerting UI` | Toggle whether to enable Alertmanager integration for this data source. |
|
||||
| `Scrape interval` | Set this to the typical scrape and evaluation interval configured in Prometheus. Defaults to 15s. |
|
||||
| `HTTP method` | Use either POST or GET HTTP method to query your data source. POST is the recommended and pre-selected method as it allows bigger queries. Change this to GET if you have a Prometheus version older than 2.1 or if POST requests are restricted in your network. |
|
||||
| `Type` | The type of your Prometheus server; `Prometheus`, `Cortex`, `Thanos`, `Mimir`. When selected, the **Version** field attempts to populate automatically using the Prometheus [buildinfo](https://semver.org/) API. Some Prometheus types, such as Cortex, don't support this API and must be manually populated. |
|
||||
| `Version` | The version of your Prometheus server, note that this field is not visible until the Prometheus type is selected. |
|
||||
| `Disable metrics lookup` | Checking this option will disable the metrics chooser and metric/label support in the query field's autocomplete. This helps if you have performance issues with bigger Prometheus instances. |
|
||||
| `Custom query parameters` | Add custom parameters to the Prometheus query URL. For example `timeout`, `partial_response`, `dedup`, or `max_source_resolution`. Multiple parameters should be concatenated together with an '&'. |
|
||||
| **Exemplars configuration** | |
|
||||
| `Internal link` | Enable this option is you have an internal link. When you enable this option, you will see a data source selector. Select the backend tracing data store for your exemplar data. |
|
||||
| `Data source` | You will see this option only if you enable `Internal link` option. Select the backend tracing data store for your exemplar data. |
|
||||
| `URL` | You will see this option only if the `Internal link` option is disabled. Enter the full URL of the external link. You can interpolate the value from the field with `${__value.raw }` macro. |
|
||||
| `URL Label` | (Optional) add a custom display label to override the value of the `Label name` field. |
|
||||
| `Label name` | Add a name for the exemplar traceID property. |
|
||||
|
||||
**Exemplars configuration:**
|
||||
|
||||
| Name | Description |
|
||||
|
||||
| Name | Description |
|
||||
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **Internal link** | Enable this option if you have an internal link. When enabled, this reveals the data source selector. Select the backend tracing data store for your exemplar data. |
|
||||
| **Data source** | _(Visible only if you enable `Internal link`)_ Selects the backend tracing data store for your exemplar data. |
|
||||
| **URL** | _(Visible only if you disable `Internal link`)_ Defines the external link's full URL. You can interpolate the value from the field by using the [`${__value.raw}` macro]({{< relref "../..//panels-visualizations/configure-data-links/#value-variables" >}}). |
|
||||
| **URL label** | _(Optional)_ Adds a custom display label to override the value of the `Label name` field. |
|
||||
| **Label name** | Adds a name for the exemplar traceID property. |
|
||||
| **Internal link** | Enable this option if you have an internal link. When enabled, this reveals the data source selector. Select the backend tracing data store for your exemplar data. |
|
||||
| **Data source** | _(Visible only if you enable `Internal link`)_ Selects the backend tracing data store for your exemplar data. |
|
||||
| **URL** | _(Visible only if you disable `Internal link`)_ Defines the external link's full URL. You can interpolate the value from the field by using the [`${__value.raw}` macro]({{< relref "../..//panels-visualizations/configure-data-links/#value-variables" >}}). |
|
||||
| **URL label** | _(Optional)_ Adds a custom display label to override the value of the `Label name` field. |
|
||||
| **Label name** | Adds a name for the exemplar traceID property. |
|
||||
|
||||
### Provision the data source
|
||||
|
||||
|
||||
@@ -38,15 +38,14 @@ To configure basic settings for the data source, complete the following steps:
|
||||
|
||||
1. Set the data source's basic configuration options:
|
||||
|
||||
| Name | Description |
|
||||
|
||||
| Name | Description |
|
||||
| -------------- | ------------------------------------------------------------------------ |
|
||||
| **Name** | Sets the name you use to refer to the data source in panels and queries. |
|
||||
| **Default** | Sets the data source that's pre-selected for new panels. |
|
||||
| **URL** | Sets the URL of the Tempo instance, such as `http://tempo`. |
|
||||
| **Basic Auth** | Enables basic authentication to the Tempo data source. |
|
||||
| **User** | Sets the user name for basic authentication. |
|
||||
| **Password** | Sets the password for basic authentication. |
|
||||
| **Name** | Sets the name you use to refer to the data source in panels and queries. |
|
||||
| **Default** | Sets the data source that's pre-selected for new panels. |
|
||||
| **URL** | Sets the URL of the Tempo instance, such as `http://tempo`. |
|
||||
| **Basic Auth** | Enables basic authentication to the Tempo data source. |
|
||||
| **User** | Sets the user name for basic authentication. |
|
||||
| **Password** | Sets the password for basic authentication. |
|
||||
|
||||
You can also configure settings specific to the Tempo data source. These options are described in the sections below.
|
||||
|
||||
@@ -232,6 +231,10 @@ datasources:
|
||||
spanBar:
|
||||
type: 'Tag'
|
||||
tag: 'http.path'
|
||||
traceQuery:
|
||||
timeShiftEnabled: true
|
||||
spanStartTimeShift: 15m
|
||||
spanEndTimeShift: 20m
|
||||
```
|
||||
|
||||
## Query the data source
|
||||
|
||||
+3
-4
@@ -33,11 +33,10 @@ To configure basic settings for the data source, complete the following steps:
|
||||
|
||||
The **Settings** tab of the data source is displayed. The data source doesn't provide any settings beyond the most basic options common to all data sources:
|
||||
|
||||
| Name | Description |
|
||||
|
||||
| Name | Description |
|
||||
| ----------- | ------------------------------------------------------------------------ |
|
||||
| **Name** | Sets the name you use to refer to the data source in panels and queries. |
|
||||
| **Default** | Defines whether this data source is pre-selected for new panels. |
|
||||
| **Name** | Sets the name you use to refer to the data source in panels and queries. |
|
||||
| **Default** | Defines whether this data source is pre-selected for new panels. |
|
||||
|
||||
## Create mock data
|
||||
|
||||
|
||||
@@ -38,15 +38,14 @@ To configure basic settings for the data source, complete the following steps:
|
||||
|
||||
1. Set the data source's basic configuration options:
|
||||
|
||||
| Name | Description |
|
||||
|
||||
| Name | Description |
|
||||
| -------------- | ------------------------------------------------------------------------ |
|
||||
| **Name** | Sets the name you use to refer to the data source in panels and queries. |
|
||||
| **Default** | Defines whether this data source is pre-selected for new panels. |
|
||||
| **URL** | Sets the URL of the Zipkin instance, such as `http://localhost:9411`. |
|
||||
| **Basic Auth** | Enables basic authentication for the Zipkin data source. |
|
||||
| **User** | Defines the user name for basic authentication. |
|
||||
| **Password** | Defines the password for basic authentication. |
|
||||
| **Name** | Sets the name you use to refer to the data source in panels and queries. |
|
||||
| **Default** | Defines whether this data source is pre-selected for new panels. |
|
||||
| **URL** | Sets the URL of the Zipkin instance, such as `http://localhost:9411`. |
|
||||
| **Basic Auth** | Enables basic authentication for the Zipkin data source. |
|
||||
| **User** | Defines the user name for basic authentication. |
|
||||
| **Password** | Defines the password for basic authentication. |
|
||||
|
||||
### Trace to logs
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ weight: 5
|
||||
|
||||
# Grafana OSS
|
||||
|
||||
[Grafana open source software](https://grafana.com/oss/) enables you to query, visualize, alert on, and explore your metrics, logs, and traces wherever they are stored. Grafana OSS provides you with tools to turn your time-series database (TSDB) data into insightful graphs and visualizations.
|
||||
[Grafana open source software](https://grafana.com/oss/) enables you to query, visualize, alert on, and explore your metrics, logs, and traces wherever they are stored. Grafana OSS provides you with tools to turn your time-series database (TSDB) data into insightful graphs and visualizations. The Grafana OSS plugin framework also enables you to connect other data sources like NoSQL/SQL databases, ticketing tools like Jira or ServiceNow, and CI/CD tooling like GitLab.
|
||||
|
||||
After you have [installed Grafana]({{< relref "../setup-grafana/installation/" >}}) and set up your first dashboard using instructions in [Getting started with Grafana]({{< relref "../getting-started/build-first-dashboard.md" >}}), you will have many options to choose from depending on your requirements. For example, if you want to view weather data and statistics about your smart home, then you can create a [playlist]({{< relref "../dashboards/create-manage-playlists/" >}}). If you are the administrator for an enterprise and are managing Grafana for multiple teams, then you can set up [provisioning]({{< relref "../administration/provisioning/" >}}) and [authentication]({{< relref "../setup-grafana/configure-security/configure-authentication/" >}}).
|
||||
|
||||
@@ -71,3 +71,5 @@ In addition to Grafana, Grafana Labs also provides the following open source pro
|
||||
**Grafana Tempo:** Grafana Tempo is an open source, easy-to-use and high-volume distributed tracing backend. For more information, refer to [Grafana Tempo documentation](https://grafana.com/docs/tempo/latest/?pg=oss-tempo&plcmt=hero-txt/).
|
||||
|
||||
**Grafana Mimir:** Grafana Mimir is an open source software project that provides a scalable long-term storage for Prometheus. For more information about Grafana Mimir, refer to [Grafana Mimir documentation](https://grafana.com/docs/mimir/latest/).
|
||||
|
||||
**Grafana Phlare:** Grafana Phlare is an open-source software project for aggregating continuous profiling data. Continuous profiling is an observability signal that enables you to understand your workload's resource (CPU, memory, etc.) usage to the exact line number. For more information about using Grafana Phlare, refer to [Grafana Phlare documentation](https://grafana.com/docs/phlare/latest/).
|
||||
|
||||
@@ -26,6 +26,8 @@ On each dashboard load, this panel queries the dashboard list, always providing
|
||||
|
||||
Use these options to refine your visualization.
|
||||
|
||||
- **Include current time range -** Select this option to propagate the time range of the current dashboard to the dashboard links. When the user clicks a link, the linked dashboard opens with the indicated time range already set.
|
||||
- **Include current template variable values -** Select this option to include template variables currently used as query parameters in a link. When the user clicks the link, any matching templates in the linked dashboard are set to the values from the link. Learn more about [Dashboard URL variables]({{< relref "../../../dashboards/build-dashboards/create-dashboard-url-variables/" >}}).
|
||||
- **Starred -** Display starred dashboards in alphabetical order.
|
||||
- **Recently viewed -** Display recently viewed dashboards in alphabetical order.
|
||||
- **Search -** Display dashboards by search query or tags. You must enter at least one value in **Query** or **Tags**. For the **Query** and **Tags** fields. Variable interpolation is supported, for example,`$my_var` or `${my_var}`.
|
||||
|
||||
@@ -47,6 +47,7 @@ Some stable features are enabled by default. You can disable a stable feature by
|
||||
| `validateDashboardsOnSave` | Validate dashboard JSON POSTed to api/dashboards/db |
|
||||
| `autoMigrateOldPanels` | Migrate old angular panels to supported versions (graph, table-old, worldmap, etc) |
|
||||
| `disableAngular` | Dynamic flag to disable angular at runtime. The preferred method is to set `angular_support_enabled` to `false` in the [security] settings, which allows you to change the state at runtime. |
|
||||
| `grpcServer` | Run the GRPC server |
|
||||
| `accessControlOnCall` | Access control primitives for OnCall |
|
||||
| `alertingNoNormalState` | Stop maintaining state of alerts that are not firing |
|
||||
| `disableElasticsearchBackendExploreQuery` | Disable executing of Elasticsearch Explore queries trough backend |
|
||||
@@ -59,7 +60,6 @@ Alpha features might be changed or removed without prior notice.
|
||||
|
||||
| Feature toggle name | Description |
|
||||
| ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `alertingBigTransactions` | Use big transactions for alerting database writes |
|
||||
| `dashboardPreviews` | Create and show thumbnails for dashboard search results |
|
||||
| `live-service-web-worker` | This will use a webworker thread to processes events rather than the main thread |
|
||||
| `queryOverLive` | Use Grafana Live WebSocket to execute backend queries |
|
||||
@@ -83,6 +83,7 @@ Alpha features might be changed or removed without prior notice.
|
||||
| `showDashboardValidationWarnings` | Show warnings when dashboards do not validate against the schema |
|
||||
| `mysqlAnsiQuotes` | Use double quotes to escape keyword in a MySQL query |
|
||||
| `elasticsearchBackendMigration` | Use Elasticsearch as backend data source |
|
||||
| `showTraceId` | Show trace ids for requests |
|
||||
| `datasourceOnboarding` | Enable data source onboarding page |
|
||||
| `secureSocksDatasourceProxy` | Enable secure socks tunneling for supported core datasources |
|
||||
| `authnService` | Use new auth service to perform authentication |
|
||||
@@ -105,6 +106,7 @@ Alpha features might be changed or removed without prior notice.
|
||||
| `alertStateHistoryLokiPrimary` | Enable a remote Loki instance as the primary source for state history reads. |
|
||||
| `alertStateHistoryLokiOnly` | Disable Grafana alerts from emitting annotations when a remote Loki instance is available. |
|
||||
| `unifiedRequestLog` | Writes error logs to the request logger |
|
||||
| `pyroscopeFlameGraph` | Changes flame graph to pyroscope one |
|
||||
|
||||
## Development feature toggles
|
||||
|
||||
@@ -113,6 +115,5 @@ The following toggles require explicitly setting Grafana's [app mode]({{< relref
|
||||
| Feature toggle name | Description |
|
||||
| ------------------- | --------------------------------------------------- |
|
||||
| `k8s` | Explore native k8s integrations |
|
||||
| `grpcServer` | Run GRPC server |
|
||||
| `entityStore` | SQL-based entity store (requires storage flag also) |
|
||||
| `nestedFolders` | Enable folder nesting |
|
||||
|
||||
+1
@@ -19,6 +19,7 @@ weight: 900
|
||||
The enhanced LDAP integration adds additional functionality on top of the [LDAP integration]({{< relref "ldap/" >}}) available in the open source edition of Grafana.
|
||||
|
||||
> **Note:** Available in [Grafana Enterprise]({{< relref "../../../../introduction/grafana-enterprise/" >}}) and [Grafana Cloud Advanced](/docs/grafana-cloud).
|
||||
> If you are a Grafana Cloud customer, please [open a support ticket in the Cloud Portal](/profile/org#support) to request this feature.
|
||||
|
||||
> To control user access with role-based permissions, refer to [role-based access control]({{< relref "../../../../administration/roles-and-permissions/access-control/" >}}).
|
||||
|
||||
|
||||
@@ -296,6 +296,10 @@ We've added support for JWT authentication.
|
||||
|
||||
We've added support for custom session parameters.
|
||||
|
||||
## Postgres, MySQL, and MSSQL data sources
|
||||
|
||||
The `database` property is now under the `jsonData` key in the data source configuration. This change is backward compatible, and existing configurations will continue to work.
|
||||
|
||||
## Before you upgrade
|
||||
|
||||
There are no known breaking changes associated with this version of Grafana.
|
||||
|
||||
@@ -8,7 +8,11 @@ e2e.scenario({
|
||||
skipScenario: false,
|
||||
scenario: () => {
|
||||
// Opening a dashboard without template variables
|
||||
e2e().intercept('POST', '/api/ds/query').as('query');
|
||||
e2e()
|
||||
.intercept({
|
||||
pathname: '/api/ds/query',
|
||||
})
|
||||
.as('query');
|
||||
e2e.flows.openDashboard({ uid: 'ZqZnVvFZz' });
|
||||
e2e().wait('@query');
|
||||
|
||||
@@ -65,7 +69,12 @@ e2e.scenario({
|
||||
skipScenario: false,
|
||||
scenario: () => {
|
||||
// Opening a dashboard without template variables
|
||||
e2e().intercept('POST', '/api/ds/query').as('query');
|
||||
e2e()
|
||||
.intercept({
|
||||
method: 'POST',
|
||||
pathname: '/api/ds/query',
|
||||
})
|
||||
.as('query');
|
||||
e2e.flows.openDashboard({ uid: 'ZqZnVvFZz' });
|
||||
e2e().wait('@query');
|
||||
|
||||
@@ -109,7 +118,12 @@ e2e.scenario({
|
||||
skipScenario: false,
|
||||
scenario: () => {
|
||||
// Opening a dashboard without template variables
|
||||
e2e().intercept('/api/ds/query').as('query');
|
||||
e2e()
|
||||
.intercept({
|
||||
method: 'POST',
|
||||
pathname: '/api/ds/query',
|
||||
})
|
||||
.as('query');
|
||||
e2e.flows.openDashboard({ uid: 'ZqZnVvFZz' });
|
||||
e2e().wait('@query');
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ describe('Variables - Load options from Url', () => {
|
||||
e2e()
|
||||
.intercept({
|
||||
method: 'POST',
|
||||
url: '/api/ds/query',
|
||||
pathname: '/api/ds/query*',
|
||||
})
|
||||
.as('query');
|
||||
|
||||
@@ -61,7 +61,7 @@ describe('Variables - Load options from Url', () => {
|
||||
e2e()
|
||||
.intercept({
|
||||
method: 'POST',
|
||||
url: '/api/ds/query',
|
||||
pathname: '/api/ds/query',
|
||||
})
|
||||
.as('query');
|
||||
|
||||
@@ -124,7 +124,7 @@ describe('Variables - Load options from Url', () => {
|
||||
e2e()
|
||||
.intercept({
|
||||
method: 'POST',
|
||||
url: '/api/ds/query',
|
||||
pathname: '/api/ds/query',
|
||||
})
|
||||
.as('query');
|
||||
|
||||
|
||||
@@ -61,7 +61,11 @@ describe('Variables - Set options from ui', () => {
|
||||
it('adding a value that is not part of dependents options should add the new values dependant options', () => {
|
||||
e2e.flows.login('admin', 'admin');
|
||||
e2e.flows.openDashboard({ uid: `${PAGE_UNDER_TEST}?orgId=1&var-datacenter=A&var-server=AA&var-pod=AAA` });
|
||||
e2e().intercept('/api/ds/query').as('query');
|
||||
e2e()
|
||||
.intercept({
|
||||
pathname: '/api/ds/query',
|
||||
})
|
||||
.as('query');
|
||||
|
||||
e2e().wait('@query');
|
||||
|
||||
@@ -119,7 +123,7 @@ describe('Variables - Set options from ui', () => {
|
||||
e2e.flows.openDashboard({
|
||||
uid: `${PAGE_UNDER_TEST}?orgId=1&var-datacenter=A&var-datacenter=B&var-server=AA&var-server=BB&var-pod=AAA&var-pod=BBB`,
|
||||
});
|
||||
e2e().intercept('/api/ds/query').as('query');
|
||||
e2e().intercept({ pathname: '/api/ds/query' }).as('query');
|
||||
|
||||
e2e().wait('@query');
|
||||
|
||||
|
||||
@@ -9,7 +9,11 @@ e2e.scenario({
|
||||
addScenarioDashBoard: false,
|
||||
skipScenario: false,
|
||||
scenario: () => {
|
||||
e2e().intercept('/api/ds/query').as('query');
|
||||
e2e()
|
||||
.intercept({
|
||||
pathname: '/api/ds/query',
|
||||
})
|
||||
.as('query');
|
||||
e2e.flows.openDashboard({ uid: 'TkZXxlNG3' });
|
||||
e2e().wait('@query');
|
||||
|
||||
@@ -79,6 +83,7 @@ e2e.scenario({
|
||||
e2e.components.PluginVisualization.current().should((e) => expect(e).to.contain('Time series'));
|
||||
|
||||
// Check that table view works
|
||||
e2e.components.Panels.Panel.loadingBar().should('not.exist');
|
||||
e2e.components.PanelEditor.toggleTableView().click({ force: true });
|
||||
e2e.components.Panels.Visualization.Table.header()
|
||||
.should('be.visible')
|
||||
|
||||
+23
-17
@@ -11,24 +11,30 @@ describe('MySQL datasource', () => {
|
||||
it('code editor autocomplete should handle table name escaping/quoting', () => {
|
||||
e2e.flows.login('admin', 'admin');
|
||||
|
||||
e2e().intercept('POST', '**/api/ds/query', (req) => {
|
||||
if (req.body.queries[0].refId === 'datasets') {
|
||||
req.alias = 'datasets';
|
||||
req.reply({
|
||||
body: datasetResponse,
|
||||
});
|
||||
} else if (req.body.queries[0].refId === 'tables') {
|
||||
req.alias = 'tables';
|
||||
req.reply({
|
||||
body: tablesResponse,
|
||||
});
|
||||
} else if (req.body.queries[0].refId === 'fields') {
|
||||
req.alias = 'fields';
|
||||
req.reply({
|
||||
body: fieldsResponse,
|
||||
});
|
||||
e2e().intercept(
|
||||
'POST',
|
||||
{
|
||||
pathname: '/api/ds/query',
|
||||
},
|
||||
(req) => {
|
||||
if (req.body.queries[0].refId === 'datasets') {
|
||||
req.alias = 'datasets';
|
||||
req.reply({
|
||||
body: datasetResponse,
|
||||
});
|
||||
} else if (req.body.queries[0].refId === 'tables') {
|
||||
req.alias = 'tables';
|
||||
req.reply({
|
||||
body: tablesResponse,
|
||||
});
|
||||
} else if (req.body.queries[0].refId === 'fields') {
|
||||
req.alias = 'fields';
|
||||
req.reply({
|
||||
body: fieldsResponse,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
e2e.pages.Explore.visit();
|
||||
|
||||
|
||||
@@ -32,16 +32,21 @@ describe('Exemplars', () => {
|
||||
});
|
||||
|
||||
it('should be able to navigate to configured data source', () => {
|
||||
let intercept = 'prometheus';
|
||||
e2e().intercept('/api/ds/query', (req) => {
|
||||
if (intercept === 'prometheus') {
|
||||
// For second intercept, we want to send tempo response
|
||||
intercept = 'tempo';
|
||||
req.reply({ fixture: 'exemplars-query-response.json' });
|
||||
} else {
|
||||
req.reply({ fixture: 'tempo-response.json' });
|
||||
e2e().intercept(
|
||||
{
|
||||
pathname: '/api/ds/query',
|
||||
},
|
||||
(req) => {
|
||||
const datasourceType = req.body.queries[0].datasource.type;
|
||||
if (datasourceType === 'prometheus') {
|
||||
req.reply({ fixture: 'exemplars-query-response.json' });
|
||||
} else if (datasourceType === 'tempo') {
|
||||
req.reply({ fixture: 'tempo-response.json' });
|
||||
} else {
|
||||
req.reply({});
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
e2e.pages.Explore.visit();
|
||||
|
||||
|
||||
@@ -11,7 +11,15 @@ e2e.scenario({
|
||||
e2e.pages.Explore.General.container().should('have.length', 1);
|
||||
e2e.components.RefreshPicker.runButtonV2().should('have.length', 1);
|
||||
|
||||
// delete query history queries that would be unrelated
|
||||
e2e.components.QueryTab.queryHistoryButton().should('be.visible').click();
|
||||
cy.get('button[title="Delete query"]').each((button) => {
|
||||
button.trigger('click');
|
||||
});
|
||||
e2e.components.QueryTab.queryHistoryButton().should('be.visible').click();
|
||||
|
||||
e2e.components.DataSource.TestData.QueryTab.scenarioSelectContainer()
|
||||
.scrollIntoView()
|
||||
.should('be.visible')
|
||||
.within(() => {
|
||||
e2e().get('input[id*="test-data-scenario-select-"]').should('be.visible').click();
|
||||
|
||||
@@ -67,7 +67,7 @@ require (
|
||||
github.com/grafana/cuetsy v0.1.6
|
||||
github.com/grafana/grafana-aws-sdk v0.12.0
|
||||
github.com/grafana/grafana-azure-sdk-go v1.6.0
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.157.0
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.158.0
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
|
||||
github.com/hashicorp/go-hclog v1.2.0
|
||||
github.com/hashicorp/go-plugin v1.4.3
|
||||
|
||||
@@ -1297,6 +1297,8 @@ github.com/grafana/grafana-plugin-sdk-go v0.94.0/go.mod h1:3VXz4nCv6wH5SfgB3mlW3
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.114.0/go.mod h1:D7x3ah+1d4phNXpbnOaxa/osSaZlwh9/ZUnGGzegRbk=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.157.0 h1:Qm0r5A4TsG+Tmy8Vagffqv21t3R/tzFUdYZZpd9COYE=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.157.0/go.mod h1:FwinU1fti54nWWsacIdL8D2WfYcKOWB2VRMtxnBbY+o=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.158.0 h1:kucTwr4LEa6hoSunnRqkuEeJOgbBTFrhdGNkJrMV4Zg=
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.158.0/go.mod h1:7/F3lL/w3MGuZTwu0jam5oL/4zNOQmhs2k8WZ9VlzhI=
|
||||
github.com/grafana/kindsys v0.0.0-20230309200316-812b9884a375 h1:iWFjqAU5GjIV/HetIE/Me6VF3SRw29u5QviMVbJUVQo=
|
||||
github.com/grafana/kindsys v0.0.0-20230309200316-812b9884a375/go.mod h1:213a3clTiegHfheYcLPLeEyHv/azK/fAF67OEbzuLzw=
|
||||
github.com/grafana/mysql v1.6.8 h1:kyo38C4NgghJMqaPrkWPy4rifAcipQVF+dKttfpgTCs=
|
||||
|
||||
+4
-2
@@ -1,6 +1,8 @@
|
||||
{
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true,
|
||||
"packages": ["packages/*"],
|
||||
"version": "9.5.0-pre"
|
||||
"packages": [
|
||||
"packages/*"
|
||||
],
|
||||
"version": "10.0.0-pre"
|
||||
}
|
||||
|
||||
+3
-2
@@ -3,7 +3,7 @@
|
||||
"license": "AGPL-3.0-only",
|
||||
"private": true,
|
||||
"name": "grafana",
|
||||
"version": "9.5.0-pre",
|
||||
"version": "10.0.0-pre",
|
||||
"repository": "github:grafana/grafana",
|
||||
"scripts": {
|
||||
"build": "yarn i18n:compile && NODE_ENV=production webpack --progress --config scripts/webpack/webpack.prod.js",
|
||||
@@ -266,7 +266,7 @@
|
||||
"@grafana/lezer-logql": "0.1.2",
|
||||
"@grafana/monaco-logql": "^0.0.7",
|
||||
"@grafana/runtime": "workspace:*",
|
||||
"@grafana/scenes": "^0.2.0",
|
||||
"@grafana/scenes": "^0.3.0",
|
||||
"@grafana/schema": "workspace:*",
|
||||
"@grafana/ui": "workspace:*",
|
||||
"@kusto/monaco-kusto": "5.3.6",
|
||||
@@ -279,6 +279,7 @@
|
||||
"@opentelemetry/semantic-conventions": "1.9.1",
|
||||
"@popperjs/core": "2.11.6",
|
||||
"@prometheus-io/lezer-promql": "^0.37.0-rc.1",
|
||||
"@pyroscope/flamegraph": "^0.35.5",
|
||||
"@react-aria/button": "3.6.1",
|
||||
"@react-aria/dialog": "3.3.1",
|
||||
"@react-aria/focus": "3.8.0",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"author": "Grafana Labs",
|
||||
"license": "Apache-2.0",
|
||||
"name": "@grafana/data",
|
||||
"version": "9.5.0-pre",
|
||||
"version": "10.0.0-pre",
|
||||
"description": "Grafana Data Library",
|
||||
"keywords": [
|
||||
"typescript"
|
||||
@@ -36,7 +36,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "6.0.2",
|
||||
"@grafana/schema": "9.5.0-pre",
|
||||
"@grafana/schema": "10.0.0-pre",
|
||||
"@types/d3-interpolate": "^3.0.0",
|
||||
"d3-interpolate": "3.0.1",
|
||||
"date-fns": "2.29.3",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { FieldType } from '../types/dataFrame';
|
||||
import { ArrayVector } from '..';
|
||||
import { DataFrame, FieldType } from '../types/dataFrame';
|
||||
|
||||
import { DataFrameJSON, dataFrameFromJSON } from './DataFrameJSON';
|
||||
import { DataFrameJSON, dataFrameFromJSON, dataFrameToJSON } from './DataFrameJSON';
|
||||
|
||||
describe('DataFrame JSON', () => {
|
||||
describe('when called with a DataFrame', () => {
|
||||
@@ -137,5 +138,104 @@ describe('DataFrame JSON', () => {
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should decode fields with nanos', () => {
|
||||
const json: DataFrameJSON = {
|
||||
schema: {
|
||||
fields: [
|
||||
{ name: 'time1', type: FieldType.time },
|
||||
{ name: 'time2', type: FieldType.time },
|
||||
],
|
||||
},
|
||||
data: {
|
||||
values: [
|
||||
[1, 2, 3],
|
||||
[4, 5, 6],
|
||||
],
|
||||
nanos: [null, [7, 8, 9]],
|
||||
},
|
||||
};
|
||||
|
||||
const frame = dataFrameFromJSON(json);
|
||||
expect(frame).toMatchInlineSnapshot(`
|
||||
{
|
||||
"fields": [
|
||||
{
|
||||
"config": {},
|
||||
"entities": {},
|
||||
"name": "time1",
|
||||
"type": "time",
|
||||
"values": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
],
|
||||
},
|
||||
{
|
||||
"config": {},
|
||||
"entities": {},
|
||||
"name": "time2",
|
||||
"nanos": [
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
],
|
||||
"type": "time",
|
||||
"values": [
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
],
|
||||
},
|
||||
],
|
||||
"length": 3,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should encode fields with nanos', () => {
|
||||
const inputFrame: DataFrame = {
|
||||
refId: 'A',
|
||||
meta: {},
|
||||
name: 'f1',
|
||||
fields: [
|
||||
{
|
||||
name: 'time1',
|
||||
type: FieldType.time,
|
||||
config: {},
|
||||
values: new ArrayVector([11, 12, 13]),
|
||||
},
|
||||
{
|
||||
name: 'time2',
|
||||
type: FieldType.time,
|
||||
config: {},
|
||||
values: new ArrayVector([14, 15, 16]),
|
||||
nanos: [17, 18, 19],
|
||||
},
|
||||
],
|
||||
length: 3,
|
||||
};
|
||||
|
||||
const expectedJSON: DataFrameJSON = {
|
||||
schema: {
|
||||
fields: [
|
||||
{ name: 'time1', type: FieldType.time, config: {} },
|
||||
{ name: 'time2', type: FieldType.time, config: {} },
|
||||
],
|
||||
meta: {},
|
||||
name: 'f1',
|
||||
refId: 'A',
|
||||
},
|
||||
data: {
|
||||
nanos: [null, [17, 18, 19]],
|
||||
values: [
|
||||
[11, 12, 13],
|
||||
[14, 15, 16],
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
expect(dataFrameToJSON(inputFrame)).toStrictEqual(expectedJSON);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { DataFrame, FieldType, FieldConfig, Labels, QueryResultMeta } from '../types';
|
||||
import { DataFrame, FieldType, FieldConfig, Labels, QueryResultMeta, Field } from '../types';
|
||||
import { ArrayVector } from '../vector';
|
||||
|
||||
import { guessFieldTypeFromNameAndValue } from './processDataFrame';
|
||||
@@ -56,6 +56,13 @@ export interface DataFrameData {
|
||||
* NOTE: currently only decoding is implemented
|
||||
*/
|
||||
enums?: Array<string[] | null>;
|
||||
|
||||
/**
|
||||
* Holds integers between 0 and 999999, used by time-fields
|
||||
* to store the nanosecond-precision that cannot be represented
|
||||
* by the millisecond-based base value.
|
||||
*/
|
||||
nanos?: Array<number[] | null>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -188,9 +195,11 @@ export function dataFrameFromJSON(dto: DataFrameJSON): DataFrame {
|
||||
type = FieldType.string;
|
||||
}
|
||||
|
||||
const nanos = data?.nanos?.[index];
|
||||
|
||||
// TODO: expand arrays further using bases,factors
|
||||
|
||||
return {
|
||||
const dataFrameField: Field & { entities: FieldValueEntityLookup } = {
|
||||
...f,
|
||||
type: type ?? guessFieldType(f.name, buffer),
|
||||
config: f.config ?? {},
|
||||
@@ -198,6 +207,12 @@ export function dataFrameFromJSON(dto: DataFrameJSON): DataFrame {
|
||||
// the presence of this prop is an optimization signal & lookup for consumers
|
||||
entities: entities ?? {},
|
||||
};
|
||||
|
||||
if (nanos != null) {
|
||||
dataFrameField.nanos = nanos;
|
||||
}
|
||||
|
||||
return dataFrameField;
|
||||
});
|
||||
|
||||
return {
|
||||
@@ -216,18 +231,34 @@ export function dataFrameToJSON(frame: DataFrame): DataFrameJSON {
|
||||
const data: DataFrameData = {
|
||||
values: [],
|
||||
};
|
||||
|
||||
const allNanos: Array<number[] | null> = [];
|
||||
let hasNanos = false;
|
||||
|
||||
const schema: DataFrameSchema = {
|
||||
refId: frame.refId,
|
||||
meta: frame.meta,
|
||||
name: frame.name,
|
||||
fields: frame.fields.map((f) => {
|
||||
const { values, state, display, ...sfield } = f;
|
||||
const { values, nanos, state, display, ...sfield } = f;
|
||||
delete (sfield as any).entities;
|
||||
data.values.push(values.toArray());
|
||||
|
||||
if (nanos != null) {
|
||||
allNanos.push(nanos);
|
||||
hasNanos = true;
|
||||
} else {
|
||||
allNanos.push(null);
|
||||
}
|
||||
|
||||
return sfield;
|
||||
}),
|
||||
};
|
||||
|
||||
if (hasNanos) {
|
||||
data.nanos = allNanos;
|
||||
}
|
||||
|
||||
return {
|
||||
schema,
|
||||
data,
|
||||
|
||||
@@ -6,7 +6,7 @@ import { ReducerID } from '../transformations/fieldReducer';
|
||||
import { FieldConfigPropertyItem, MappingType, SpecialValueMatch, ValueMapping } from '../types';
|
||||
|
||||
import { getDisplayProcessor } from './displayProcessor';
|
||||
import { getFieldDisplayValues, GetFieldDisplayValuesOptions } from './fieldDisplay';
|
||||
import { fixCellTemplateExpressions, getFieldDisplayValues, GetFieldDisplayValuesOptions } from './fieldDisplay';
|
||||
import { standardFieldConfigEditorRegistry } from './standardFieldConfigEditorRegistry';
|
||||
|
||||
describe('FieldDisplay', () => {
|
||||
@@ -534,3 +534,11 @@ function createDisplayOptions(extend: Partial<GetFieldDisplayValuesOptions> = {}
|
||||
|
||||
return merge(options, extend);
|
||||
}
|
||||
|
||||
describe('fixCellTemplateExpressions', () => {
|
||||
it('Should replace __cell_x correctly', () => {
|
||||
expect(fixCellTemplateExpressions('$__cell_10 asd ${__cell_15} asd [[__cell_20]]')).toEqual(
|
||||
'${__data.fields[10]} asd ${__data.fields[15]} asd ${__data.fields[20]}'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { toString, isEmpty } from 'lodash';
|
||||
import { isEmpty } from 'lodash';
|
||||
|
||||
import { DataFrameView } from '../dataframe/DataFrameView';
|
||||
import { getTimeField } from '../dataframe/processDataFrame';
|
||||
@@ -96,7 +96,6 @@ export const getFieldDisplayValues = (options: GetFieldDisplayValuesOptions): Fi
|
||||
|
||||
const data = options.data ?? [];
|
||||
const limit = reduceOptions.limit ? reduceOptions.limit : DEFAULT_FIELD_DISPLAY_VALUES_LIMIT;
|
||||
const scopedVars: ScopedVars = {};
|
||||
|
||||
let hitLimit = false;
|
||||
|
||||
@@ -125,7 +124,7 @@ export const getFieldDisplayValues = (options: GetFieldDisplayValuesOptions): Fi
|
||||
};
|
||||
}
|
||||
|
||||
const displayName = field.config.displayName ?? '';
|
||||
let displayName = field.config.displayName ?? '';
|
||||
|
||||
const display =
|
||||
field.display ??
|
||||
@@ -137,23 +136,10 @@ export const getFieldDisplayValues = (options: GetFieldDisplayValuesOptions): Fi
|
||||
|
||||
// Show all rows
|
||||
if (reduceOptions.values) {
|
||||
const usesCellValues = displayName.indexOf(VAR_CELL_PREFIX) >= 0;
|
||||
|
||||
for (let j = 0; j < field.values.length; j++) {
|
||||
// Add all the row variables
|
||||
if (usesCellValues) {
|
||||
for (let k = 0; k < dataFrame.fields.length; k++) {
|
||||
const f = dataFrame.fields[k];
|
||||
const v = f.values.get(j);
|
||||
scopedVars[VAR_CELL_PREFIX + k] = {
|
||||
value: v,
|
||||
text: toString(v),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
field.state = setIndexForPaletteColor(field, values.length);
|
||||
|
||||
const scopedVars = getFieldScopedVarsWithDataContexAndRowIndex(field, j);
|
||||
const displayValue = display(field.values.get(j));
|
||||
const rowName = getSmartDisplayNameForRow(dataFrame, field, j, replaceVariables, scopedVars);
|
||||
const overrideColor = lookupRowColorFromOverride(rowName, options.fieldConfig, theme);
|
||||
@@ -190,14 +176,13 @@ export const getFieldDisplayValues = (options: GetFieldDisplayValuesOptions): Fi
|
||||
});
|
||||
|
||||
for (const calc of calcs) {
|
||||
const scopedVars = field.state?.scopedVars ?? {};
|
||||
scopedVars[VAR_CALC] = { value: calc, text: calc };
|
||||
|
||||
const displayValue = display(results[calc]);
|
||||
|
||||
if (displayName !== '') {
|
||||
displayValue.title = replaceVariables(displayName, {
|
||||
...field.state?.scopedVars, // series and field scoped vars
|
||||
...scopedVars,
|
||||
});
|
||||
displayValue.title = replaceVariables(displayName, scopedVars);
|
||||
} else {
|
||||
displayValue.title = getFieldDisplayName(field, dataFrame, data);
|
||||
}
|
||||
@@ -247,18 +232,22 @@ function getSmartDisplayNameForRow(
|
||||
field: Field,
|
||||
rowIndex: number,
|
||||
replaceVariables: InterpolateFunction,
|
||||
scopedVars: ScopedVars
|
||||
scopedVars: ScopedVars | undefined
|
||||
): string {
|
||||
const displayName = field.config.displayName;
|
||||
|
||||
if (displayName) {
|
||||
// Handle old __cell_n syntax
|
||||
if (displayName.indexOf(VAR_CELL_PREFIX)) {
|
||||
return replaceVariables(fixCellTemplateExpressions(displayName), scopedVars);
|
||||
}
|
||||
|
||||
return replaceVariables(displayName, scopedVars);
|
||||
}
|
||||
|
||||
let parts: string[] = [];
|
||||
let otherNumericFields = 0;
|
||||
|
||||
if (field.config.displayName) {
|
||||
return replaceVariables(field.config.displayName, {
|
||||
...field.state?.scopedVars, // series and field scoped vars
|
||||
...scopedVars,
|
||||
});
|
||||
}
|
||||
|
||||
for (const otherField of frame.fields) {
|
||||
if (otherField === field) {
|
||||
continue;
|
||||
@@ -382,3 +371,28 @@ function getDisplayText(display: DisplayValue, fallback: string): string {
|
||||
}
|
||||
return display.text;
|
||||
}
|
||||
|
||||
export function fixCellTemplateExpressions(str: string) {
|
||||
return str.replace(/\${__cell_(\d+)}|\[\[__cell_(\d+)\]\]|\$__cell_(\d+)/g, (match, fmt1, fmt2, fmt3) => {
|
||||
return `\${__data.fields[${fmt1 ?? fmt2 ?? fmt3}]}`;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones the existing dataContext and adds rowIndex to it
|
||||
*/
|
||||
function getFieldScopedVarsWithDataContexAndRowIndex(field: Field, rowIndex: number): ScopedVars | undefined {
|
||||
if (field.state?.scopedVars?.__dataContext) {
|
||||
return {
|
||||
...field.state?.scopedVars,
|
||||
__dataContext: {
|
||||
value: {
|
||||
...field.state?.scopedVars?.__dataContext.value,
|
||||
rowIndex,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return field.state?.scopedVars;
|
||||
}
|
||||
|
||||
@@ -199,35 +199,9 @@ describe('applyFieldOverrides', () => {
|
||||
fieldConfigRegistry: new FieldConfigOptionsRegistry(),
|
||||
});
|
||||
|
||||
expect(withOverrides[0].fields[0].state!.scopedVars).toMatchInlineSnapshot(`
|
||||
{
|
||||
"__field": {
|
||||
"text": "Field",
|
||||
"value": {},
|
||||
},
|
||||
"__series": {
|
||||
"text": "Series",
|
||||
"value": {
|
||||
"name": "A",
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
|
||||
expect(withOverrides[1].fields[0].state!.scopedVars).toMatchInlineSnapshot(`
|
||||
{
|
||||
"__field": {
|
||||
"text": "Field",
|
||||
"value": {},
|
||||
},
|
||||
"__series": {
|
||||
"text": "Series",
|
||||
"value": {
|
||||
"name": "B",
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
expect(withOverrides[0].fields[0].state!.scopedVars?.__dataContext?.value.frame).toBe(withOverrides[0]);
|
||||
expect(withOverrides[0].fields[0].state!.scopedVars?.__dataContext?.value.frameIndex).toBe(0);
|
||||
expect(withOverrides[0].fields[0].state!.scopedVars?.__dataContext?.value.field).toBe(withOverrides[0].fields[0]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -441,6 +415,124 @@ describe('setFieldConfigDefaults', () => {
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('applies field config defaults correctly when links property exist in field config and no links are defined in panel', () => {
|
||||
const dsFieldConfig: FieldConfig = {
|
||||
links: [
|
||||
{
|
||||
title: 'Google link',
|
||||
url: 'https://google.com',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const panelFieldConfig: FieldConfig = {};
|
||||
|
||||
const context: FieldOverrideEnv = {
|
||||
data: [],
|
||||
field: { type: FieldType.number } as Field,
|
||||
dataFrameIndex: 0,
|
||||
fieldConfigRegistry: customFieldRegistry,
|
||||
};
|
||||
|
||||
// we mutate dsFieldConfig
|
||||
// @ts-ignore
|
||||
setFieldConfigDefaults(dsFieldConfig, panelFieldConfig, context);
|
||||
|
||||
expect(dsFieldConfig).toMatchInlineSnapshot(`
|
||||
{
|
||||
"custom": {},
|
||||
"links": [
|
||||
{
|
||||
"title": "Google link",
|
||||
"url": "https://google.com",
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('applies field config defaults correctly when links property exist in panel config and no links are defined in ds field config', () => {
|
||||
const dsFieldConfig: FieldConfig = {};
|
||||
|
||||
const panelFieldConfig: FieldConfig = {
|
||||
links: [
|
||||
{
|
||||
title: 'Google link',
|
||||
url: 'https://google.com',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const context: FieldOverrideEnv = {
|
||||
data: [],
|
||||
field: { type: FieldType.number } as Field,
|
||||
dataFrameIndex: 0,
|
||||
fieldConfigRegistry: customFieldRegistry,
|
||||
};
|
||||
|
||||
// we mutate dsFieldConfig
|
||||
// @ts-ignore
|
||||
setFieldConfigDefaults(dsFieldConfig, panelFieldConfig, context);
|
||||
|
||||
expect(dsFieldConfig).toMatchInlineSnapshot(`
|
||||
{
|
||||
"custom": {},
|
||||
"links": [
|
||||
{
|
||||
"title": "Google link",
|
||||
"url": "https://google.com",
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('applies a merge strategy for links when they exist in ds config and panel', () => {
|
||||
const dsFieldConfig: FieldConfig = {
|
||||
links: [
|
||||
{
|
||||
title: 'Google link',
|
||||
url: 'https://google.com',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const panelFieldConfig: FieldConfig = {
|
||||
links: [
|
||||
{
|
||||
title: 'Grafana',
|
||||
url: 'https://grafana.com',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const context: FieldOverrideEnv = {
|
||||
data: [],
|
||||
field: { type: FieldType.number } as Field,
|
||||
dataFrameIndex: 0,
|
||||
fieldConfigRegistry: customFieldRegistry,
|
||||
};
|
||||
|
||||
// we mutate dsFieldConfig
|
||||
setFieldConfigDefaults(dsFieldConfig, panelFieldConfig, context);
|
||||
|
||||
expect(dsFieldConfig).toMatchInlineSnapshot(`
|
||||
{
|
||||
"custom": {},
|
||||
"links": [
|
||||
{
|
||||
"title": "Google link",
|
||||
"url": "https://google.com",
|
||||
},
|
||||
{
|
||||
"title": "Grafana",
|
||||
"url": "https://grafana.com",
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setDynamicConfigValue', () => {
|
||||
|
||||
@@ -39,10 +39,7 @@ import { mapInternalLinkToExplore } from '../utils/dataLinks';
|
||||
|
||||
import { FieldConfigOptionsRegistry } from './FieldConfigOptionsRegistry';
|
||||
import { getDisplayProcessor, getRawDisplayProcessor } from './displayProcessor';
|
||||
import { getFrameDisplayName } from './fieldState';
|
||||
import { getFieldDisplayValuesProxy } from './getFieldDisplayValuesProxy';
|
||||
import { standardFieldConfigEditorRegistry } from './standardFieldConfigEditorRegistry';
|
||||
import { getTemplateProxyForField } from './templateProxies';
|
||||
|
||||
interface OverrideProps {
|
||||
match: FieldMatcher;
|
||||
@@ -122,18 +119,17 @@ export function applyFieldOverrides(options: ApplyFieldOverrideOptions): DataFra
|
||||
};
|
||||
});
|
||||
|
||||
const scopedVars: ScopedVars = {
|
||||
__series: { text: 'Series', value: { name: getFrameDisplayName(newFrame, index) } }, // might be missing
|
||||
};
|
||||
|
||||
for (const field of newFrame.fields) {
|
||||
const config = field.config;
|
||||
|
||||
field.state!.scopedVars = {
|
||||
...scopedVars,
|
||||
__field: {
|
||||
text: 'Field',
|
||||
value: getTemplateProxyForField(field, newFrame, options.data),
|
||||
__dataContext: {
|
||||
value: {
|
||||
data: options.data!,
|
||||
frame: newFrame,
|
||||
frameIndex: index,
|
||||
field: field,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -293,6 +289,11 @@ export function setDynamicConfigValue(config: FieldConfig, value: DynamicConfigV
|
||||
// config -> from DS
|
||||
// defaults -> from Panel config
|
||||
export function setFieldConfigDefaults(config: FieldConfig, defaults: FieldConfig, context: FieldOverrideEnv) {
|
||||
// For cases where we have links on the datasource config and the panel config, we need to merge them
|
||||
if (config.links && defaults.links) {
|
||||
// Combine the data source links and the panel default config links
|
||||
config.links = [...config.links, ...defaults.links];
|
||||
}
|
||||
for (const fieldConfigProperty of context.fieldConfigRegistry.list()) {
|
||||
if (fieldConfigProperty.isCustom && !config.custom) {
|
||||
config.custom = {};
|
||||
@@ -371,49 +372,29 @@ export const getLinksSupplier =
|
||||
}
|
||||
|
||||
return field.config.links.map((link: DataLink) => {
|
||||
let dataFrameVars = {};
|
||||
let dataContext: DataContextScopedVar = { value: { frame, field } };
|
||||
const dataContext: DataContextScopedVar = getFieldDataContextClone(frame, field, fieldScopedVars);
|
||||
const dataLinkScopedVars = {
|
||||
...fieldScopedVars,
|
||||
__dataContext: dataContext,
|
||||
};
|
||||
|
||||
// We are not displaying reduction result
|
||||
if (config.valueRowIndex !== undefined && !isNaN(config.valueRowIndex)) {
|
||||
dataContext.value.rowIndex = config.valueRowIndex;
|
||||
|
||||
const fieldsProxy = getFieldDisplayValuesProxy({
|
||||
frame,
|
||||
rowIndex: config.valueRowIndex,
|
||||
timeZone: timeZone,
|
||||
});
|
||||
|
||||
dataFrameVars = {
|
||||
__data: {
|
||||
value: {
|
||||
name: frame.name,
|
||||
refId: frame.refId,
|
||||
fields: fieldsProxy,
|
||||
},
|
||||
text: 'Data',
|
||||
},
|
||||
};
|
||||
} else {
|
||||
dataContext.value.calculatedValue = config.calculatedValue;
|
||||
}
|
||||
|
||||
const variables: ScopedVars = {
|
||||
...fieldScopedVars,
|
||||
...dataFrameVars,
|
||||
__dataContext: dataContext,
|
||||
};
|
||||
|
||||
if (link.onClick) {
|
||||
return {
|
||||
href: link.url,
|
||||
title: replaceVariables(link.title || '', variables),
|
||||
title: replaceVariables(link.title || '', dataLinkScopedVars),
|
||||
target: link.targetBlank ? '_blank' : undefined,
|
||||
onClick: (evt, origin) => {
|
||||
link.onClick!({
|
||||
origin: origin ?? field,
|
||||
e: evt,
|
||||
replaceVariables: (v) => replaceVariables(v, variables),
|
||||
replaceVariables: (v) => replaceVariables(v, dataLinkScopedVars),
|
||||
});
|
||||
},
|
||||
origin: field,
|
||||
@@ -425,7 +406,7 @@ export const getLinksSupplier =
|
||||
return mapInternalLinkToExplore({
|
||||
link,
|
||||
internalLink: link.internal,
|
||||
scopedVars: variables,
|
||||
scopedVars: dataLinkScopedVars,
|
||||
field,
|
||||
range: link.internal.range ?? ({} as any),
|
||||
replaceVariables,
|
||||
@@ -440,13 +421,13 @@ export const getLinksSupplier =
|
||||
|
||||
if (href) {
|
||||
href = locationUtil.assureBaseUrl(href.replace(/\n/g, ''));
|
||||
href = replaceVariables(href, variables, VariableFormatID.PercentEncode);
|
||||
href = replaceVariables(href, dataLinkScopedVars, VariableFormatID.PercentEncode);
|
||||
href = locationUtil.processUrl(href);
|
||||
}
|
||||
|
||||
const info: LinkModel<Field> = {
|
||||
href,
|
||||
title: replaceVariables(link.title || '', variables),
|
||||
title: replaceVariables(link.title || '', dataLinkScopedVars),
|
||||
target: link.targetBlank ? '_blank' : undefined,
|
||||
origin: field,
|
||||
};
|
||||
@@ -530,3 +511,18 @@ export function useFieldOverrides(
|
||||
};
|
||||
}, [fieldConfigRegistry, fieldConfig, data, prevSeries, timeZone, theme, replace]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clones the existing dataContext or creates a new one
|
||||
*/
|
||||
function getFieldDataContextClone(frame: DataFrame, field: Field, fieldScopedVars: ScopedVars) {
|
||||
if (fieldScopedVars?.__dataContext) {
|
||||
return {
|
||||
value: {
|
||||
...fieldScopedVars.__dataContext.value,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return { value: { frame, field, data: [frame] } };
|
||||
}
|
||||
|
||||
@@ -16,9 +16,11 @@ export interface ScopedVars {
|
||||
*/
|
||||
export interface DataContextScopedVar {
|
||||
value: {
|
||||
data: DataFrame[];
|
||||
frame: DataFrame;
|
||||
field: Field;
|
||||
rowIndex?: number;
|
||||
frameIndex?: number;
|
||||
calculatedValue?: DisplayValue;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ export class AppPlugin<T extends KeyValue = KeyValue> extends GrafanaPlugin<AppP
|
||||
return this._extensionConfigs;
|
||||
}
|
||||
|
||||
configureExtensionLink<Context extends object>(extension: Exclude<PluginExtensionLinkConfig<Context>, 'type'>) {
|
||||
configureExtensionLink<Context extends object>(extension: Omit<PluginExtensionLinkConfig<Context>, 'type'>) {
|
||||
this._extensionConfigs.push({
|
||||
...extension,
|
||||
type: PluginExtensionTypes.link,
|
||||
|
||||
@@ -137,6 +137,14 @@ export interface Field<T = any, V = Vector<T>> {
|
||||
*/
|
||||
config: FieldConfig;
|
||||
values: V; // The raw field values
|
||||
|
||||
/**
|
||||
* When type === FieldType.Time, this can optionally store
|
||||
* the nanosecond-precison fractions as integers between
|
||||
* 0 and 999999.
|
||||
*/
|
||||
nanos?: number[];
|
||||
|
||||
labels?: Labels;
|
||||
|
||||
/**
|
||||
|
||||
@@ -465,6 +465,11 @@ export interface DataQueryResponse {
|
||||
* Defaults to LoadingState.Done if state is not defined
|
||||
*/
|
||||
state?: LoadingState;
|
||||
|
||||
/**
|
||||
* traceIds related to the response, if available
|
||||
*/
|
||||
traceIds?: string[];
|
||||
}
|
||||
|
||||
export enum DataQueryErrorType {
|
||||
@@ -488,6 +493,7 @@ export interface DataQueryError {
|
||||
status?: number;
|
||||
statusText?: string;
|
||||
refId?: string;
|
||||
traceId?: string;
|
||||
type?: DataQueryErrorType;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
* @public
|
||||
*/
|
||||
export interface FeatureToggles {
|
||||
alertingBigTransactions?: boolean;
|
||||
trimDefaults?: boolean;
|
||||
disableEnvelopeEncryption?: boolean;
|
||||
database_metrics?: boolean;
|
||||
@@ -65,6 +64,7 @@ export interface FeatureToggles {
|
||||
nestedFolders?: boolean;
|
||||
accessTokenExpirationCheck?: boolean;
|
||||
elasticsearchBackendMigration?: boolean;
|
||||
showTraceId?: boolean;
|
||||
datasourceOnboarding?: boolean;
|
||||
emptyDashboardPage?: boolean;
|
||||
secureSocksDatasourceProxy?: boolean;
|
||||
@@ -93,4 +93,5 @@ export interface FeatureToggles {
|
||||
alertStateHistoryLokiOnly?: boolean;
|
||||
unifiedRequestLog?: boolean;
|
||||
renderAuthJWT?: boolean;
|
||||
pyroscopeFlameGraph?: boolean;
|
||||
}
|
||||
|
||||
@@ -66,6 +66,9 @@ export interface PanelData {
|
||||
|
||||
/** Contains the range from the request or a shifted time range if a request uses relative time */
|
||||
timeRange: TimeRange;
|
||||
|
||||
/** traceIds collected during the processing of the requests */
|
||||
traceIds?: string[];
|
||||
}
|
||||
|
||||
export interface PanelProps<T = any> {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { DataQuery } from '@grafana/schema';
|
||||
|
||||
import { RawTimeRange, TimeZone } from './time';
|
||||
|
||||
// Plugin Extensions types
|
||||
@@ -18,7 +20,7 @@ export type PluginExtension = {
|
||||
export type PluginExtensionLink = PluginExtension & {
|
||||
type: PluginExtensionTypes.link;
|
||||
path?: string;
|
||||
onClick?: (event: React.MouseEvent) => void;
|
||||
onClick?: (event?: React.MouseEvent) => void;
|
||||
};
|
||||
|
||||
// Objects used for registering extensions (in app plugins)
|
||||
@@ -43,7 +45,7 @@ export type PluginExtensionLinkConfig<Context extends object = object> = PluginE
|
||||
Context,
|
||||
Pick<PluginExtensionLink, 'path'> & {
|
||||
type: PluginExtensionTypes.link;
|
||||
onClick?: (event: React.MouseEvent, helpers: PluginExtensionEventHelpers<Context>) => void;
|
||||
onClick?: (event: React.MouseEvent | undefined, helpers: PluginExtensionEventHelpers<Context>) => void;
|
||||
}
|
||||
>;
|
||||
|
||||
@@ -73,7 +75,7 @@ export type PluginExtensionPanelContext = {
|
||||
timeRange: RawTimeRange;
|
||||
timeZone: TimeZone;
|
||||
dashboard: Dashboard;
|
||||
targets: Target[];
|
||||
targets: DataQuery[];
|
||||
};
|
||||
|
||||
type Dashboard = {
|
||||
@@ -81,8 +83,3 @@ type Dashboard = {
|
||||
title: string;
|
||||
tags: string[];
|
||||
};
|
||||
|
||||
type Target = {
|
||||
pluginId: string;
|
||||
refId: string;
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"author": "Grafana Labs",
|
||||
"license": "Apache-2.0",
|
||||
"name": "@grafana/e2e-selectors",
|
||||
"version": "9.5.0-pre",
|
||||
"version": "10.0.0-pre",
|
||||
"description": "Grafana End-to-End Test Selectors Library",
|
||||
"keywords": [
|
||||
"cli",
|
||||
|
||||
@@ -76,6 +76,7 @@ export const Components = {
|
||||
menu: (title: string) => `data-testid Panel menu ${title}`,
|
||||
containerByTitle: (title: string) => `${title} panel`,
|
||||
headerCornerInfo: (mode: string) => `Panel header ${mode}`,
|
||||
loadingBar: () => `Panel loading bar`,
|
||||
},
|
||||
Visualization: {
|
||||
Graph: {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"author": "Grafana Labs",
|
||||
"license": "Apache-2.0",
|
||||
"name": "@grafana/e2e",
|
||||
"version": "9.5.0-pre",
|
||||
"version": "10.0.0-pre",
|
||||
"description": "Grafana End-to-End Test Library",
|
||||
"keywords": [
|
||||
"cli",
|
||||
@@ -63,7 +63,7 @@
|
||||
"@babel/core": "7.20.5",
|
||||
"@babel/preset-env": "7.20.2",
|
||||
"@cypress/webpack-preprocessor": "5.17.0",
|
||||
"@grafana/e2e-selectors": "9.5.0-pre",
|
||||
"@grafana/e2e-selectors": "10.0.0-pre",
|
||||
"@grafana/tsconfig": "^1.2.0-rc1",
|
||||
"@mochajs/json-file-reporter": "^1.2.0",
|
||||
"babel-loader": "9.1.2",
|
||||
|
||||
@@ -91,15 +91,15 @@ export const configurePanel = (config: PartialAddPanelConfig | PartialEditPanelC
|
||||
e2e.components.Panels.Panel.headerItems('Edit').click();
|
||||
} else {
|
||||
try {
|
||||
e2e.components.PageToolbar.item('Add panel').should('be.visible');
|
||||
e2e.components.PageToolbar.item('Add panel').click();
|
||||
e2e.components.PageToolbar.itemButton('Add panel button').should('be.visible');
|
||||
e2e.components.PageToolbar.itemButton('Add panel button').click();
|
||||
} catch (e) {
|
||||
// Depending on the screen size, the "Add panel" button might be hidden
|
||||
e2e.components.PageToolbar.item('Show more items').click();
|
||||
e2e.components.PageToolbar.item('Add panel').last().click();
|
||||
e2e.components.PageToolbar.item('Add panel button').last().click();
|
||||
}
|
||||
e2e.pages.AddDashboard.addNewPanel().should('be.visible');
|
||||
e2e.pages.AddDashboard.addNewPanel().click();
|
||||
e2e.pages.AddDashboard.itemButton('Add new visualization menu item').should('be.visible');
|
||||
e2e.pages.AddDashboard.itemButton('Add new visualization menu item').click();
|
||||
}
|
||||
|
||||
if (timeRange) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@grafana/eslint-plugin",
|
||||
"description": "ESLint rules for use within the Grafana repo. Not suitable (or supported) for external use.",
|
||||
"version": "9.5.0-pre",
|
||||
"version": "10.0.0-pre",
|
||||
"main": "./index.cjs",
|
||||
"author": "Grafana Labs",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"author": "Grafana Labs",
|
||||
"license": "Apache-2.0",
|
||||
"name": "@grafana/runtime",
|
||||
"version": "9.5.0-pre",
|
||||
"version": "10.0.0-pre",
|
||||
"description": "Grafana Runtime Library",
|
||||
"keywords": [
|
||||
"grafana",
|
||||
@@ -37,10 +37,10 @@
|
||||
"postpack": "mv package.json.bak package.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@grafana/data": "9.5.0-pre",
|
||||
"@grafana/e2e-selectors": "9.5.0-pre",
|
||||
"@grafana/data": "10.0.0-pre",
|
||||
"@grafana/e2e-selectors": "10.0.0-pre",
|
||||
"@grafana/faro-web-sdk": "1.0.2",
|
||||
"@grafana/ui": "9.5.0-pre",
|
||||
"@grafana/ui": "10.0.0-pre",
|
||||
"@sentry/browser": "6.19.7",
|
||||
"history": "4.10.1",
|
||||
"lodash": "4.17.21",
|
||||
|
||||
@@ -96,6 +96,7 @@ export interface FetchResponse<T = any> {
|
||||
readonly type: ResponseType;
|
||||
readonly url: string;
|
||||
readonly config: BackendSrvRequest;
|
||||
readonly traceId?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,6 +123,7 @@ export interface FetchError<T = any> {
|
||||
cancelled?: boolean;
|
||||
isHandled?: boolean;
|
||||
config: BackendSrvRequest;
|
||||
traceId?: string;
|
||||
}
|
||||
|
||||
export function isFetchError(e: unknown): e is FetchError {
|
||||
|
||||
@@ -98,7 +98,7 @@ describe('DataSourceWithBackend', () => {
|
||||
"hideFromInspector": false,
|
||||
"method": "POST",
|
||||
"requestId": undefined,
|
||||
"url": "/api/ds/query",
|
||||
"url": "/api/ds/query?ds_type=dummy",
|
||||
}
|
||||
`);
|
||||
});
|
||||
@@ -153,7 +153,7 @@ describe('DataSourceWithBackend', () => {
|
||||
"hideFromInspector": false,
|
||||
"method": "POST",
|
||||
"requestId": undefined,
|
||||
"url": "/api/ds/query?expression=true",
|
||||
"url": "/api/ds/query?ds_type=dummy&expression=true",
|
||||
}
|
||||
`);
|
||||
});
|
||||
@@ -222,7 +222,7 @@ describe('DataSourceWithBackend', () => {
|
||||
"hideFromInspector": true,
|
||||
"method": "POST",
|
||||
"requestId": undefined,
|
||||
"url": "/api/ds/query",
|
||||
"url": "/api/ds/query?ds_type=dummy",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
@@ -202,10 +202,16 @@ class DataSourceWithBackend<
|
||||
headers[PluginRequestHeaders.PluginID] = Array.from(pluginIDs).join(', ');
|
||||
headers[PluginRequestHeaders.DatasourceUID] = Array.from(dsUIDs).join(', ');
|
||||
|
||||
let url = '/api/ds/query';
|
||||
let url = '/api/ds/query?ds_type=' + this.type;
|
||||
|
||||
if (hasExpr) {
|
||||
headers[PluginRequestHeaders.FromExpression] = 'true';
|
||||
url += '?expression=true';
|
||||
url += '&expression=true';
|
||||
}
|
||||
|
||||
// Appending request ID to url to facilitate client-side performance metrics. See #65244 for more context.
|
||||
if (requestId) {
|
||||
url += `&requestId=${requestId}`;
|
||||
}
|
||||
|
||||
if (request.dashboardUID) {
|
||||
|
||||
@@ -280,6 +280,82 @@ describe('Query Response parser', () => {
|
||||
expect(ids).toEqual(['A', 'B']);
|
||||
});
|
||||
|
||||
test('should handle a success-response without traceIds', () => {
|
||||
const input = {
|
||||
data: {
|
||||
results: {
|
||||
A: {
|
||||
frames: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
} as unknown as FetchResponse<BackendDataSourceResponse>;
|
||||
const res = toDataQueryResponse(input);
|
||||
expect(res.traceIds).toBeUndefined();
|
||||
});
|
||||
|
||||
test('should handle a success-response with traceIds', () => {
|
||||
const input = {
|
||||
data: {
|
||||
results: {
|
||||
A: {
|
||||
frames: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
traceId: 'traceId1',
|
||||
} as unknown as FetchResponse<BackendDataSourceResponse>;
|
||||
const res = toDataQueryResponse(input);
|
||||
expect(res.traceIds).toStrictEqual(['traceId1']);
|
||||
});
|
||||
|
||||
test('should handle an error-response without traceIds', () => {
|
||||
const input = {
|
||||
data: {
|
||||
results: {
|
||||
A: {
|
||||
error: 'error from A',
|
||||
status: 400,
|
||||
},
|
||||
B: {
|
||||
error: 'error from B',
|
||||
status: 400,
|
||||
},
|
||||
},
|
||||
},
|
||||
} as unknown as FetchResponse<BackendDataSourceResponse>;
|
||||
const res = toDataQueryResponse(input);
|
||||
expect(res.traceIds).toBeUndefined();
|
||||
expect(res.error?.traceId).toBeUndefined();
|
||||
expect(res.errors).toHaveLength(2);
|
||||
expect(res.errors?.[0].traceId).toBeUndefined();
|
||||
expect(res.errors?.[1].traceId).toBeUndefined();
|
||||
});
|
||||
|
||||
test('should handle an error-response with traceIds', () => {
|
||||
const input = {
|
||||
data: {
|
||||
results: {
|
||||
A: {
|
||||
error: 'error from A',
|
||||
status: 400,
|
||||
},
|
||||
B: {
|
||||
error: 'error from B',
|
||||
status: 400,
|
||||
},
|
||||
},
|
||||
},
|
||||
traceId: 'traceId1',
|
||||
} as unknown as FetchResponse<BackendDataSourceResponse>;
|
||||
const res = toDataQueryResponse(input);
|
||||
expect(res.traceIds).toStrictEqual(['traceId1']);
|
||||
expect(res.error?.traceId).toBe('traceId1');
|
||||
expect(res.errors).toHaveLength(2);
|
||||
expect(res.errors?.[0].traceId).toBe('traceId1');
|
||||
expect(res.errors?.[1].traceId).toBe('traceId1');
|
||||
});
|
||||
|
||||
describe('Cache notice', () => {
|
||||
let resp: FetchResponse<BackendDataSourceResponse>;
|
||||
|
||||
|
||||
@@ -65,6 +65,13 @@ export function toDataQueryResponse(
|
||||
queries?: DataQuery[]
|
||||
): DataQueryResponse {
|
||||
const rsp: DataQueryResponse = { data: [], state: LoadingState.Done };
|
||||
|
||||
const traceId = 'traceId' in res ? res.traceId : undefined;
|
||||
|
||||
if (traceId != null) {
|
||||
rsp.traceIds = [traceId];
|
||||
}
|
||||
|
||||
// If the response isn't in a correct shape we just ignore the data and pass empty DataQueryResponse.
|
||||
if ((res as FetchResponse).data?.results) {
|
||||
const results = (res as FetchResponse).data.results;
|
||||
@@ -83,17 +90,21 @@ export function toDataQueryResponse(
|
||||
|
||||
for (const dr of data) {
|
||||
if (dr.error) {
|
||||
const errorObj: DataQueryError = {
|
||||
refId: dr.refId,
|
||||
message: dr.error,
|
||||
status: dr.status,
|
||||
};
|
||||
if (traceId != null) {
|
||||
errorObj.traceId = traceId;
|
||||
}
|
||||
if (!rsp.error) {
|
||||
rsp.error = {
|
||||
refId: dr.refId,
|
||||
message: dr.error,
|
||||
status: dr.status,
|
||||
};
|
||||
rsp.error = { ...errorObj };
|
||||
}
|
||||
if (rsp.errors) {
|
||||
rsp.errors.push({ refId: dr.refId, message: dr.error, status: dr.status });
|
||||
rsp.errors.push({ ...errorObj });
|
||||
} else {
|
||||
rsp.errors = [{ refId: dr.refId, message: dr.error, status: dr.status }];
|
||||
rsp.errors = [{ ...errorObj }];
|
||||
}
|
||||
rsp.state = LoadingState.Error;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"author": "Grafana Labs",
|
||||
"license": "Apache-2.0",
|
||||
"name": "@grafana/schema",
|
||||
"version": "9.5.0-pre",
|
||||
"version": "10.0.0-pre",
|
||||
"description": "Grafana Schema Library",
|
||||
"keywords": [
|
||||
"typescript"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"author": "Grafana Labs",
|
||||
"license": "Apache-2.0",
|
||||
"name": "@grafana/toolkit",
|
||||
"version": "9.5.0-pre",
|
||||
"version": "10.0.0-pre",
|
||||
"description": "Grafana Toolkit",
|
||||
"keywords": [
|
||||
"grafana",
|
||||
@@ -51,10 +51,10 @@
|
||||
"@babel/preset-env": "7.18.9",
|
||||
"@babel/preset-react": "7.18.6",
|
||||
"@babel/preset-typescript": "7.18.6",
|
||||
"@grafana/data": "9.5.0-pre",
|
||||
"@grafana/data": "10.0.0-pre",
|
||||
"@grafana/eslint-config": "5.1.0",
|
||||
"@grafana/tsconfig": "^1.2.0-rc1",
|
||||
"@grafana/ui": "9.5.0-pre",
|
||||
"@grafana/ui": "10.0.0-pre",
|
||||
"@jest/core": "27.5.1",
|
||||
"@types/command-exists": "^1.2.0",
|
||||
"@types/eslint": "8.4.1",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"author": "Grafana Labs",
|
||||
"license": "Apache-2.0",
|
||||
"name": "@grafana/ui",
|
||||
"version": "9.5.0-pre",
|
||||
"version": "10.0.0-pre",
|
||||
"description": "Grafana Components Library",
|
||||
"keywords": [
|
||||
"grafana",
|
||||
@@ -49,10 +49,10 @@
|
||||
"dependencies": {
|
||||
"@emotion/css": "11.10.6",
|
||||
"@emotion/react": "11.10.6",
|
||||
"@grafana/data": "9.5.0-pre",
|
||||
"@grafana/e2e-selectors": "9.5.0-pre",
|
||||
"@grafana/data": "10.0.0-pre",
|
||||
"@grafana/e2e-selectors": "10.0.0-pre",
|
||||
"@grafana/faro-web-sdk": "1.0.2",
|
||||
"@grafana/schema": "9.5.0-pre",
|
||||
"@grafana/schema": "10.0.0-pre",
|
||||
"@leeoniya/ufuzzy": "1.0.6",
|
||||
"@monaco-editor/react": "4.4.6",
|
||||
"@popperjs/core": "2.11.6",
|
||||
|
||||
@@ -7,7 +7,6 @@ import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { useStyles2 } from '../../themes/ThemeContext';
|
||||
import { IconName } from '../../types';
|
||||
import { Icon } from '../Icon/Icon';
|
||||
import { HorizontalGroup } from '../Layout/Layout';
|
||||
import { Tooltip } from '../Tooltip/Tooltip';
|
||||
|
||||
export type BadgeColor = 'blue' | 'red' | 'green' | 'orange' | 'purple';
|
||||
@@ -23,10 +22,8 @@ export const Badge = React.memo<BadgeProps>(({ icon, color, text, tooltip, class
|
||||
const styles = useStyles2(useCallback((theme) => getStyles(theme, color), [color]));
|
||||
const badge = (
|
||||
<div className={cx(styles.wrapper, className)} {...otherProps}>
|
||||
<HorizontalGroup align="center" spacing="xs">
|
||||
{icon && <Icon name={icon} size="sm" />}
|
||||
<span>{text}</span>
|
||||
</HorizontalGroup>
|
||||
{icon && <Icon name={icon} size="sm" />}
|
||||
{text}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -59,7 +56,6 @@ const getStyles = (theme: GrafanaTheme2, color: BadgeColor) => {
|
||||
|
||||
return {
|
||||
wrapper: css`
|
||||
font-size: ${theme.typography.size.sm};
|
||||
display: inline-flex;
|
||||
padding: 1px 4px;
|
||||
border-radius: ${theme.shape.radius.default};
|
||||
@@ -67,12 +63,10 @@ const getStyles = (theme: GrafanaTheme2, color: BadgeColor) => {
|
||||
border: 1px solid ${borderColor};
|
||||
color: ${textColor};
|
||||
font-weight: ${theme.typography.fontWeightRegular};
|
||||
|
||||
> span {
|
||||
position: relative;
|
||||
top: 1px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
gap: 2px;
|
||||
font-size: ${theme.typography.bodySmall.fontSize};
|
||||
line-height: ${theme.typography.bodySmall.lineHeight};
|
||||
align-items: center;
|
||||
`,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -11,7 +11,7 @@ import { TooltipPlacement } from '../Tooltip/types';
|
||||
export interface Props {
|
||||
overlay: React.ReactElement | (() => React.ReactElement);
|
||||
placement?: TooltipPlacement;
|
||||
children: React.ReactElement | ((isOpen: boolean) => React.ReactElement);
|
||||
children: React.ReactElement;
|
||||
/** Amount in pixels to nudge the dropdown vertically and horizontally, respectively. */
|
||||
offset?: [number, number];
|
||||
onVisibleChange?: (state: boolean) => void;
|
||||
@@ -51,7 +51,7 @@ export const Dropdown = React.memo(({ children, overlay, placement, offset, onVi
|
||||
|
||||
return (
|
||||
<>
|
||||
{React.cloneElement(typeof children === 'function' ? children(visible) : children, {
|
||||
{React.cloneElement(children, {
|
||||
ref: setTriggerRef,
|
||||
})}
|
||||
{visible && (
|
||||
|
||||
@@ -11,7 +11,7 @@ import { getSegmentStyles } from './styles';
|
||||
|
||||
import { SegmentSelect, useExpandableLabel, SegmentProps } from './';
|
||||
|
||||
export interface SegmentSyncProps<T> extends SegmentProps<T>, Omit<HTMLProps<HTMLDivElement>, 'value' | 'onChange'> {
|
||||
export interface SegmentSyncProps<T> extends SegmentProps, Omit<HTMLProps<HTMLDivElement>, 'value' | 'onChange'> {
|
||||
value?: T | SelectableValue<T>;
|
||||
onChange: (item: SelectableValue<T>) => void;
|
||||
options: Array<SelectableValue<T>>;
|
||||
|
||||
@@ -15,7 +15,7 @@ import { getSegmentStyles } from './styles';
|
||||
|
||||
import { useExpandableLabel, SegmentProps } from '.';
|
||||
|
||||
export interface SegmentAsyncProps<T> extends SegmentProps<T>, Omit<HTMLProps<HTMLDivElement>, 'value' | 'onChange'> {
|
||||
export interface SegmentAsyncProps<T> extends SegmentProps, Omit<HTMLProps<HTMLDivElement>, 'value' | 'onChange'> {
|
||||
value?: T | SelectableValue<T>;
|
||||
loadOptions: (query?: string) => Promise<Array<SelectableValue<T>>>;
|
||||
/**
|
||||
|
||||
@@ -100,12 +100,10 @@ export const InputWithAutoFocus = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export const Basic: ComponentStory<React.ComponentType<SegmentInputProps<string | number>>> = (
|
||||
args: SegmentInputProps<string | number>
|
||||
) => {
|
||||
export const Basic: ComponentStory<React.ComponentType<SegmentInputProps>> = (args: SegmentInputProps) => {
|
||||
const [value, setValue] = useState(args.value);
|
||||
|
||||
const props: SegmentInputProps<string | number> = {
|
||||
const props: SegmentInputProps = {
|
||||
...args,
|
||||
value,
|
||||
onChange: (value) => {
|
||||
@@ -117,7 +115,7 @@ export const Basic: ComponentStory<React.ComponentType<SegmentInputProps<string
|
||||
|
||||
return (
|
||||
<SegmentSection label="Segment:">
|
||||
<SegmentInput<string | number> {...props} />
|
||||
<SegmentInput {...props} />
|
||||
</SegmentSection>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -10,8 +10,8 @@ import { getSegmentStyles } from './styles';
|
||||
|
||||
import { useExpandableLabel, SegmentProps } from '.';
|
||||
|
||||
export interface SegmentInputProps<T>
|
||||
extends Omit<SegmentProps<T>, 'allowCustomValue' | 'allowEmptyValue'>,
|
||||
export interface SegmentInputProps
|
||||
extends Omit<SegmentProps, 'allowCustomValue' | 'allowEmptyValue'>,
|
||||
Omit<HTMLProps<HTMLInputElement>, 'value' | 'onChange'> {
|
||||
value: string | number;
|
||||
onChange: (text: string | number) => void;
|
||||
@@ -19,7 +19,7 @@ export interface SegmentInputProps<T>
|
||||
|
||||
const FONT_SIZE = 14;
|
||||
|
||||
export function SegmentInput<T>({
|
||||
export function SegmentInput({
|
||||
value: initialValue,
|
||||
onChange,
|
||||
Component,
|
||||
@@ -30,7 +30,7 @@ export function SegmentInput<T>({
|
||||
autofocus = false,
|
||||
onExpandedChange,
|
||||
...rest
|
||||
}: React.PropsWithChildren<SegmentInputProps<T>>) {
|
||||
}: React.PropsWithChildren<SegmentInputProps>) {
|
||||
const ref = useRef<HTMLInputElement>(null);
|
||||
const [value, setValue] = useState<number | string>(initialValue);
|
||||
const [inputWidth, setInputWidth] = useState<number>(measureText((initialValue || '').toString(), FONT_SIZE).width);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ReactElement } from 'react';
|
||||
|
||||
export interface SegmentProps<T> {
|
||||
export interface SegmentProps {
|
||||
Component?: ReactElement;
|
||||
className?: string;
|
||||
allowCustomValue?: boolean;
|
||||
|
||||
@@ -30,7 +30,7 @@ export const SeriesIcon = React.memo(
|
||||
background: cssColor,
|
||||
width: '14px',
|
||||
height: '4px',
|
||||
borderRadius: theme.shape.radius.default,
|
||||
borderRadius: theme.shape.radius.pill,
|
||||
display: 'inline-block',
|
||||
marginRight: '8px',
|
||||
};
|
||||
|
||||
@@ -156,6 +156,11 @@ export class UPlotScaleBuilder extends PlotConfigBuilder<ScaleProps, Scale> {
|
||||
|
||||
let minMax: uPlot.Range.MinMax = [dataMin, dataMax];
|
||||
|
||||
// don't pad numeric x scales
|
||||
if (scaleKey === 'x' && !isTime) {
|
||||
return minMax;
|
||||
}
|
||||
|
||||
// happens when all series on a scale are `show: false`, re-returning nulls will auto-disable axis
|
||||
if (!hasFixedRange && dataMin == null && dataMax == null) {
|
||||
return minMax;
|
||||
|
||||
@@ -5,6 +5,14 @@
|
||||
"@grafana/ui": ["."]
|
||||
}
|
||||
},
|
||||
"exclude": ["**/*.story.tsx", "**/*.test.ts*", "**/*.tmpl.ts", "dist", "node_modules", "src/utils/storybook"],
|
||||
"exclude": [
|
||||
"**/*.story.tsx",
|
||||
"**/*.story.internal.tsx",
|
||||
"**/*.test.ts*",
|
||||
"**/*.tmpl.ts",
|
||||
"dist",
|
||||
"node_modules",
|
||||
"src/utils/storybook"
|
||||
],
|
||||
"extends": "./tsconfig.json"
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/plugins/backendplugin/coreplugin"
|
||||
"github.com/grafana/grafana/pkg/plugins/backendplugin/provider"
|
||||
"github.com/grafana/grafana/pkg/plugins/config"
|
||||
pluginClient "github.com/grafana/grafana/pkg/plugins/manager/client"
|
||||
"github.com/grafana/grafana/pkg/plugins/manager/fakes"
|
||||
"github.com/grafana/grafana/pkg/plugins/manager/loader"
|
||||
@@ -34,6 +33,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/oauthtoken/oauthtokentest"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/config"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginaccesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
||||
pluginSettings "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginsettings/service"
|
||||
@@ -59,13 +59,12 @@ func TestCallResource(t *testing.T) {
|
||||
|
||||
coreRegistry := coreplugin.ProvideCoreRegistry(nil, &cloudwatch.CloudWatchService{}, nil, nil, nil, nil,
|
||||
nil, nil, nil, nil, testdatasource.ProvideService(cfg, featuremgmt.WithFeatures()), nil, nil, nil, nil, nil, nil)
|
||||
var pCfg *config.Cfg
|
||||
pCfg, err = config.ProvideConfig(setting.ProvideProvider(cfg), cfg)
|
||||
pCfg, err := config.ProvideConfig(setting.ProvideProvider(cfg), cfg)
|
||||
require.NoError(t, err)
|
||||
reg := registry.ProvideService()
|
||||
cdn := pluginscdn.ProvideService(pCfg)
|
||||
l := loader.ProvideService(pCfg, fakes.NewFakeLicensingService(), signature.NewUnsignedAuthorizer(pCfg),
|
||||
reg, provider.ProvideService(coreRegistry), finder.NewLocalFinder(), fakes.NewFakeRoleRegistry(), cdn, assetpath.ProvideService(cdn))
|
||||
reg, provider.ProvideService(coreRegistry), finder.NewLocalFinder(), fakes.NewFakeRoleRegistry(),
|
||||
assetpath.ProvideService(pluginscdn.ProvideService(pCfg)))
|
||||
srcs := sources.ProvideService(cfg, pCfg)
|
||||
ps, err := store.ProvideService(reg, srcs, l)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -771,8 +771,7 @@ func realPackageVariant(ctx context.Context, v config.Variant, edition config.Ed
|
||||
defaultFileSrc: filepath.Join(grafanaDir, "packaging", "rpm", "sysconfig", "grafana-server"),
|
||||
systemdFileSrc: filepath.Join(grafanaDir, "packaging", "rpm", "systemd", "grafana-server.service"),
|
||||
wrapperFilePath: filepath.Join(grafanaDir, "packaging", "wrappers"),
|
||||
// chkconfig is depended on since our systemd service wraps a SysV init script, and that requires chkconfig
|
||||
depends: []string{"/sbin/service", "chkconfig", "fontconfig", "freetype", "urw-fonts"},
|
||||
depends: []string{"/sbin/service", "fontconfig", "freetype", "urw-fonts"},
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -5,20 +5,26 @@ import (
|
||||
|
||||
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/permissions"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
func NewSqlBuilder(cfg *setting.Cfg, dialect migrator.Dialect) SQLBuilder {
|
||||
return SQLBuilder{cfg: cfg, dialect: dialect}
|
||||
func NewSqlBuilder(cfg *setting.Cfg, features featuremgmt.FeatureToggles, dialect migrator.Dialect, recursiveQueriesAreSupported bool) SQLBuilder {
|
||||
return SQLBuilder{cfg: cfg, features: features, dialect: dialect, recursiveQueriesAreSupported: recursiveQueriesAreSupported}
|
||||
}
|
||||
|
||||
type SQLBuilder struct {
|
||||
cfg *setting.Cfg
|
||||
sql bytes.Buffer
|
||||
params []interface{}
|
||||
cfg *setting.Cfg
|
||||
features featuremgmt.FeatureToggles
|
||||
sql bytes.Buffer
|
||||
params []interface{}
|
||||
recQry string
|
||||
recQryParams []interface{}
|
||||
recursiveQueriesAreSupported bool
|
||||
|
||||
dialect migrator.Dialect
|
||||
}
|
||||
|
||||
@@ -31,10 +37,22 @@ func (sb *SQLBuilder) Write(sql string, params ...interface{}) {
|
||||
}
|
||||
|
||||
func (sb *SQLBuilder) GetSQLString() string {
|
||||
return sb.sql.String()
|
||||
if sb.recQry == "" {
|
||||
return sb.sql.String()
|
||||
}
|
||||
|
||||
var bf bytes.Buffer
|
||||
bf.WriteString(sb.recQry)
|
||||
bf.WriteString(sb.sql.String())
|
||||
return bf.String()
|
||||
}
|
||||
|
||||
func (sb *SQLBuilder) GetParams() []interface{} {
|
||||
if len(sb.recQryParams) == 0 {
|
||||
return sb.params
|
||||
}
|
||||
|
||||
sb.params = append(sb.recQryParams, sb.params...)
|
||||
return sb.params
|
||||
}
|
||||
|
||||
@@ -44,11 +62,15 @@ func (sb *SQLBuilder) AddParams(params ...interface{}) {
|
||||
|
||||
func (sb *SQLBuilder) WriteDashboardPermissionFilter(user *user.SignedInUser, permission dashboards.PermissionType) {
|
||||
var (
|
||||
sql string
|
||||
params []interface{}
|
||||
sql string
|
||||
params []interface{}
|
||||
recQry string
|
||||
recQryParams []interface{}
|
||||
)
|
||||
if !ac.IsDisabled(sb.cfg) {
|
||||
sql, params = permissions.NewAccessControlDashboardPermissionFilter(user, permission, "").Where()
|
||||
filterRBAC := permissions.NewAccessControlDashboardPermissionFilter(user, permission, "", sb.features, sb.recursiveQueriesAreSupported)
|
||||
sql, params = filterRBAC.Where()
|
||||
recQry, recQryParams = filterRBAC.With()
|
||||
} else {
|
||||
sql, params = permissions.DashboardPermissionFilter{
|
||||
OrgRole: user.OrgRole,
|
||||
@@ -61,4 +83,6 @@ func (sb *SQLBuilder) WriteDashboardPermissionFilter(user *user.SignedInUser, pe
|
||||
|
||||
sb.sql.WriteString(" AND " + sql)
|
||||
sb.params = append(sb.params, params...)
|
||||
sb.recQry = recQry
|
||||
sb.recQryParams = recQryParams
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
dashver "github.com/grafana/grafana/pkg/services/dashboardversion"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
@@ -24,6 +25,7 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping integration test")
|
||||
}
|
||||
|
||||
t.Run("WriteDashboardPermissionFilter", func(t *testing.T) {
|
||||
t.Run("user ACL", func(t *testing.T) {
|
||||
test(t,
|
||||
@@ -31,6 +33,7 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
||||
&DashboardPermission{User: true, Permission: dashboards.PERMISSION_VIEW},
|
||||
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||
shouldFind,
|
||||
featuremgmt.WithFeatures(),
|
||||
)
|
||||
|
||||
test(t,
|
||||
@@ -38,6 +41,7 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
||||
&DashboardPermission{User: true, Permission: dashboards.PERMISSION_VIEW},
|
||||
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||
shouldNotFind,
|
||||
featuremgmt.WithFeatures(),
|
||||
)
|
||||
|
||||
test(t,
|
||||
@@ -45,6 +49,7 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
||||
&DashboardPermission{User: true, Permission: dashboards.PERMISSION_EDIT},
|
||||
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||
shouldFind,
|
||||
featuremgmt.WithFeatures(),
|
||||
)
|
||||
|
||||
test(t,
|
||||
@@ -52,6 +57,41 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
||||
&DashboardPermission{User: true, Permission: dashboards.PERMISSION_VIEW},
|
||||
Search{RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||
shouldNotFind,
|
||||
featuremgmt.WithFeatures(),
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("user ACL with nested folders", func(t *testing.T) {
|
||||
test(t,
|
||||
DashboardProps{},
|
||||
&DashboardPermission{User: true, Permission: dashboards.PERMISSION_VIEW},
|
||||
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||
shouldFind,
|
||||
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||
)
|
||||
|
||||
test(t,
|
||||
DashboardProps{},
|
||||
&DashboardPermission{User: true, Permission: dashboards.PERMISSION_VIEW},
|
||||
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||
shouldNotFind,
|
||||
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||
)
|
||||
|
||||
test(t,
|
||||
DashboardProps{},
|
||||
&DashboardPermission{User: true, Permission: dashboards.PERMISSION_EDIT},
|
||||
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||
shouldFind,
|
||||
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||
)
|
||||
|
||||
test(t,
|
||||
DashboardProps{},
|
||||
&DashboardPermission{User: true, Permission: dashboards.PERMISSION_VIEW},
|
||||
Search{RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||
shouldNotFind,
|
||||
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||
)
|
||||
})
|
||||
|
||||
@@ -61,6 +101,7 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
||||
&DashboardPermission{Role: org.RoleViewer, Permission: dashboards.PERMISSION_VIEW},
|
||||
Search{UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||
shouldFind,
|
||||
featuremgmt.WithFeatures(),
|
||||
)
|
||||
|
||||
test(t,
|
||||
@@ -68,6 +109,7 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
||||
&DashboardPermission{Role: org.RoleViewer, Permission: dashboards.PERMISSION_VIEW},
|
||||
Search{UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||
shouldNotFind,
|
||||
featuremgmt.WithFeatures(),
|
||||
)
|
||||
|
||||
test(t,
|
||||
@@ -75,6 +117,7 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
||||
&DashboardPermission{Role: org.RoleEditor, Permission: dashboards.PERMISSION_VIEW},
|
||||
Search{UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||
shouldNotFind,
|
||||
featuremgmt.WithFeatures(),
|
||||
)
|
||||
|
||||
test(t,
|
||||
@@ -82,6 +125,41 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
||||
&DashboardPermission{Role: org.RoleEditor, Permission: dashboards.PERMISSION_VIEW},
|
||||
Search{UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||
shouldNotFind,
|
||||
featuremgmt.WithFeatures(),
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("role ACL with nested folders", func(t *testing.T) {
|
||||
test(t,
|
||||
DashboardProps{},
|
||||
&DashboardPermission{Role: org.RoleViewer, Permission: dashboards.PERMISSION_VIEW},
|
||||
Search{UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||
shouldFind,
|
||||
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||
)
|
||||
|
||||
test(t,
|
||||
DashboardProps{},
|
||||
&DashboardPermission{Role: org.RoleViewer, Permission: dashboards.PERMISSION_VIEW},
|
||||
Search{UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||
shouldNotFind,
|
||||
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||
)
|
||||
|
||||
test(t,
|
||||
DashboardProps{},
|
||||
&DashboardPermission{Role: org.RoleEditor, Permission: dashboards.PERMISSION_VIEW},
|
||||
Search{UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||
shouldNotFind,
|
||||
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||
)
|
||||
|
||||
test(t,
|
||||
DashboardProps{},
|
||||
&DashboardPermission{Role: org.RoleEditor, Permission: dashboards.PERMISSION_VIEW},
|
||||
Search{UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||
shouldNotFind,
|
||||
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||
)
|
||||
})
|
||||
|
||||
@@ -91,6 +169,7 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
||||
&DashboardPermission{Team: true, Permission: dashboards.PERMISSION_VIEW},
|
||||
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||
shouldFind,
|
||||
featuremgmt.WithFeatures(),
|
||||
)
|
||||
|
||||
test(t,
|
||||
@@ -98,6 +177,7 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
||||
&DashboardPermission{Team: true, Permission: dashboards.PERMISSION_VIEW},
|
||||
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||
shouldNotFind,
|
||||
featuremgmt.WithFeatures(),
|
||||
)
|
||||
|
||||
test(t,
|
||||
@@ -105,6 +185,7 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
||||
&DashboardPermission{Team: true, Permission: dashboards.PERMISSION_EDIT},
|
||||
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||
shouldFind,
|
||||
featuremgmt.WithFeatures(),
|
||||
)
|
||||
|
||||
test(t,
|
||||
@@ -112,6 +193,41 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
||||
&DashboardPermission{Team: true, Permission: dashboards.PERMISSION_EDIT},
|
||||
Search{UserFromACL: false, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||
shouldNotFind,
|
||||
featuremgmt.WithFeatures(),
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("team ACL with nested folders", func(t *testing.T) {
|
||||
test(t,
|
||||
DashboardProps{},
|
||||
&DashboardPermission{Team: true, Permission: dashboards.PERMISSION_VIEW},
|
||||
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||
shouldFind,
|
||||
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||
)
|
||||
|
||||
test(t,
|
||||
DashboardProps{},
|
||||
&DashboardPermission{Team: true, Permission: dashboards.PERMISSION_VIEW},
|
||||
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||
shouldNotFind,
|
||||
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||
)
|
||||
|
||||
test(t,
|
||||
DashboardProps{},
|
||||
&DashboardPermission{Team: true, Permission: dashboards.PERMISSION_EDIT},
|
||||
Search{UserFromACL: true, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||
shouldFind,
|
||||
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||
)
|
||||
|
||||
test(t,
|
||||
DashboardProps{},
|
||||
&DashboardPermission{Team: true, Permission: dashboards.PERMISSION_EDIT},
|
||||
Search{UserFromACL: false, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||
shouldNotFind,
|
||||
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||
)
|
||||
})
|
||||
|
||||
@@ -121,6 +237,7 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
||||
nil,
|
||||
Search{OrgId: -1, UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||
shouldNotFind,
|
||||
featuremgmt.WithFeatures(),
|
||||
)
|
||||
|
||||
test(t,
|
||||
@@ -128,6 +245,7 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
||||
nil,
|
||||
Search{OrgId: -1, UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||
shouldFind,
|
||||
featuremgmt.WithFeatures(),
|
||||
)
|
||||
|
||||
test(t,
|
||||
@@ -135,6 +253,7 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
||||
nil,
|
||||
Search{OrgId: -1, UsersOrgRole: org.RoleEditor, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||
shouldFind,
|
||||
featuremgmt.WithFeatures(),
|
||||
)
|
||||
|
||||
test(t,
|
||||
@@ -142,6 +261,41 @@ func TestIntegrationSQLBuilder(t *testing.T) {
|
||||
nil,
|
||||
Search{OrgId: -1, UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||
shouldNotFind,
|
||||
featuremgmt.WithFeatures(),
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("defaults for user ACL with nested folders", func(t *testing.T) {
|
||||
test(t,
|
||||
DashboardProps{},
|
||||
nil,
|
||||
Search{OrgId: -1, UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||
shouldNotFind,
|
||||
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||
)
|
||||
|
||||
test(t,
|
||||
DashboardProps{OrgId: -1},
|
||||
nil,
|
||||
Search{OrgId: -1, UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_VIEW},
|
||||
shouldFind,
|
||||
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||
)
|
||||
|
||||
test(t,
|
||||
DashboardProps{OrgId: -1},
|
||||
nil,
|
||||
Search{OrgId: -1, UsersOrgRole: org.RoleEditor, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||
shouldFind,
|
||||
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||
)
|
||||
|
||||
test(t,
|
||||
DashboardProps{OrgId: -1},
|
||||
nil,
|
||||
Search{OrgId: -1, UsersOrgRole: org.RoleViewer, RequiredPermission: dashboards.PERMISSION_EDIT},
|
||||
shouldNotFind,
|
||||
featuremgmt.WithFeatures(featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders)),
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -172,7 +326,7 @@ type dashboardResponse struct {
|
||||
Id int64
|
||||
}
|
||||
|
||||
func test(t *testing.T, dashboardProps DashboardProps, dashboardPermission *DashboardPermission, search Search, shouldFind bool) {
|
||||
func test(t *testing.T, dashboardProps DashboardProps, dashboardPermission *DashboardPermission, search Search, shouldFind bool, features featuremgmt.FeatureToggles) {
|
||||
t.Helper()
|
||||
|
||||
t.Run("", func(t *testing.T) {
|
||||
@@ -186,7 +340,7 @@ func test(t *testing.T, dashboardProps DashboardProps, dashboardPermission *Dash
|
||||
aclUserID = createDummyACL(t, sqlStore, dashboardPermission, search, dashboard.ID)
|
||||
t.Logf("Created ACL with user ID %d\n", aclUserID)
|
||||
}
|
||||
dashboards := getDashboards(t, sqlStore, search, aclUserID)
|
||||
dashboards := getDashboards(t, sqlStore, search, aclUserID, features)
|
||||
|
||||
if shouldFind {
|
||||
require.Len(t, dashboards, 1, "Should return one dashboard")
|
||||
@@ -292,7 +446,7 @@ func createDummyACL(t *testing.T, sqlStore *sqlstore.SQLStore, dashboardPermissi
|
||||
return 0
|
||||
}
|
||||
|
||||
func getDashboards(t *testing.T, sqlStore *sqlstore.SQLStore, search Search, aclUserID int64) []*dashboardResponse {
|
||||
func getDashboards(t *testing.T, sqlStore *sqlstore.SQLStore, search Search, aclUserID int64, features featuremgmt.FeatureToggles) []*dashboardResponse {
|
||||
t.Helper()
|
||||
|
||||
old := sqlStore.Cfg.RBACEnabled
|
||||
@@ -301,7 +455,10 @@ func getDashboards(t *testing.T, sqlStore *sqlstore.SQLStore, search Search, acl
|
||||
sqlStore.Cfg.RBACEnabled = old
|
||||
}()
|
||||
|
||||
builder := NewSqlBuilder(sqlStore.Cfg, sqlStore.GetDialect())
|
||||
recursiveQueriesAreSupported, err := sqlStore.RecursiveQueriesAreSupported()
|
||||
require.NoError(t, err)
|
||||
|
||||
builder := NewSqlBuilder(sqlStore.Cfg, features, sqlStore.GetDialect(), recursiveQueriesAreSupported)
|
||||
signedInUser := &user.SignedInUser{
|
||||
UserID: 9999999999,
|
||||
}
|
||||
@@ -325,7 +482,7 @@ func getDashboards(t *testing.T, sqlStore *sqlstore.SQLStore, search Search, acl
|
||||
builder.Write("SELECT * FROM dashboard WHERE true")
|
||||
builder.WriteDashboardPermissionFilter(signedInUser, search.RequiredPermission)
|
||||
t.Logf("Searching for dashboards, SQL: %q\n", builder.GetSQLString())
|
||||
err := sqlStore.GetEngine().SQL(builder.GetSQLString(), builder.params...).Find(&res)
|
||||
err = sqlStore.GetEngine().SQL(builder.GetSQLString(), builder.params...).Find(&res)
|
||||
require.NoError(t, err)
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
//go:build memcached
|
||||
// +build memcached
|
||||
|
||||
package remotecache
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
func TestMemcachedCacheStorage(t *testing.T) {
|
||||
opts := &setting.RemoteCacheOptions{Name: memcachedCacheType, ConnStr: "localhost:11211"}
|
||||
func TestIntegrationMemcachedCacheStorage(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping integration test")
|
||||
}
|
||||
|
||||
u, ok := os.LookupEnv("MEMCACHED_HOSTS")
|
||||
if !ok || u == "" {
|
||||
t.Skip("No Memcached hosts provided")
|
||||
}
|
||||
|
||||
opts := &setting.RemoteCacheOptions{Name: memcachedCacheType, ConnStr: u}
|
||||
client := createTestClient(t, opts, nil)
|
||||
runTestsForClient(t, client)
|
||||
runCountTestsForClient(t, opts, nil)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user