├── examples
├── php
│ ├── .gitignore
│ ├── linux-node-overview
│ │ ├── index.php
│ │ └── composer.json
│ ├── grafana-agent-overview
│ │ ├── index.php
│ │ └── composer.json
│ ├── custom-panel
│ │ ├── composer.json
│ │ ├── src
│ │ │ └── Custom
│ │ │ │ ├── Options.php
│ │ │ │ └── PanelBuilder.php
│ │ └── index.php
│ ├── custom-query
│ │ ├── composer.json
│ │ ├── index.php
│ │ └── src
│ │ │ └── Custom
│ │ │ ├── Query.php
│ │ │ └── QueryBuilder.php
│ ├── red-method
│ │ ├── composer.json
│ │ └── index.php
│ └── README.md
├── go
│ ├── .gitignore
│ ├── alert-rule
│ │ ├── go.mod
│ │ └── go.sum
│ ├── red-method
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── main.go
│ │ └── common.go
│ ├── custom-panel
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── main.go
│ ├── custom-query
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── main.go
│ ├── linux-node-overview
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── main.go
│ │ └── builder
│ │ │ └── host.go
│ ├── grafana-agent-overview
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── discovery.go
│ │ ├── overview.go
│ │ └── common.go
│ └── grafana-openapi-client-go
│ │ └── go.mod
├── pulumi
│ ├── python
│ │ ├── .gitignore
│ │ ├── Pulumi.dev.yaml
│ │ ├── requirements.txt
│ │ ├── Pulumi.yaml
│ │ └── __main__.py
│ ├── typescript
│ │ ├── .gitignore
│ │ ├── Pulumi.dev.yaml
│ │ ├── Pulumi.yaml
│ │ ├── package.json
│ │ ├── tsconfig.json
│ │ └── index.ts
│ ├── go
│ │ ├── Pulumi.dev.yaml
│ │ ├── Pulumi.yaml
│ │ └── main.go
│ └── README.md
├── python
│ ├── red-method
│ │ ├── src
│ │ │ ├── __init__.py
│ │ │ └── common.py
│ │ ├── requirements.txt
│ │ └── main.py
│ ├── custom-panel
│ │ ├── src
│ │ │ ├── __init__.py
│ │ │ └── custompanel.py
│ │ ├── requirements.txt
│ │ └── main.py
│ ├── custom-query
│ │ ├── src
│ │ │ └── __init__.py
│ │ ├── requirements.txt
│ │ └── main.py
│ ├── linux-node-overview
│ │ ├── src
│ │ │ └── __init__.py
│ │ └── requirements.txt
│ ├── .gitignore
│ ├── grafana-agent-overview
│ │ ├── src
│ │ │ ├── __init__.py
│ │ │ ├── discovery.py
│ │ │ └── common.py
│ │ └── requirements.txt
│ └── alert-rule
│ │ └── requirements.txt
├── typescript
│ ├── .gitignore
│ ├── red-method
│ │ ├── src
│ │ │ ├── index.ts
│ │ │ └── common.ts
│ │ ├── package.json
│ │ └── tsconfig.json
│ ├── custom-panel
│ │ ├── src
│ │ │ ├── index.ts
│ │ │ └── customPanel.ts
│ │ ├── package.json
│ │ └── tsconfig.json
│ ├── custom-query
│ │ ├── src
│ │ │ ├── index.ts
│ │ │ └── customQuery.ts
│ │ ├── package.json
│ │ └── tsconfig.json
│ ├── alert-rule
│ │ ├── package.json
│ │ ├── tsconfig.json
│ │ └── src
│ │ │ └── index.ts
│ ├── linux-node-overview
│ │ ├── package.json
│ │ └── tsconfig.json
│ └── grafana-agent-overview
│ │ ├── package.json
│ │ ├── tsconfig.json
│ │ └── src
│ │ ├── discovery.ts
│ │ ├── overview.ts
│ │ └── common.ts
├── terraform
│ ├── .gitignore
│ ├── main.tf
│ ├── README.md
│ └── dashboards.tf
└── java
│ ├── alert-rule
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ └── build.gradle
│ ├── red-method
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── src
│ │ └── main
│ │ │ └── java
│ │ │ └── red
│ │ │ ├── Main.java
│ │ │ └── Common.java
│ └── build.gradle
│ ├── custom-panel
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── src
│ │ └── main
│ │ │ └── java
│ │ │ └── custompanel
│ │ │ ├── CustomPanelOptions.java
│ │ │ ├── Main.java
│ │ │ └── CustomPanelBuilder.java
│ └── build.gradle
│ ├── custom-query
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── src
│ │ └── main
│ │ │ └── java
│ │ │ └── customquery
│ │ │ ├── CustomQuery.java
│ │ │ ├── CustomQueryBuilder.java
│ │ │ └── Main.java
│ └── build.gradle
│ ├── linux-node-overview
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── src
│ │ └── main
│ │ │ └── java
│ │ │ └── linuxnode
│ │ │ ├── Main.java
│ │ │ └── linux
│ │ │ └── Network.java
│ └── build.gradle
│ ├── grafana-agent-overview
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── build.gradle
│ └── src
│ │ └── main
│ │ └── java
│ │ └── agent
│ │ └── Discovery.java
│ └── README.md
├── gradle.properties
├── .github
├── CODEOWNERS
├── zizmor.yaml
├── ISSUE_TEMPLATE
│ ├── config.yml
│ ├── 3-general-issue.yaml
│ ├── 2-feature-request.yaml
│ ├── 0-bug-report.yaml
│ └── 1-missing-fields.yaml
└── actions
│ └── setup-cog
│ └── action.yaml
├── .gitignore
├── .cog
├── templates
│ ├── java
│ │ ├── extra
│ │ │ ├── settings.gradle
│ │ │ ├── gradle.properties
│ │ │ ├── src
│ │ │ │ └── main
│ │ │ │ │ └── java
│ │ │ │ │ └── com
│ │ │ │ │ └── grafana
│ │ │ │ │ └── foundation
│ │ │ │ │ └── cog
│ │ │ │ │ └── variants
│ │ │ │ │ ├── Dataquery.java
│ │ │ │ │ ├── UnknownDataquery.java
│ │ │ │ │ ├── UnknownDataquerySerializer.java
│ │ │ │ │ ├── DataqueryConfig.java
│ │ │ │ │ └── PanelConfig.java
│ │ │ └── docs
│ │ │ │ └── Installing.md
│ │ └── overrides
│ │ │ ├── api_reference_object_dashboard_Dashboard_extra.tmpl
│ │ │ ├── assigment_Dashboard_WithRow.tmpl
│ │ │ └── assigment_Dashboard_WithPanel.tmpl
│ ├── go
│ │ ├── extra
│ │ │ ├── go.mod
│ │ │ ├── docs
│ │ │ │ ├── Installing.md
│ │ │ │ └── How-To
│ │ │ │ │ ├── converting-a-dashboard.md
│ │ │ │ │ └── building-a-dashboard.md
│ │ │ └── cog
│ │ │ │ └── plugins
│ │ │ │ └── variants.go
│ │ └── overrides
│ │ │ ├── object_variant_dataquery.tmpl
│ │ │ ├── object_dashboardv2beta1_DataQueryKind_field_spec_custom_strict_unmarshal.tmpl
│ │ │ ├── object_dashboard_Panel_field_options_custom_strict_unmarshal.tmpl
│ │ │ ├── object_common_TableFooterOptions_field_fields_custom_strict_unmarshal.tmpl
│ │ │ ├── object_dashboard_DataSourceRef_custom_unmarshal.tmpl
│ │ │ ├── object_dashboard_Panel_field_targets_custom_strict_unmarshal.tmpl
│ │ │ ├── assignment_Dashboard_withPanel.tmpl
│ │ │ ├── variant_dataquery_field_unmarshal.tmpl
│ │ │ ├── object_dashboard_Panel_field_fieldConfig_custom_strict_unmarshal.tmpl
│ │ │ ├── object_dashboardv2beta1_DataQueryKind_custom_unmarshal.tmpl
│ │ │ ├── api_reference_object_dashboard_Dashboard_extra.tmpl
│ │ │ ├── assignment_Dashboard_withRow.tmpl
│ │ │ ├── api_reference_builder_dashboard_Dashboard_extra.tmpl
│ │ │ └── object_common_TableFooterOptions_custom_unmarshal.tmpl
│ ├── python
│ │ ├── extra
│ │ │ ├── grafana_foundation_sdk
│ │ │ │ └── cog
│ │ │ │ │ ├── variants.py
│ │ │ │ │ └── plugins.py
│ │ │ ├── docs
│ │ │ │ ├── Installing.md
│ │ │ │ └── How-To
│ │ │ │ │ └── building-a-dashboard.md
│ │ │ └── pyproject.toml
│ │ └── overrides
│ │ │ ├── assignment_Dashboard_withPanel.tmpl
│ │ │ ├── variant_dataquery_field_unmarshal.tmpl
│ │ │ ├── object_dashboardv2beta1_DataQueryKind_custom_unmarshal.tmpl.tmpl
│ │ │ ├── schema_variant_panelcfg.tmpl
│ │ │ ├── api_reference_object_dashboard_Dashboard_extra.tmpl
│ │ │ ├── schema_variant_dataquery.tmpl
│ │ │ ├── api_reference_builder_dashboard_Dashboard_extra.tmpl
│ │ │ └── assignment_Dashboard_withRow.tmpl
│ ├── php
│ │ ├── extra
│ │ │ ├── docs
│ │ │ │ ├── Installing.md
│ │ │ │ └── How-To
│ │ │ │ │ ├── converting-a-dashboard.md
│ │ │ │ │ └── building-a-dashboard.md
│ │ │ └── src
│ │ │ │ └── Cog
│ │ │ │ ├── Dataquery.php
│ │ │ │ ├── UnknownDataqueryBuilder.php
│ │ │ │ ├── PanelcfgConfig.php
│ │ │ │ ├── DataqueryConfig.php
│ │ │ │ └── UnknownDataquery.php
│ │ └── overrides
│ │ │ ├── object_variant_dataquery.tmpl
│ │ │ ├── api_reference_object_dashboard_Dashboard_extra.tmpl
│ │ │ ├── assignment_Dashboard_withPanel.tmpl
│ │ │ ├── variant_dataquery_field_unmarshal.tmpl
│ │ │ ├── object_dashboardv2beta1_DataQueryKind_custom_unmarshal.tmpl.tmpl
│ │ │ ├── api_reference_builder_dashboard_Dashboard_extra.tmpl
│ │ │ └── api_reference_package_dashboard_extra.tmpl
│ ├── typescript
│ │ ├── extra
│ │ │ ├── docs
│ │ │ │ ├── Installing.md
│ │ │ │ └── How-To
│ │ │ │ │ ├── building-a-dashboard.md
│ │ │ │ │ └── custom-panel-type.md
│ │ │ ├── babel.config.json
│ │ │ └── tsconfig.json
│ │ └── overrides
│ │ │ ├── assignment_Dashboard_withPanel.tmpl
│ │ │ ├── api_reference_builder_dashboard_Dashboard_extra.tmpl
│ │ │ └── assignment_Dashboard_withRow.tmpl
│ └── README.md
├── veneers
│ ├── expr.common.yaml
│ ├── datasource.common.yaml
│ ├── elasticsearch.common.yaml
│ ├── alerting.go.yaml
│ ├── alerting.typescript.yaml
│ ├── accesspolicy.common.yaml
│ ├── team.common.yaml
│ ├── folder.common.yaml
│ ├── dashboardv2
│ │ ├── datasource.python.yaml
│ │ ├── datasource.ts.yaml
│ │ ├── dashboardv2beta1.go.yaml
│ │ └── dashboardv2beta1.java.yaml
│ ├── tempo.go.yaml
│ ├── cloudwatch.go.yaml
│ ├── dashboard.go.yaml
│ ├── dashboard.php.yaml
│ ├── common.common.yaml
│ ├── alerting.common.yaml
│ ├── dashboard.python.yaml
│ └── heatmap.common.yaml
├── schemas
│ ├── composable
│ │ ├── datasource
│ │ │ └── dataquery.cue
│ │ └── athena
│ │ │ └── dataquery.cue
│ └── resource
│ │ └── manifest.cue
├── compiler
│ ├── team.yaml
│ ├── common_passes.yaml
│ ├── athena.yaml
│ ├── prometheus.yaml
│ ├── dataqueries_refid.yaml
│ ├── dashboardv2beta1.yaml
│ └── testdata_passes.yaml
├── converters
│ └── config.yaml
└── repository_templates
│ ├── php
│ ├── composer.json
│ └── .config
│ │ └── ci
│ │ └── php
│ │ └── phpstan.neon
│ ├── python
│ └── .github
│ │ └── workflows
│ │ └── python-release.tmpl
│ ├── typescript
│ └── .github
│ │ └── workflows
│ │ └── typescript-release.tmpl
│ └── common
│ └── README.md
├── scripts
├── versions.sh
├── validate
│ ├── java.sh
│ ├── python.sh
│ ├── typescript.sh
│ ├── go.sh
│ └── php.sh
├── fetch-kind-registry.sh
├── release-validate.sh
├── release-all.sh
├── libs
│ └── git.sh
└── docs
│ └── _pull_versions.sh
├── .mkdocs
├── mkdocs-version.yml
└── overrides
│ └── main.html
├── .editorconfig
├── composer.json
├── devbox.json
├── catalog-info.yaml
├── requirements.txt
└── Makefile
/examples/php/.gitignore:
--------------------------------------------------------------------------------
1 | */vendor
--------------------------------------------------------------------------------
/examples/go/.gitignore:
--------------------------------------------------------------------------------
1 | */vendor
2 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.java.home=
2 |
--------------------------------------------------------------------------------
/examples/pulumi/python/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | venv/
3 |
--------------------------------------------------------------------------------
/examples/python/red-method/src/__init__.py:
--------------------------------------------------------------------------------
1 | # src
2 |
--------------------------------------------------------------------------------
/examples/python/custom-panel/src/__init__.py:
--------------------------------------------------------------------------------
1 | # src
2 |
--------------------------------------------------------------------------------
/examples/python/custom-query/src/__init__.py:
--------------------------------------------------------------------------------
1 | # src
2 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @grafana/grafana-app-platform-squad
2 |
--------------------------------------------------------------------------------
/examples/python/linux-node-overview/src/__init__.py:
--------------------------------------------------------------------------------
1 | # src
2 |
--------------------------------------------------------------------------------
/examples/typescript/.gitignore:
--------------------------------------------------------------------------------
1 | */build
2 | */node_modules
3 |
--------------------------------------------------------------------------------
/examples/pulumi/typescript/.gitignore:
--------------------------------------------------------------------------------
1 | /bin/
2 | /node_modules/
3 |
--------------------------------------------------------------------------------
/examples/python/.gitignore:
--------------------------------------------------------------------------------
1 | */.venv
2 | __pycache__
3 | *.pyc
4 |
--------------------------------------------------------------------------------
/examples/python/grafana-agent-overview/src/__init__.py:
--------------------------------------------------------------------------------
1 | # src
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | .gradle
3 | /examples/java/*/build/
4 |
5 | /kind-registry
6 |
--------------------------------------------------------------------------------
/.cog/templates/java/extra/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'grafana-foundation-sdk'
2 |
--------------------------------------------------------------------------------
/examples/python/alert-rule/requirements.txt:
--------------------------------------------------------------------------------
1 | grafana-foundation-sdk==1746136285!11.6.0
2 |
--------------------------------------------------------------------------------
/examples/python/custom-panel/requirements.txt:
--------------------------------------------------------------------------------
1 | grafana-foundation-sdk==1746136285!11.6.0
2 |
--------------------------------------------------------------------------------
/examples/python/custom-query/requirements.txt:
--------------------------------------------------------------------------------
1 | grafana-foundation-sdk==1746136285!11.6.0
2 |
--------------------------------------------------------------------------------
/examples/python/red-method/requirements.txt:
--------------------------------------------------------------------------------
1 | grafana-foundation-sdk==1746136285!11.6.0
2 |
--------------------------------------------------------------------------------
/examples/terraform/.gitignore:
--------------------------------------------------------------------------------
1 | .terraform
2 | .terraform.lock.hcl
3 | terraform.tfstate*
4 |
--------------------------------------------------------------------------------
/examples/python/linux-node-overview/requirements.txt:
--------------------------------------------------------------------------------
1 | grafana-foundation-sdk==1746136285!11.6.0
2 |
--------------------------------------------------------------------------------
/examples/python/grafana-agent-overview/requirements.txt:
--------------------------------------------------------------------------------
1 | grafana-foundation-sdk==1746136285!11.6.0
2 |
--------------------------------------------------------------------------------
/.github/zizmor.yaml:
--------------------------------------------------------------------------------
1 | rules:
2 | template-injection:
3 | ignore:
4 | - ".cog/repository_templates/**/*.yaml"
5 |
--------------------------------------------------------------------------------
/examples/pulumi/go/Pulumi.dev.yaml:
--------------------------------------------------------------------------------
1 | encryptionsalt: v1:BEftHDn41bo=:v1:/KUE9m/zZaCucHYs:hUJgPPzk6cspkZqzbSeMxjSLc4PolA==
2 |
--------------------------------------------------------------------------------
/examples/pulumi/python/Pulumi.dev.yaml:
--------------------------------------------------------------------------------
1 | encryptionsalt: v1:JUSLvitr2WM=:v1:/JLqOYWEeQHx7gqH:nM9RkBYiHXQKdMP+62QkLZycWyD9pg==
2 |
--------------------------------------------------------------------------------
/.cog/templates/go/extra/go.mod:
--------------------------------------------------------------------------------
1 | {{- if not .Data.Debug -}}
2 | module {{ .Data.PackageRoot }}
3 |
4 | go 1.21
5 |
6 | {{- end -}}
--------------------------------------------------------------------------------
/examples/pulumi/typescript/Pulumi.dev.yaml:
--------------------------------------------------------------------------------
1 | encryptionsalt: v1:ndbNyyxE2kA=:v1:R0etjMYFwiaC7/me:ouuaAW0UsZ6GpU68p6NvHWdBsCQOzQ==
2 |
--------------------------------------------------------------------------------
/.cog/templates/python/extra/grafana_foundation_sdk/cog/variants.py:
--------------------------------------------------------------------------------
1 | from abc import ABC
2 |
3 |
4 | class Dataquery(ABC):
5 | ...
6 |
--------------------------------------------------------------------------------
/examples/pulumi/python/requirements.txt:
--------------------------------------------------------------------------------
1 | pulumi>=3.0.0,<4.0.0
2 | pulumiverse_grafana==0.5.0
3 | grafana_foundation_sdk==1713437340!10.4.0
4 |
--------------------------------------------------------------------------------
/.cog/templates/php/extra/docs/Installing.md:
--------------------------------------------------------------------------------
1 | # Installing
2 |
3 | ```shell
4 | composer require "grafana/foundation-sdk:dev-{{ .Extra.ReleaseBranch }}"
5 | ```
6 |
--------------------------------------------------------------------------------
/.cog/templates/go/extra/docs/Installing.md:
--------------------------------------------------------------------------------
1 | # Installing
2 |
3 | ```shell
4 | go get github.com/grafana/grafana-foundation-sdk/go@{{ .Extra.ReleaseBranch }}
5 | ```
6 |
--------------------------------------------------------------------------------
/examples/java/alert-rule/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grafana/grafana-foundation-sdk/HEAD/examples/java/alert-rule/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/examples/java/red-method/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grafana/grafana-foundation-sdk/HEAD/examples/java/red-method/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/examples/java/custom-panel/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grafana/grafana-foundation-sdk/HEAD/examples/java/custom-panel/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/examples/java/custom-query/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grafana/grafana-foundation-sdk/HEAD/examples/java/custom-query/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/.cog/templates/java/extra/gradle.properties:
--------------------------------------------------------------------------------
1 | grafanaFoundationSDKVersion={{ if .Data.Debug }}0.0{{ else }}{{ .Extra.GrafanaVersion|registryToSemver }}-{{ .Extra.BuildTimestamp }}{{ end }}
2 |
--------------------------------------------------------------------------------
/.cog/templates/php/extra/src/Cog/Dataquery.php:
--------------------------------------------------------------------------------
1 | {{ page.meta.title | striptags }} - {{ config.site_name }}
6 | {% elif page.title and not page.is_homepage %}
7 |
{{ page.title | striptags }} - {{ config.site_name }}
8 | {% else %}
9 | {{ config.site_name }}
10 | {% endif %}
11 | {% endblock %}
--------------------------------------------------------------------------------
/.cog/templates/go/overrides/object_dashboardv2beta1_DataQueryKind_field_spec_custom_strict_unmarshal.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "object_dashboardv2beta1_DataQueryKind_field_spec_custom_strict_unmarshal" -}}
2 | {{- $cog := importPkg "cog" -}}
3 | dataquery, err := cog.UnmarshalDataquery(fields["spec"], resource.Group)
4 | if err != nil {
5 | errs = append(errs, cog.MakeBuildErrors("spec", err)...)
6 | } else {
7 | resource.Spec = dataquery
8 | }
9 | {{- end }}
10 |
--------------------------------------------------------------------------------
/.cog/veneers/cloudwatch.go.yaml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/grafana/cog/main/schemas/veneers.json
2 |
3 | language: go
4 |
5 | package: cloudwatch
6 |
7 | builders: ~
8 |
9 | options:
10 | - struct_fields_as_arguments:
11 | by_name: QueryEditorOperator.value
12 | fields: [ ArrayOfQueryEditorOperatorType ]
13 | - rename_arguments:
14 | by_name: QueryEditorOperator.value
15 | as: [operatorTypes]
16 |
--------------------------------------------------------------------------------
/.cog/converters/config.yaml:
--------------------------------------------------------------------------------
1 | runtime:
2 | - package: 'dashboard'
3 | name: 'panel'
4 | name_func: 'ConvertPanelToCode'
5 | discriminator_field: 'type'
6 |
7 | - package: 'dashboardv2beta1'
8 | name: 'vizconfigkind'
9 | name_func: 'ConvertPanelToCode'
10 | discriminator_field: 'group'
11 |
12 | - package: 'dashboardv2beta1'
13 | name: 'dataquerykind'
14 | name_func: 'ConvertDataQueryKindToCode'
15 | discriminator_field: 'group'
16 |
--------------------------------------------------------------------------------
/examples/typescript/custom-panel/src/index.ts:
--------------------------------------------------------------------------------
1 | import { DashboardBuilder } from '@grafana/grafana-foundation-sdk/dashboard';
2 | import { CustomPanelBuilder } from "./customPanel";
3 |
4 | const builder = new DashboardBuilder('[Example] Custom panel')
5 | .uid('example-custom-panel')
6 | .withPanel(
7 | new CustomPanelBuilder()
8 | .title('Sample custom panel')
9 | .makeBeautiful()
10 | );
11 |
12 | console.log(JSON.stringify(builder.build(), null, 2));
13 |
--------------------------------------------------------------------------------
/.cog/compiler/athena.yaml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/grafana/cog/main/schemas/compiler_passes.json
2 |
3 | passes:
4 | ##########
5 | # Athena #
6 | ##########
7 |
8 | - schema_set_entry_point:
9 | package: athena
10 | entry_point: Dataquery
11 |
12 | - retype_field:
13 | field: athena.Dataquery.datasource
14 | as:
15 | kind: ref
16 | ref: { referred_pkg: common, referred_type: DataSourceRef }
17 |
--------------------------------------------------------------------------------
/.cog/templates/php/extra/docs/How-To/converting-a-dashboard.md:
--------------------------------------------------------------------------------
1 | # Converting a dashboard
2 |
3 | ```php
4 |
10 | com.grafana
11 | grafana-foundation-sdk
12 | {{ .Extra.GrafanaVersion|registryToSemver }}-{{ .Extra.BuildTimestamp }}
13 |
14 | ```
15 |
--------------------------------------------------------------------------------
/devbox.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://raw.githubusercontent.com/jetify-com/devbox/main/.schema/devbox.schema.json",
3 | "packages": [
4 | "python312@3.12",
5 | "go@1.23",
6 | "php83Packages.composer@2.7",
7 | "php83Packages.phpstan@2.1.1",
8 | "yarn@1.22",
9 | "gradle@8.10"
10 | ],
11 | "shell": {
12 | "init_hook": [
13 | "echo 'Entering Python venv' && . $VENV_DIR/bin/activate",
14 | "echo 'Installing Python dependencies' && pip install -qq -r requirements.txt"
15 | ]
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/examples/pulumi/README.md:
--------------------------------------------------------------------------------
1 | # Examples
2 |
3 | This folder contains examples of the Foundation SDK being used in combination with [Pulumi](https://www.pulumi.com/). These tools work well together because they both allow users to work in the programming language of their choice. The Foundation SDK allows users to build Grafana objects in various languages, and Pulumi allows users to invoke Terraform in various languages.
4 |
5 | ## Running the examples
6 |
7 | From an example's folder:
8 |
9 | ```console
10 | $ pulumi install
11 | $ pulumi up
12 | ```
13 |
--------------------------------------------------------------------------------
/examples/pulumi/typescript/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "outDir": "bin",
5 | "target": "es2020",
6 | "module": "NodeNext",
7 | "moduleResolution": "NodeNext",
8 | "sourceMap": true,
9 | "experimentalDecorators": true,
10 | "pretty": true,
11 | "noFallthroughCasesInSwitch": true,
12 | "noImplicitReturns": true,
13 | "forceConsistentCasingInFileNames": true
14 | },
15 | "files": [
16 | "index.ts"
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/.cog/templates/java/extra/src/main/java/com/grafana/foundation/cog/variants/UnknownDataquery.java:
--------------------------------------------------------------------------------
1 | package com.grafana.foundation.cog.variants;
2 |
3 | import com.fasterxml.jackson.databind.annotation.JsonSerialize;
4 |
5 | import java.util.HashMap;
6 | import java.util.Map;
7 |
8 | @JsonSerialize(using = UnknownDataquerySerializer.class)
9 | public class UnknownDataquery implements Dataquery {
10 | public final Map genericFields = new HashMap<>();
11 |
12 | public String dataqueryName() {
13 | return "unknown";
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/examples/java/custom-query/src/main/java/customquery/CustomQuery.java:
--------------------------------------------------------------------------------
1 | package customquery;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import com.grafana.foundation.cog.variants.Dataquery;
5 |
6 | public class CustomQuery implements Dataquery {
7 | @JsonProperty("refId")
8 | public String refId;
9 | @JsonProperty("hide")
10 | public Boolean hide;
11 | @JsonProperty("query")
12 | public String query;
13 |
14 | @Override
15 | public String dataqueryName() {
16 | return "custom-query";
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/examples/pulumi/typescript/index.ts:
--------------------------------------------------------------------------------
1 | import * as pulumi from "@pulumi/pulumi";
2 | import * as grafana from "@pulumiverse/grafana";
3 | import { builder } from '../../typescript/linux-node-overview/src/index';
4 |
5 | const provider = new grafana.Provider("grafana", { url: "http://localhost:3000", auth: "admin:admin" });
6 |
7 | const dashboard = builder.build();
8 |
9 | const pulumiDashboard = new grafana.Dashboard(dashboard.uid || 'uid', { configJson: JSON.stringify(dashboard, null, 2) }, { provider: provider });
10 |
11 | export const dashboardUid = pulumiDashboard.uid;
12 |
--------------------------------------------------------------------------------
/scripts/validate/go.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Exit on error. Append "|| true" if you expect an error.
4 | set -o errexit
5 | # Exit on error inside any functions or subshells.
6 | set -o errtrace
7 | # Do not allow use of undefined vars. Use ${VAR:-} to use an undefined VAR
8 | set -o nounset
9 | # Catch the error in case mysqldump fails (but gzip succeeds) in `mysqldump | gzip`
10 | set -o pipefail
11 |
12 | release_path=${1:-"./"}
13 |
14 | cd "${release_path}/go"
15 |
16 | for d in */ ; do
17 | [[ "$d" != "docs/" ]] && (echo "Building $d"; go build "./$d")
18 | done
--------------------------------------------------------------------------------
/.cog/templates/README.md:
--------------------------------------------------------------------------------
1 | # Template blocks
2 |
3 | The templates contained in this folder are used to customize the types, builders and docs generated by cog.
4 | For example, to automatically position panels on the grid whenever they're added to a dashboard.
5 |
6 | To achieve that, cog looks for [template blocks](https://pkg.go.dev/text/template#example-Template-Block) following
7 | a particular naming convention, and renders them.
8 |
9 | A [list of every supported template block](https://grafana.github.io/cog/reference/template_blocks/) is available in cog's documentation.
10 |
--------------------------------------------------------------------------------
/.cog/templates/typescript/extra/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@grafana/tsconfig",
3 | "compilerOptions": {
4 | "declaration": true,
5 | "emitDeclarationOnly": false,
6 | "lib": ["es2015", "es2016", "es2017", "es2018", "es2019", "es2020"],
7 | "module": "commonjs",
8 | "moduleResolution": "node",
9 | "target": "es2020",
10 | "declarationDir": "dist",
11 | "importHelpers": true,
12 | "outDir": "dist",
13 | "rootDirs": ["."],
14 | "useUnknownInCatchVariables": false
15 | },
16 | "exclude": ["dist", "node_modules"],
17 | "include": ["**/*.ts"]
18 | }
--------------------------------------------------------------------------------
/examples/terraform/README.md:
--------------------------------------------------------------------------------
1 | # Examples
2 |
3 | This folder contains examples of the Foundation SDK being used in combination with [Terraform](https://www.terraform.io/) and the [Grafana Provider](https://registry.terraform.io/providers/grafana/grafana/latest/docs).
4 |
5 | While the Foundation SDK does not integrate directly with TF/the HCL language, it can be used in Terraform "external datasources". Building dashboards is a complex problem that is hard to model/reason with in the HCL language.
6 |
7 | ## Running this example
8 |
9 | ```console
10 | $ terraform init
11 | $ terraform apply
12 | ```
13 |
--------------------------------------------------------------------------------
/.cog/templates/php/extra/src/Cog/UnknownDataqueryBuilder.php:
--------------------------------------------------------------------------------
1 |
7 | */
8 | final class UnknownDataqueryBuilder implements Builder
9 | {
10 | protected UnknownDataquery $internal;
11 |
12 | public function __construct(?UnknownDataquery $object = null)
13 | {
14 | $this->internal = $object ?: new UnknownDataquery([]);
15 | }
16 |
17 | /**
18 | * @return UnknownDataquery
19 | */
20 | public function build()
21 | {
22 | return $this->internal;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/examples/typescript/custom-query/src/index.ts:
--------------------------------------------------------------------------------
1 | import { DashboardBuilder } from '@grafana/grafana-foundation-sdk/dashboard';
2 | import { PanelBuilder as TimeSeriesBuilder } from "@grafana/grafana-foundation-sdk/timeseries";
3 | import { CustomQueryBuilder } from "./customQuery";
4 |
5 | const builder = new DashboardBuilder('[Example] Custom query')
6 | .uid('example-custom-query')
7 | .withPanel(
8 | new TimeSeriesBuilder()
9 | .title('Sample panel')
10 | .withTarget(
11 | new CustomQueryBuilder("query here")
12 | )
13 | );
14 |
15 | console.log(JSON.stringify(builder.build(), null, 2));
16 |
--------------------------------------------------------------------------------
/catalog-info.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: backstage.io/v1alpha1
2 | kind: Component
3 | metadata:
4 | name: grafana-foundation-sdk
5 | title: Grafana Foundation SDK
6 | annotations:
7 | github.com/project-slug: grafana/grafana-foundation-sdk
8 | tags:
9 | - gitops
10 | links:
11 | - title: "Internal Slack Channel #app-platform"
12 | url: https://grafanalabs.enterprise.slack.com/archives/C04RVCAG9B5
13 | description: |
14 | Set of tools, types and libraries for building and manipulating Grafana objects.
15 | spec:
16 | type: library
17 | owner: group:default/grafana-app-platform-squad
18 | lifecycle: experimental
19 |
--------------------------------------------------------------------------------
/.cog/repository_templates/php/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "grafana/foundation-sdk",
3 | "type": "library",
4 | "license": "Apache-2.0",
5 | "homepage": "https://github.com/grafana/grafana-foundation-sdk",
6 | "description": "A set of tools, types and libraries for building and manipulating Grafana objects.",
7 | "keywords": [
8 | "observability",
9 | "sdk",
10 | "grafana",
11 | "logs",
12 | "traces",
13 | "metrics"
14 | ],
15 | "autoload": {
16 | "psr-4": {
17 | "Grafana\\Foundation\\": "php/src/"
18 | }
19 | },
20 | "require": {}
21 | }
22 |
--------------------------------------------------------------------------------
/examples/typescript/alert-rule/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "alert-rule",
3 | "version": "1.0.0",
4 | "license": "Apache-2.0",
5 | "author": "Grafana Labs",
6 | "private": true,
7 | "scripts": {
8 | "start": "node build/src/index.js",
9 | "dev": "ts-node src/index.ts",
10 | "build": "tsc -p tsconfig.json",
11 | "build:watch": "tsc -w -p tsconfig.json"
12 | },
13 | "dependencies": {
14 | "@grafana/grafana-foundation-sdk": "~11.6.0-cogv0.0.x.1746136285",
15 | "tslib": "~2.6"
16 | },
17 | "devDependencies": {
18 | "@types/node": "~20",
19 | "ts-node": "^10.9.2",
20 | "typescript": "~5.3"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/examples/typescript/red-method/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "custom-query",
3 | "version": "1.0.0",
4 | "license": "Apache-2.0",
5 | "author": "Grafana Labs",
6 | "private": true,
7 | "scripts": {
8 | "start": "node build/src/index.js",
9 | "dev": "ts-node src/index.ts",
10 | "build": "tsc -p tsconfig.json",
11 | "build:watch": "tsc -w -p tsconfig.json"
12 | },
13 | "dependencies": {
14 | "@grafana/grafana-foundation-sdk": "~11.6.0-cogv0.0.x.1746136285",
15 | "tslib": "~2.6"
16 | },
17 | "devDependencies": {
18 | "@types/node": "~20",
19 | "ts-node": "^10.9.2",
20 | "typescript": "~5.3"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/.cog/schemas/resource/manifest.cue:
--------------------------------------------------------------------------------
1 | package resource
2 |
3 | DashboardV2Beta1: "dashboard.grafana.app/v2beta1"
4 | DashboardV2Alpha1: "dashboard.grafana.app/v2alpha1"
5 | DashboardKind: "Dashboard"
6 |
7 | Manifest: {
8 | apiVersion: string
9 | kind: string
10 | metadata: #Metadata
11 | spec: _
12 | }
13 |
14 | #Metadata: {
15 | name: string
16 | namespace?: string
17 | labels?: [string]: string
18 | annotations?: [string]: string
19 | uid?: string
20 | resourceVersion?: string
21 | generation?: int64
22 | creationTimestamp?: string
23 | updateTimestamp?: string
24 | deletionTimestamp?: string
25 | }
26 |
--------------------------------------------------------------------------------
/examples/java/red-method/src/main/java/red/Main.java:
--------------------------------------------------------------------------------
1 | package red;
2 |
3 | import com.fasterxml.jackson.core.JsonProcessingException;
4 | import com.grafana.foundation.dashboard.Dashboard;
5 |
6 | import java.util.List;
7 |
8 | import static red.Red.red;
9 |
10 | public class Main {
11 | public static void main(String[] args) {
12 | Dashboard dashboard = red("RED method", List.of("sample-service", "payments", "front-gateway")).build();
13 |
14 | try {
15 | System.out.println(dashboard.toJSON());
16 | } catch (JsonProcessingException e) {
17 | throw new RuntimeException(e);
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/examples/typescript/custom-panel/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "custom-panel",
3 | "version": "1.0.0",
4 | "license": "Apache-2.0",
5 | "author": "Grafana Labs",
6 | "private": true,
7 | "scripts": {
8 | "start": "node build/src/index.js",
9 | "dev": "ts-node src/index.ts",
10 | "build": "tsc -p tsconfig.json",
11 | "build:watch": "tsc -w -p tsconfig.json"
12 | },
13 | "dependencies": {
14 | "@grafana/grafana-foundation-sdk": "~11.6.0-cogv0.0.x.1746136285",
15 | "tslib": "~2.6"
16 | },
17 | "devDependencies": {
18 | "@types/node": "~20",
19 | "ts-node": "^10.9.2",
20 | "typescript": "~5.3"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/examples/typescript/custom-query/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "custom-query",
3 | "version": "1.0.0",
4 | "license": "Apache-2.0",
5 | "author": "Grafana Labs",
6 | "private": true,
7 | "scripts": {
8 | "start": "node build/src/index.js",
9 | "dev": "ts-node src/index.ts",
10 | "build": "tsc -p tsconfig.json",
11 | "build:watch": "tsc -w -p tsconfig.json"
12 | },
13 | "dependencies": {
14 | "@grafana/grafana-foundation-sdk": "~11.6.0-cogv0.0.x.1746136285",
15 | "tslib": "~2.6"
16 | },
17 | "devDependencies": {
18 | "@types/node": "~20",
19 | "ts-node": "^10.9.2",
20 | "typescript": "~5.3"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/examples/typescript/linux-node-overview/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "custom-query",
3 | "version": "1.0.0",
4 | "license": "Apache-2.0",
5 | "author": "Grafana Labs",
6 | "private": true,
7 | "scripts": {
8 | "start": "node build/src/index.js",
9 | "dev": "ts-node src/index.ts",
10 | "build": "tsc -p tsconfig.json",
11 | "build:watch": "tsc -w -p tsconfig.json"
12 | },
13 | "dependencies": {
14 | "@grafana/grafana-foundation-sdk": "~11.6.0-cogv0.0.x.1746136285",
15 | "tslib": "~2.6"
16 | },
17 | "devDependencies": {
18 | "@types/node": "~20",
19 | "ts-node": "^10.9.2",
20 | "typescript": "~5.3"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/examples/typescript/grafana-agent-overview/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "custom-query",
3 | "version": "1.0.0",
4 | "license": "Apache-2.0",
5 | "author": "Grafana Labs",
6 | "private": true,
7 | "scripts": {
8 | "start": "node build/src/index.js",
9 | "dev": "ts-node src/index.ts",
10 | "build": "tsc -p tsconfig.json",
11 | "build:watch": "tsc -w -p tsconfig.json"
12 | },
13 | "dependencies": {
14 | "@grafana/grafana-foundation-sdk": "~11.6.0-cogv0.0.x.1746136285",
15 | "tslib": "~2.6"
16 | },
17 | "devDependencies": {
18 | "@types/node": "~20",
19 | "ts-node": "^10.9.2",
20 | "typescript": "~5.3"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/.cog/templates/java/overrides/api_reference_object_dashboard_Dashboard_extra.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "api_reference_object_dashboard_Dashboard_extra" -}}
2 | ## Examples
3 |
4 | ### Unmarshalling from JSON
5 |
6 | ```java
7 | public class Main {
8 | public static void main(String[] args) {
9 | ObjectMapper mapper = new ObjectMapper();
10 | try {
11 | InputStream json = Main.class.getResourceAsStream("/dashboard.json");
12 | Dashboard dashboard = mapper.readValue(json, Dashboard.class);
13 | System.out.println(dashboard.toJSON());
14 | } catch (IOException e) {
15 | e.printStackTrace();
16 | }
17 | }
18 | }
19 | ```
20 | {{ end }}
21 |
--------------------------------------------------------------------------------
/.cog/templates/java/extra/src/main/java/com/grafana/foundation/cog/variants/UnknownDataquerySerializer.java:
--------------------------------------------------------------------------------
1 | package com.grafana.foundation.cog.variants;
2 |
3 | import com.fasterxml.jackson.core.JsonGenerator;
4 | import com.fasterxml.jackson.databind.JsonSerializer;
5 | import com.fasterxml.jackson.databind.SerializerProvider;
6 |
7 | import java.io.IOException;
8 |
9 | public class UnknownDataquerySerializer extends JsonSerializer {
10 | @Override
11 | public void serialize(UnknownDataquery unknownDataquery, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
12 | jsonGenerator.writeObject(unknownDataquery.genericFields);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/scripts/validate/php.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Exit on error. Append "|| true" if you expect an error.
4 | set -o errexit
5 | # Exit on error inside any functions or subshells.
6 | set -o errtrace
7 | # Do not allow use of undefined vars. Use ${VAR:-} to use an undefined VAR
8 | set -o nounset
9 | # Catch the error in case mysqldump fails (but gzip succeeds) in `mysqldump | gzip`
10 | set -o pipefail
11 |
12 | __dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13 | source "${__dir}/../libs/logs.sh"
14 |
15 | release_path=${1:-"./"}
16 |
17 | cd "${release_path}"
18 |
19 | composer install
20 |
21 | debug " → running phpstan"
22 | phpstan analyze --memory-limit 512M -c .config/ci/php/phpstan.neon
23 |
--------------------------------------------------------------------------------
/.cog/veneers/dashboard.go.yaml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/grafana/cog/main/schemas/veneers.json
2 |
3 | language: go
4 |
5 | package: dashboard
6 |
7 | builders: ~
8 |
9 | options:
10 | ##############
11 | # Dashboards #
12 | ##############
13 |
14 | # Time(from, to) instead of time(struct {From string `json:"from"`, To string `json:"to"`}{From: "lala", To: "lala})
15 | - struct_fields_as_arguments:
16 | by_name: Dashboard.time
17 |
18 | ##############
19 | # Panels #
20 | ##############
21 |
22 | # WithOverride(matcher, properties) instead of WithOverride(struct{...})
23 | - struct_fields_as_arguments:
24 | by_name: Panel.withOverride
25 |
--------------------------------------------------------------------------------
/.cog/veneers/dashboard.php.yaml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/grafana/cog/main/schemas/veneers.json
2 |
3 | language: php
4 |
5 | package: dashboard
6 |
7 | builders: ~
8 |
9 | options:
10 | ##############
11 | # Dashboards #
12 | ##############
13 |
14 | # Time(from, to) instead of time(struct {From string `json:"from"`, To string `json:"to"`}{From: "lala", To: "lala})
15 | - struct_fields_as_arguments:
16 | by_name: Dashboard.time
17 |
18 | ##############
19 | # Panels #
20 | ##############
21 |
22 | # WithOverride(matcher, properties) instead of WithOverride(struct{...})
23 | - struct_fields_as_arguments:
24 | by_name: Panel.withOverride
25 |
--------------------------------------------------------------------------------
/examples/typescript/custom-panel/src/customPanel.ts:
--------------------------------------------------------------------------------
1 | import * as dashboard from '@grafana/grafana-foundation-sdk/dashboard';
2 |
3 | export interface CustomPanelOptions {
4 | makeBeautiful?: boolean;
5 | }
6 |
7 | export const defaultCustomPanelOptions = (): CustomPanelOptions => ({});
8 |
9 | export class CustomPanelBuilder extends dashboard.PanelBuilder {
10 | constructor() {
11 | super();
12 |
13 | this.internal.type = "custom-panel"; // panel plugin ID
14 | }
15 |
16 | makeBeautiful(): this {
17 | if (!this.internal.options) {
18 | this.internal.options = defaultCustomPanelOptions();
19 | }
20 | this.internal.options.makeBeautiful = true;
21 | return this;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/.cog/repository_templates/php/.config/ci/php/phpstan.neon:
--------------------------------------------------------------------------------
1 | parameters:
2 | level: 9 # https://phpstan.org/user-guide/rule-levels
3 | paths:
4 | - ../../../php/src
5 |
6 | ignoreErrors:
7 | - identifier: identical.alwaysFalse # not a big deal, duplicated enum values come from the schema
8 | paths:
9 | - ../../../php/src/Common/ScaleDirection.php
10 | - identifier: offsetAccess.nonOffsetAccessible
11 | paths:
12 | - ../../../php/src/Cog/Runtime.php
13 |
14 | # cog being very defensive isn't a bad thing
15 | - identifier: isset.variable
16 | - identifier: instanceof.alwaysTrue
17 | - identifier: function.alreadyNarrowedType
18 | - identifier: arrayFilter.same
19 |
--------------------------------------------------------------------------------
/examples/typescript/alert-rule/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es2022",
4 | "module": "node16",
5 | "lib": ["ES2022"],
6 | "moduleResolution": "node16",
7 | "rootDir": ".",
8 | "outDir": "build",
9 | "allowSyntheticDefaultImports": true,
10 | "importHelpers": true,
11 | "alwaysStrict": true,
12 | "sourceMap": true,
13 | "forceConsistentCasingInFileNames": true,
14 | "noFallthroughCasesInSwitch": true,
15 | "noImplicitReturns": true,
16 | "noUnusedLocals": true,
17 | "noUnusedParameters": true,
18 | "noImplicitAny": false,
19 | "noImplicitThis": false,
20 | "strictNullChecks": false
21 | },
22 | "include": ["src/*"]
23 | }
24 |
--------------------------------------------------------------------------------
/examples/typescript/custom-panel/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es2022",
4 | "module": "node16",
5 | "lib": ["ES2022"],
6 | "moduleResolution": "node16",
7 | "rootDir": ".",
8 | "outDir": "build",
9 | "allowSyntheticDefaultImports": true,
10 | "importHelpers": true,
11 | "alwaysStrict": true,
12 | "sourceMap": true,
13 | "forceConsistentCasingInFileNames": true,
14 | "noFallthroughCasesInSwitch": true,
15 | "noImplicitReturns": true,
16 | "noUnusedLocals": true,
17 | "noUnusedParameters": true,
18 | "noImplicitAny": false,
19 | "noImplicitThis": false,
20 | "strictNullChecks": false
21 | },
22 | "include": ["src/*"]
23 | }
24 |
--------------------------------------------------------------------------------
/examples/typescript/custom-query/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es2022",
4 | "module": "node16",
5 | "lib": ["ES2022"],
6 | "moduleResolution": "node16",
7 | "rootDir": ".",
8 | "outDir": "build",
9 | "allowSyntheticDefaultImports": true,
10 | "importHelpers": true,
11 | "alwaysStrict": true,
12 | "sourceMap": true,
13 | "forceConsistentCasingInFileNames": true,
14 | "noFallthroughCasesInSwitch": true,
15 | "noImplicitReturns": true,
16 | "noUnusedLocals": true,
17 | "noUnusedParameters": true,
18 | "noImplicitAny": false,
19 | "noImplicitThis": false,
20 | "strictNullChecks": false
21 | },
22 | "include": ["src/*"]
23 | }
24 |
--------------------------------------------------------------------------------
/examples/typescript/red-method/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es2022",
4 | "module": "node16",
5 | "lib": ["ES2022"],
6 | "moduleResolution": "node16",
7 | "rootDir": ".",
8 | "outDir": "build",
9 | "allowSyntheticDefaultImports": true,
10 | "importHelpers": true,
11 | "alwaysStrict": true,
12 | "sourceMap": true,
13 | "forceConsistentCasingInFileNames": true,
14 | "noFallthroughCasesInSwitch": true,
15 | "noImplicitReturns": true,
16 | "noUnusedLocals": true,
17 | "noUnusedParameters": true,
18 | "noImplicitAny": false,
19 | "noImplicitThis": false,
20 | "strictNullChecks": false
21 | },
22 | "include": ["src/*"]
23 | }
24 |
--------------------------------------------------------------------------------
/examples/typescript/grafana-agent-overview/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es2022",
4 | "module": "node16",
5 | "lib": ["ES2022"],
6 | "moduleResolution": "node16",
7 | "rootDir": ".",
8 | "outDir": "build",
9 | "allowSyntheticDefaultImports": true,
10 | "importHelpers": true,
11 | "alwaysStrict": true,
12 | "sourceMap": true,
13 | "forceConsistentCasingInFileNames": true,
14 | "noFallthroughCasesInSwitch": true,
15 | "noImplicitReturns": true,
16 | "noUnusedLocals": true,
17 | "noUnusedParameters": true,
18 | "noImplicitAny": false,
19 | "noImplicitThis": false,
20 | "strictNullChecks": false
21 | },
22 | "include": ["src/*"]
23 | }
24 |
--------------------------------------------------------------------------------
/examples/typescript/linux-node-overview/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es2022",
4 | "module": "node16",
5 | "lib": ["ES2022"],
6 | "moduleResolution": "node16",
7 | "rootDir": ".",
8 | "outDir": "build",
9 | "allowSyntheticDefaultImports": true,
10 | "importHelpers": true,
11 | "alwaysStrict": true,
12 | "sourceMap": true,
13 | "forceConsistentCasingInFileNames": true,
14 | "noFallthroughCasesInSwitch": true,
15 | "noImplicitReturns": true,
16 | "noUnusedLocals": true,
17 | "noUnusedParameters": true,
18 | "noImplicitAny": false,
19 | "noImplicitThis": false,
20 | "strictNullChecks": false
21 | },
22 | "include": ["src/*"]
23 | }
24 |
--------------------------------------------------------------------------------
/examples/java/red-method/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java'
3 | id 'application'
4 | }
5 |
6 | java {
7 | sourceCompatibility = JavaVersion.VERSION_17
8 | targetCompatibility = JavaVersion.VERSION_17
9 |
10 | withJavadocJar()
11 | withSourcesJar()
12 | }
13 |
14 | application {
15 | mainClass = "red.Main"
16 | }
17 |
18 | allprojects {
19 | version = rootProject.version
20 | apply plugin: "java"
21 |
22 | repositories {
23 | mavenCentral()
24 | }
25 | }
26 |
27 | dependencies {
28 | implementation("com.grafana:grafana-foundation-sdk:11.6.0-1746136285")
29 | }
30 |
31 | tasks.withType(Javadoc).configureEach {
32 | options.addStringOption('Xdoclint:-missing', '-quiet')
33 | }
34 |
--------------------------------------------------------------------------------
/examples/java/alert-rule/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java'
3 | id 'application'
4 | }
5 |
6 | java {
7 | sourceCompatibility = JavaVersion.VERSION_17
8 | targetCompatibility = JavaVersion.VERSION_17
9 |
10 | withJavadocJar()
11 | withSourcesJar()
12 | }
13 |
14 | application {
15 | mainClass = "alertrule.Main"
16 | }
17 |
18 | allprojects {
19 | version = rootProject.version
20 | apply plugin: "java"
21 |
22 | repositories {
23 | mavenCentral()
24 | }
25 | }
26 |
27 | dependencies {
28 | implementation("com.grafana:grafana-foundation-sdk:11.6.0-1746136285")
29 | }
30 |
31 | tasks.withType(Javadoc).configureEach {
32 | options.addStringOption('Xdoclint:-missing', '-quiet')
33 | }
34 |
--------------------------------------------------------------------------------
/examples/java/custom-panel/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java'
3 | id 'application'
4 | }
5 |
6 | java {
7 | sourceCompatibility = JavaVersion.VERSION_17
8 | targetCompatibility = JavaVersion.VERSION_17
9 |
10 | withJavadocJar()
11 | withSourcesJar()
12 | }
13 |
14 | application {
15 | mainClass = "custompanel.Main"
16 | }
17 |
18 | allprojects {
19 | version = rootProject.version
20 | apply plugin: "java"
21 |
22 | repositories {
23 | mavenCentral()
24 | }
25 | }
26 |
27 | dependencies {
28 | implementation("com.grafana:grafana-foundation-sdk:11.6.0-1746136285")
29 | }
30 |
31 | tasks.withType(Javadoc).configureEach {
32 | options.addStringOption('Xdoclint:-missing', '-quiet')
33 | }
34 |
--------------------------------------------------------------------------------
/examples/java/custom-query/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java'
3 | id 'application'
4 | }
5 |
6 | java {
7 | sourceCompatibility = JavaVersion.VERSION_17
8 | targetCompatibility = JavaVersion.VERSION_17
9 |
10 | withJavadocJar()
11 | withSourcesJar()
12 | }
13 |
14 | application {
15 | mainClass = "customquery.Main"
16 | }
17 |
18 | allprojects {
19 | version = rootProject.version
20 | apply plugin: "java"
21 |
22 | repositories {
23 | mavenCentral()
24 | }
25 | }
26 |
27 | dependencies {
28 | implementation("com.grafana:grafana-foundation-sdk:11.6.0-1746136285")
29 | }
30 |
31 | tasks.withType(Javadoc).configureEach {
32 | options.addStringOption('Xdoclint:-missing', '-quiet')
33 | }
34 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/3-general-issue.yaml:
--------------------------------------------------------------------------------
1 | name: General issue
2 | description: Ask for information, doubts, etc...
3 | title: "[Question]: "
4 | labels: [question, help wanted]
5 |
6 | body:
7 | - type: markdown
8 | attributes:
9 | value: |
10 | If you are looking for examples, you should take a look to [this link](https://github.com/grafana/grafana-foundation-sdk/tree/main/examples).
11 | Also each language in each branch has extra information about their setup.
12 | - type: markdown
13 | attributes:
14 | value: |
15 | #
16 |
17 | - type: textarea
18 | attributes:
19 | label: What do you need?
20 | description: Describe your issue.
21 | validations:
22 | required: true
23 |
--------------------------------------------------------------------------------
/examples/java/grafana-agent-overview/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java'
3 | id 'application'
4 | }
5 |
6 | java {
7 | sourceCompatibility = JavaVersion.VERSION_17
8 | targetCompatibility = JavaVersion.VERSION_17
9 |
10 | withJavadocJar()
11 | withSourcesJar()
12 | }
13 |
14 | application {
15 | mainClass = "agent.Main"
16 | }
17 |
18 | allprojects {
19 | version = rootProject.version
20 | apply plugin: "java"
21 |
22 | repositories {
23 | mavenCentral()
24 | }
25 | }
26 |
27 | dependencies {
28 | implementation("com.grafana:grafana-foundation-sdk:11.6.0-1746136285")
29 | }
30 |
31 | tasks.withType(Javadoc).configureEach {
32 | options.addStringOption('Xdoclint:-missing', '-quiet')
33 | }
34 |
--------------------------------------------------------------------------------
/examples/java/linux-node-overview/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java'
3 | id 'application'
4 | }
5 |
6 | java {
7 | sourceCompatibility = JavaVersion.VERSION_17
8 | targetCompatibility = JavaVersion.VERSION_17
9 |
10 | withJavadocJar()
11 | withSourcesJar()
12 | }
13 |
14 | application {
15 | mainClass = "linuxnode.Main"
16 | }
17 |
18 | allprojects {
19 | version = rootProject.version
20 | apply plugin: "java"
21 |
22 | repositories {
23 | mavenCentral()
24 | }
25 | }
26 |
27 | dependencies {
28 | implementation("com.grafana:grafana-foundation-sdk:11.6.0-1746136285")
29 | }
30 |
31 | tasks.withType(Javadoc).configureEach {
32 | options.addStringOption('Xdoclint:-missing', '-quiet')
33 | }
34 |
--------------------------------------------------------------------------------
/examples/php/custom-panel/src/Custom/Options.php:
--------------------------------------------------------------------------------
1 | makeBeautiful = $makeBeautiful ?: false;
12 | }
13 |
14 | public function jsonSerialize(): array
15 | {
16 | return [
17 | "makeBeautiful" => $this->makeBeautiful,
18 | ];
19 | }
20 |
21 | /**
22 | * @param array{makeBeautiful?: bool} $data
23 | */
24 | public static function fromArray(array $data): self
25 | {
26 | return new self(
27 | makeBeautiful: $data["makeBeautiful"] ?? null,
28 | );
29 | }
30 | }
--------------------------------------------------------------------------------
/.cog/templates/go/extra/docs/How-To/converting-a-dashboard.md:
--------------------------------------------------------------------------------
1 | # Converting a dashboard
2 |
3 | ```go
4 | package main
5 |
6 | import (
7 | "encoding/json"
8 | "fmt"
9 | "os"
10 |
11 | "github.com/grafana/grafana-foundation-sdk/go/cog/plugins"
12 | "github.com/grafana/grafana-foundation-sdk/go/dashboard"
13 | )
14 |
15 | func main() {
16 | // Required to correctly unmarshal panels and dataqueries
17 | plugins.RegisterDefaultPlugins()
18 |
19 | dashboardJSON, err := os.ReadFile("dashboard.json")
20 | if err != nil {
21 | panic(err)
22 | }
23 |
24 | dash := dashboard.Dashboard{}
25 | if err = json.Unmarshal(dashboardJSON, &dash); err != nil {
26 | panic(err)
27 | }
28 |
29 | converted := dashboard.DashboardConverter(dash)
30 | fmt.Println(converted)
31 | }
32 | ```
33 |
--------------------------------------------------------------------------------
/.cog/veneers/common.common.yaml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/grafana/cog/main/schemas/veneers.json
2 |
3 | language: all
4 |
5 | package: common
6 |
7 | builders:
8 | ###############
9 | # Table panel #
10 | ###############
11 |
12 | - omit: { by_name: TableAutoCellOptions }
13 | - omit: { by_name: TableSparklineCellOptions }
14 | - omit: { by_name: TableBarGaugeCellOptions }
15 | - omit: { by_name: TableColoredBackgroundCellOptions }
16 | - omit: { by_name: TableColorTextCellOptions }
17 | - omit: { by_name: TableImageCellOptions }
18 | - omit: { by_name: TableDataLinksCellOptions }
19 | - omit: { by_name: TableActionsCellOptions }
20 | - omit: { by_name: TableJsonViewCellOptions }
21 |
22 | - omit: { by_name: DataSourceRef }
23 |
--------------------------------------------------------------------------------
/.cog/templates/python/extra/grafana_foundation_sdk/cog/plugins.py:
--------------------------------------------------------------------------------
1 | {{- $panelPackages := .Context.PackagesForVariant "panelcfg" -}}
2 | {{- $dataqueryPackages := .Context.PackagesForVariant "dataquery" -}}
3 | {{- range $pkg := $panelPackages }}
4 | from ..models import {{ $pkg }}
5 | {{- end }}
6 | {{- range $pkg := $dataqueryPackages }}
7 | from ..models import {{ $pkg }}
8 | {{- end }}
9 | from . import runtime as cogruntime
10 |
11 |
12 | def register_default_plugins():
13 | # Panelcfg variants
14 | {{- range $pkg := $panelPackages }}
15 | cogruntime.register_panelcfg_variant({{ $pkg }}.variant_config())
16 | {{- end }}
17 |
18 | # Dataquery variants
19 | {{- range $pkg := $dataqueryPackages }}
20 | cogruntime.register_dataquery_variant({{ $pkg }}.variant_config())
21 | {{- end }}
22 |
--------------------------------------------------------------------------------
/.cog/templates/java/overrides/assigment_Dashboard_WithRow.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "pre_assignment_Dashboard_withRow" }}
2 |
3 | // Position the row on the grid
4 | if (panelOrRowPanel.rowPanel.gridPos == null || (panelOrRowPanel.rowPanel.gridPos.x == 0 && panelOrRowPanel.rowPanel.gridPos.y == 0)) {
5 | GridPos gridPos = new GridPos();
6 | gridPos.x = 0; // beginning of the line
7 | gridPos.y = this.currentY;
8 | gridPos.h = 1;
9 | gridPos.w = 24; // full width
10 | panelOrRowPanel.rowPanel.gridPos = gridPos;
11 | }
12 | {{- end }}
13 |
14 | {{- define "post_assignment_Dashboard_withRow" }}
15 |
16 | // Reset the state for the next row
17 | this.currentX = 0;
18 | this.currentY += panelOrRowPanel.rowPanel.gridPos.h;
19 | this.lastPanelHeight = 0;
20 | {{- end }}
21 |
--------------------------------------------------------------------------------
/.cog/compiler/prometheus.yaml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/grafana/cog/main/schemas/compiler_passes.json
2 |
3 | passes:
4 | - unspec: {}
5 |
6 | - retype_field:
7 | field: prometheus.Dataquery.datasource
8 | as:
9 | kind: ref
10 | ref: { referred_pkg: common, referred_type: DataSourceRef }
11 |
12 | # Add a few missing fields.
13 | # This is meant to be removed once the schema is updated.
14 | - add_fields:
15 | to: prometheus.dataquery
16 | fields:
17 | - name: interval
18 | comments: ['An additional lower limit for the step parameter of the Prometheus query and for the', '`$__interval` and `$__rate_interval` variables.']
19 | type:
20 | kind: scalar
21 | scalar: { scalar_kind: string }
22 |
--------------------------------------------------------------------------------
/.cog/templates/go/overrides/object_dashboard_Panel_field_options_custom_strict_unmarshal.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "object_dashboard_Panel_field_options_custom_strict_unmarshal" -}}
2 | {{- /* Non-standard unmarshalling to parse the correct Options struct based on the panel type */}}
3 | variantCfg, found := cog.ConfigForPanelcfgVariant(resource.Type)
4 | if found && variantCfg.StrictOptionsUnmarshaler != nil {
5 | options, err := variantCfg.StrictOptionsUnmarshaler(fields["options"])
6 | if err != nil {
7 | errs = append(errs, cog.MakeBuildErrors("options", err)...)
8 | } else {
9 | resource.Options = options
10 | }
11 | } else {
12 | if err := json.Unmarshal(fields["options"], &resource.Options); err != nil {
13 | errs = append(errs, cog.MakeBuildErrors("options", err)...)
14 | }
15 | }
16 |
17 | {{ end }}
18 |
--------------------------------------------------------------------------------
/examples/php/custom-panel/src/Custom/PanelBuilder.php:
--------------------------------------------------------------------------------
1 |
10 | */
11 | class PanelBuilder extends Dashboard\PanelBuilder implements Cog\Builder
12 | {
13 | public function __construct()
14 | {
15 | parent::__construct();
16 | $this->internal->type = 'custom-panel';
17 | }
18 |
19 | public function makeBeautiful(): static
20 | {
21 | if ($this->internal->options === null) {
22 | $this->internal->options = new Options();
23 | }
24 | assert($this->internal->options instanceof Options);
25 | $this->internal->options->makeBeautiful = true;
26 |
27 | return $this;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/.cog/templates/go/overrides/object_common_TableFooterOptions_field_fields_custom_strict_unmarshal.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "object_common_TableFooterOptions_field_fields_custom_strict_unmarshal" -}}
2 | {{- /* Non-standard unmarshalling needed because even though the "fields" field
3 | is typed as []string in the schema, Grafana uses `""` as an empty value
4 | */ -}}
5 | if len(fields["fields"]) != 0 && fields["fields"][0] == '"' {
6 | var field string
7 | if err := json.Unmarshal(fields["fields"], &field); err != nil {
8 | errs = append(errs, cog.MakeBuildErrors("fields", err)...)
9 | } else {
10 | resource.Fields = []string{field}
11 | }
12 | } else {
13 | if err := json.Unmarshal(fields["fields"], &resource.Fields); err != nil {
14 | errs = append(errs, cog.MakeBuildErrors("fields", err)...)
15 | }
16 | }
17 |
18 | {{ end }}
19 |
--------------------------------------------------------------------------------
/.cog/templates/php/overrides/api_reference_object_dashboard_Dashboard_extra.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "api_reference_object_dashboard_Dashboard_extra" -}}
2 | ## Examples
3 |
4 | ### Encoding to JSON
5 |
6 | ```php
7 | use Grafana\Foundation\Dashboard\Dashboard;
8 |
9 | require_once __DIR__.'/vendor/autoload.php';
10 |
11 | $dashboard = new Dashboard(
12 | uid: 'sample-dashboard-uid',
13 | title: 'Sample dashboard',
14 | );
15 |
16 | echo(json_encode($dashboard, JSON_PRETTY_PRINT).PHP_EOL);
17 | ```
18 |
19 | ### Decoding from JSON
20 |
21 | ```php
22 | use Grafana\Foundation\Dashboard\Dashboard;
23 |
24 | require_once __DIR__.'/vendor/autoload.php';
25 |
26 | $dashboardJSON = file_get_contents(__DIR__.'/dashboard.json');
27 |
28 | $dashboard = Dashboard::fromArray(json_decode($dashboardJSON, true));
29 |
30 | var_dump($dashboard);
31 | ```
32 | {{ end }}
33 |
--------------------------------------------------------------------------------
/examples/java/custom-query/src/main/java/customquery/CustomQueryBuilder.java:
--------------------------------------------------------------------------------
1 | package customquery;
2 |
3 | import com.grafana.foundation.cog.Builder;
4 | import com.grafana.foundation.cog.variants.Dataquery;
5 |
6 | public class CustomQueryBuilder implements Builder {
7 | private final CustomQuery internal;
8 |
9 | public CustomQueryBuilder(String query) {
10 | this.internal = new CustomQuery();
11 | this.internal.query = query;
12 | }
13 |
14 | public CustomQueryBuilder refId(String refId) {
15 | this.internal.refId = refId;
16 | return this;
17 | }
18 |
19 | public CustomQueryBuilder hide(Boolean hide) {
20 | this.internal.hide = hide;
21 | return this;
22 | }
23 |
24 | @Override
25 | public CustomQuery build() {
26 | return this.internal;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/examples/php/custom-query/index.php:
--------------------------------------------------------------------------------
1 | registerDataqueryVariant(new Cog\DataqueryConfig(
12 | identifier: 'custom', // datasource plugin ID
13 | fromArray: [Custom\Query::class, 'fromArray'],
14 | ));
15 |
16 | $builder = (new DashboardBuilder(title: '[Example] Custom query'))
17 | ->uid('example-custom-query')
18 | ->withPanel(
19 | (new Timeseries\PanelBuilder())
20 | ->title('Sample panel')
21 | ->withTarget(new Custom\QueryBuilder('query here'))
22 | )
23 | ;
24 |
25 | var_dump($builder->build());
--------------------------------------------------------------------------------
/.cog/schemas/composable/athena/dataquery.cue:
--------------------------------------------------------------------------------
1 | package athena
2 |
3 | import (
4 | "github.com/grafana/grafana/packages/grafana-schema/src/common"
5 | )
6 |
7 | // Manually converted from https://github.com/grafana/athena-datasource/blob/57ad707147b7a11e9a521a836d6bf9799877e0e3/src/types.ts
8 | Dataquery: {
9 | common.DataQuery
10 |
11 | format: #FormatOptions
12 | connectionArgs: #ConnectionArgs
13 | table?: string
14 | column?: string
15 |
16 | queryID?: string
17 |
18 | rawSQL: string | *""
19 | }
20 |
21 | defaultKey: "__default"
22 |
23 | #ConnectionArgs: {
24 | region?: string | *defaultKey
25 | catalog?: string | *defaultKey
26 | database?: string | *defaultKey
27 | resultReuseEnabled?: bool | *false
28 | resultReuseMaxAgeInMinutes?: number | *60
29 | }
30 |
31 | #FormatOptions: 0 | 1 | 2 @cog(kind="enum", memberNames="TimeSeries|Table|Logs")
32 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | Babel==2.15.0
2 | brotlicffi==1.1.0.0
3 | certifi==2024.7.4
4 | cffi==1.17.1
5 | charset-normalizer==3.3.2
6 | click==8.1.7
7 | colorama==0.4.6
8 | ghp-import==2.1.0
9 | idna==3.7
10 | importlib_metadata==7.1.0
11 | Jinja2==3.1.4
12 | Markdown==3.7
13 | MarkupSafe==2.1.5
14 | mergedeep==1.3.4
15 | mkdocs==1.6.1
16 | mkdocs-get-deps==0.2.0
17 | mkdocs-material==9.5.39
18 | mkdocs-material-extensions==1.3.1
19 | mkdocs-nav-weight==0.2.0
20 | mypy==1.10.0
21 | mypy-extensions==1.0.0
22 | packaging==24.1
23 | paginate==0.5.7
24 | pathspec==0.12.1
25 | platformdirs==4.2.2
26 | pycparser==2.22
27 | Pygments==2.18.0
28 | pymdown-extensions==10.11.2
29 | python-dateutil==2.9.0.post0
30 | PyYAML==6.0.2
31 | pyyaml_env_tag==0.1
32 | regex==2024.5.15
33 | requests==2.32.3
34 | six==1.16.0
35 | toml==0.10.2
36 | typing_extensions==4.12.2
37 | urllib3==2.2.2
38 | watchdog==4.0.1
39 | zipp==3.19.2
40 |
--------------------------------------------------------------------------------
/.cog/templates/go/overrides/object_dashboard_DataSourceRef_custom_unmarshal.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "object_dashboard_DataSourceRef_custom_unmarshal" }}
2 | {{- /* Non-standard unmarshalling, to support "legacy" datasource references. ie: older versions of Grafana reference datasources directly by their name */ -}}
3 | func (resource *DataSourceRef) UnmarshalJSON(raw []byte) error {
4 | if raw == nil {
5 | return nil
6 | }
7 |
8 | if raw[0] == '"' {
9 | var datasourceUid string
10 | if err := json.Unmarshal(raw, &datasourceUid); err != nil {
11 | return err
12 | }
13 | resource.Uid = &datasourceUid
14 | } else {
15 | type original DataSourceRef
16 |
17 | if err := json.Unmarshal(raw, (*original)(resource)); err != nil {
18 | return err
19 | }
20 | }
21 |
22 | return nil
23 | }
24 |
25 | {{ end }}
26 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/2-feature-request.yaml:
--------------------------------------------------------------------------------
1 | name: Feature/enhancement request
2 | description: Request for feature or enhancement that are you would like to see.
3 | title: "[Feature]: "
4 | labels: [enhancement]
5 |
6 | body:
7 | - type: markdown
8 | attributes:
9 | value: |
10 | Grafana-foundation-SDK is open to improvements. We will evaluate your request.
11 | - type: markdown
12 | attributes:
13 | value: |
14 | #
15 |
16 | - type: textarea
17 | attributes:
18 | label: Why is this needed?
19 | description: Describe the problem that you want to solve.
20 | validations:
21 | required: true
22 |
23 | - type: textarea
24 | attributes:
25 | label: What would you like to be added?
26 | description: Add a brief description of the feature o enhancement should do.
27 | validations:
28 | required: true
29 |
--------------------------------------------------------------------------------
/scripts/release-validate.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Exit on error. Append "|| true" if you expect an error.
4 | set -o errexit
5 | # Exit on error inside any functions or subshells.
6 | set -o errtrace
7 | # Do not allow use of undefined vars. Use ${VAR:-} to use an undefined VAR
8 | set -o nounset
9 | # Catch the error in case mysqldump fails (but gzip succeeds) in `mysqldump | gzip`
10 | set -o pipefail
11 |
12 | __dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13 | source "${__dir}/libs/logs.sh"
14 |
15 | release_path=${1:-"./"}
16 |
17 | find "${release_path}" -maxdepth 1 -mindepth 1 -type d -not -path '*/.*' -print | while read -r target; do
18 | target=${target#"$release_path/"}
19 |
20 | if [ -e "${__dir}/validate/${target}.sh" ]; then
21 | info " → checking ${target}"
22 | ${__dir}/validate/${target}.sh "${release_path}"
23 | else
24 | warning " → skipping ${target}: no validator file found"
25 | fi
26 | done
--------------------------------------------------------------------------------
/.cog/veneers/alerting.common.yaml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/grafana/cog/main/schemas/veneers.json
2 |
3 | language: all
4 |
5 | package: alerting
6 |
7 | builders:
8 | - omit: { by_object: RelativeTimeRange }
9 |
10 | # Make some constructors more friendly
11 | - promote_options_to_constructor:
12 | by_object: RuleGroup
13 | options: [title]
14 | - promote_options_to_constructor:
15 | by_object: Rule
16 | options: [title]
17 | - promote_options_to_constructor:
18 | by_object: Query
19 | options: [refId]
20 |
21 | options:
22 | - duplicate:
23 | by_name: RuleGroup.rules
24 | as: withRule
25 | - array_to_append:
26 | by_name: RuleGroup.withRule
27 |
28 | - rename:
29 | by_name: Rule.data
30 | as: queries
31 | - duplicate:
32 | by_name: Rule.queries
33 | as: withQuery
34 | - array_to_append:
35 | by_name: Rule.withQuery
36 |
--------------------------------------------------------------------------------
/examples/php/custom-panel/index.php:
--------------------------------------------------------------------------------
1 | registerPanelcfgVariant(new Cog\PanelcfgConfig(
12 | identifier: 'custom-panel', // panel plugin ID
13 | optionsFromArray: [Custom\Options::class, 'fromArray'],
14 | ));
15 |
16 | $builder = (new DashboardBuilder(title: '[Example] Custom panel type'))
17 | ->uid('example-custom-panel')
18 | ->refresh('1m')
19 | ->time('now-30m', 'now')
20 | ->withRow(new RowBuilder('Overview'))
21 | ->withPanel(
22 | (new Custom\PanelBuilder())
23 | ->title('Sample panel')
24 | ->makeBeautiful()
25 | )
26 | ;
27 |
28 | var_dump($builder->build());
29 |
--------------------------------------------------------------------------------
/.github/actions/setup-cog/action.yaml:
--------------------------------------------------------------------------------
1 | name: "Setup cog"
2 | description: "Downloads cog and adds it to the $PATH"
3 | inputs:
4 | version:
5 | description: "Cog version to install"
6 | required: true
7 | default: "0.0.46"
8 | outputs:
9 | bin-path:
10 | description: "Path to the cog binary"
11 | value: ${{ steps.setup.outputs.bin-path }}
12 | runs:
13 | using: "composite"
14 | steps:
15 | - name: Download cog
16 | shell: bash
17 | env:
18 | COG_VERSION: ${{ inputs.version }}
19 | run: |
20 | version="$(echo "${COG_VERSION}" | sed 's/[^a-zA-Z0-9._\/-]//g')"
21 | mkdir -p "${HOME}/.local/bin/"
22 | wget https://github.com/grafana/cog/releases/download/v${version}/cog_Linux_x86_64.tar.gz
23 | tar -xzf cog_Linux_x86_64.tar.gz
24 | mv cog "${HOME}/.local/bin/cog"
25 | chmod +x "${HOME}/.local/bin/cog"
26 | echo "bin-path=${HOME}/.local/bin" >> "${GITHUB_OUTPUT}"
27 |
--------------------------------------------------------------------------------
/.cog/templates/go/overrides/object_dashboard_Panel_field_targets_custom_strict_unmarshal.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "object_dashboard_Panel_field_targets_custom_strict_unmarshal" -}}
2 | {{- /* Non-standard unmarshalling to use the possible datasourceRef defined on the panel when unmarshalling dataqueries */}}
3 | rawDataqueries := []json.RawMessage{}
4 | if err := json.Unmarshal(fields["targets"], &rawDataqueries); err != nil {
5 | return err
6 | }
7 |
8 | dataqueryTypeHint := ""
9 | if resource.Datasource != nil && resource.Datasource.Type != nil {
10 | dataqueryTypeHint = *resource.Datasource.Type
11 | }
12 |
13 | for i1 := range rawDataqueries {
14 | dataquery, err := cog.StrictUnmarshalDataquery(rawDataqueries[i1], dataqueryTypeHint)
15 | if err != nil {
16 | errs = append(errs, cog.MakeBuildErrors("targets["+strconv.Itoa(i1)+"]", err)...)
17 | continue
18 | }
19 |
20 | resource.Targets = append(resource.Targets, dataquery)
21 | }
22 |
23 | {{ end }}
24 |
--------------------------------------------------------------------------------
/.cog/templates/go/overrides/assignment_Dashboard_withPanel.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "pre_assignment_Dashboard_withPanel" }}
2 |
3 | if panelResource.GridPos == nil {
4 | panelResource.GridPos = NewGridPos()
5 | }
6 | // The panel either has no position set, or it is the first panel of the dashboard.
7 | // In that case, we position it on the grid
8 | if panelResource.GridPos.X == 0 && panelResource.GridPos.Y == 0 {
9 | panelResource.GridPos.X = builder.currentX
10 | panelResource.GridPos.Y = builder.currentY
11 | }
12 | {{- end }}
13 |
14 | {{- define "post_assignment_Dashboard_withPanel" }}
15 |
16 | // Prepare the coordinates for the next panel
17 | builder.currentX += panelResource.GridPos.W
18 | builder.lastPanelHeight = max(builder.lastPanelHeight, panelResource.GridPos.H)
19 |
20 | // Check for grid width overflow?
21 | if builder.currentX >= 24 {
22 | builder.currentX = 0
23 | builder.currentY += builder.lastPanelHeight
24 | builder.lastPanelHeight = 0
25 | }
26 | {{- end }}
27 |
--------------------------------------------------------------------------------
/examples/python/custom-panel/main.py:
--------------------------------------------------------------------------------
1 | from grafana_foundation_sdk.builders.dashboard import Dashboard
2 | from grafana_foundation_sdk.cog.encoder import JSONEncoder
3 | from grafana_foundation_sdk.cog.plugins import register_default_plugins
4 | from grafana_foundation_sdk.cog.runtime import register_panelcfg_variant
5 |
6 | from src.custompanel import custom_panel_variant_config, CustomPanelBuilder
7 |
8 |
9 | if __name__ == "__main__":
10 | # Required to correctly unmarshal panels and dataqueries
11 | register_default_plugins()
12 |
13 | # This lets cog know about the newly created panel type and how to unmarshal it.
14 | register_panelcfg_variant(custom_panel_variant_config())
15 |
16 | dashboard = (
17 | Dashboard("[Example] Custom panel")
18 | .uid("example-custom-panel")
19 | .with_panel(CustomPanelBuilder().title("Sample custom panel").make_beautiful())
20 | ).build()
21 |
22 | print(JSONEncoder(sort_keys=True, indent=2).encode(dashboard))
23 |
--------------------------------------------------------------------------------
/.cog/templates/python/overrides/assignment_Dashboard_withPanel.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "pre_assignment_Dashboard_withPanel" }}
2 |
3 | if panel_resource.grid_pos is None:
4 | panel_resource.grid_pos = dashboard.GridPos()
5 |
6 | # The panel either has no position set, or it is the first panel of the dashboard.
7 | # In that case, we position it on the grid
8 | if panel_resource.grid_pos.x == 0 and panel_resource.grid_pos.y == 0:
9 | panel_resource.grid_pos.x = self.__current_x
10 | panel_resource.grid_pos.y = self.__current_y
11 | {{- end }}
12 |
13 | {{- define "post_assignment_Dashboard_withPanel" }}
14 |
15 | # Prepare the coordinates for the next panel
16 | self.__current_x += panel_resource.grid_pos.w
17 | self.__last_panel_height = max(self.__last_panel_height, panel_resource.grid_pos.h)
18 |
19 | # Check for grid width overflow?
20 | if self.__current_x >= 24:
21 | self.__current_x = 0
22 | self.__current_y += self.__last_panel_height
23 | self.__last_panel_height = 0
24 | {{- end }}
25 |
--------------------------------------------------------------------------------
/scripts/release-all.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Exit on error. Append "|| true" if you expect an error.
4 | set -o errexit
5 | # Exit on error inside any functions or subshells.
6 | set -o errtrace
7 | # Do not allow use of undefined vars. Use ${VAR:-} to use an undefined VAR
8 | set -o nounset
9 | # Catch the error in case mysqldump fails (but gzip succeeds) in `mysqldump |gzip`
10 | set -o pipefail
11 |
12 | bold=$(tput bold)
13 | normal=$(tput sgr0)
14 |
15 | __dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
16 | source "${__dir}/libs/logs.sh"
17 | source "${__dir}/versions.sh"
18 |
19 | #################
20 | ### Usage ###
21 | #################
22 |
23 | # LOG_LEVEL=7 ./scripts/release-all.sh
24 |
25 | ############
26 | ### Main ###
27 | ############
28 |
29 | for version in ${ALL_GRAFANA_VERSIONS//;/ } ; do
30 | log_group_start "Releasing ${version}"
31 |
32 | info "🪧 Releasing ${bold}${version}${normal}"
33 | $__dir/release-version.sh "${version}"
34 |
35 | log_group_end
36 | done
37 |
--------------------------------------------------------------------------------
/.cog/templates/typescript/overrides/assignment_Dashboard_withPanel.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "pre_assignment_Dashboard_withPanel" }}
2 |
3 | if (!panelResource.gridPos) {
4 | panelResource.gridPos = dashboard.defaultGridPos();
5 | }
6 |
7 | // The panel either has no position set, or it is the first panel of the dashboard.
8 | // In that case, we position it on the grid
9 | if (panelResource.gridPos.x == 0 && panelResource.gridPos.y == 0) {
10 | panelResource.gridPos.x = this.currentX;
11 | panelResource.gridPos.y = this.currentY;
12 | }
13 | {{- end }}
14 |
15 | {{- define "post_assignment_Dashboard_withPanel" }}
16 |
17 | // Prepare the coordinates for the next panel
18 | this.currentX += panelResource.gridPos.w;
19 | this.lastPanelHeight = Math.max(this.lastPanelHeight, panelResource.gridPos.h);
20 |
21 | // Check for grid width overflow?
22 | if (this.currentX >= 24) {
23 | this.currentX = 0;
24 | this.currentY += this.lastPanelHeight;
25 | this.lastPanelHeight = 0;
26 | }
27 | {{- end }}
28 |
--------------------------------------------------------------------------------
/.cog/templates/java/extra/src/main/java/com/grafana/foundation/cog/variants/DataqueryConfig.java:
--------------------------------------------------------------------------------
1 | package com.grafana.foundation.cog.variants;
2 | {{ if .Data.Config.GenerateConverters }}
3 | import com.grafana.foundation.cog.Converter;
4 | {{- end }}
5 |
6 | public class DataqueryConfig {
7 | private final Class extends Dataquery> dataquery;
8 | {{ if .Data.Config.GenerateConverters }}private final Converter converter;{{ end }}
9 |
10 | public DataqueryConfig(Class extends Dataquery> dataquery{{ if .Data.Config.GenerateConverters }}, Converter converter{{ end }}) {
11 | this.dataquery = dataquery;
12 | {{ if .Data.Config.GenerateConverters }}this.converter = converter;{{ end }}
13 | }
14 |
15 | public Class extends Dataquery> getDataquery() {
16 | return dataquery;
17 | }
18 |
19 | {{- if .Data.Config.GenerateConverters }}
20 | public Converter getConverter() {
21 | return converter;
22 | }
23 | {{- end }}
24 | }
25 |
--------------------------------------------------------------------------------
/examples/java/custom-panel/src/main/java/custompanel/Main.java:
--------------------------------------------------------------------------------
1 | package custompanel;
2 |
3 | import com.fasterxml.jackson.core.JsonProcessingException;
4 | import com.grafana.foundation.cog.variants.Registry;
5 | import com.grafana.foundation.dashboard.Dashboard;
6 | import com.grafana.foundation.dashboard.DashboardBuilder;
7 |
8 | public class Main {
9 | public static void main(String[] args) {
10 | Registry.registerPanel("custom-panel", CustomPanelOptions.class, null);
11 |
12 | Dashboard dashboard = new DashboardBuilder("[Example] Custom Panel").
13 | uid("example-custom-panel").
14 | withPanel(new CustomPanelBuilder().
15 | title("Sample custom panel").
16 | makeItBeautiful()
17 | ).
18 | build();
19 |
20 | try {
21 | System.out.println(dashboard.toJSON());
22 | } catch (JsonProcessingException e) {
23 | throw new RuntimeException(e);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/.cog/templates/python/overrides/variant_dataquery_field_unmarshal.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "variant_dataquery_field_unmarshal" -}}
2 | {{- $dataqueryHint := "\"\"" -}}
3 | {{- range $candidate := .Object.Type.Struct.Fields -}}
4 | {{- if and ($candidate.Type.IsRef) (eq $candidate.Type.Ref.ReferredType "DataSourceRef") -}}
5 | {{- $dataqueryHint = include "dataquery_field_unmarshal_hint" (dict "Candidate" $candidate) -}}
6 | {{- end -}}
7 | {{- end -}}
8 | {{- $cogruntime := importModule "cogruntime" "..cog" "runtime" -}}
9 |
10 | {{- if .Field.Type.IsArray -}}
11 | [{{ $cogruntime }}.dataquery_from_json(dataquery_json, {{ $dataqueryHint }}) for dataquery_json in data["{{ .Field.Name }}"]]
12 | {{- else -}}
13 | {{ $cogruntime }}.dataquery_from_json(data["{{ .Field.Name }}"], {{ $dataqueryHint }})
14 | {{- end -}}
15 | {{- end }}
16 |
17 | {{- define "dataquery_field_unmarshal_hint" -}}
18 | data["{{ .Candidate.Name }}"]["type"] if data.get("{{ .Candidate.Name }}") is not None and data["{{ .Candidate.Name }}"].get("type", "") != "" else ""
19 | {{- end }}
--------------------------------------------------------------------------------
/examples/pulumi/python/__main__.py:
--------------------------------------------------------------------------------
1 | from grafana_foundation_sdk.cog.encoder import JSONEncoder
2 | import pulumiverse_grafana as grafana
3 | import pulumi
4 | import os
5 | import sys
6 |
7 |
8 | if __name__ == '__main__':
9 | # Hack to re-use other examples
10 | sys.path.append(os.path.join(os.path.dirname(__file__),
11 | "..", '..', "python", "linux-node-overview"))
12 | from main import builder
13 |
14 | provider = grafana.Provider(
15 | 'grafana', url='http://localhost:3000', auth='admin:admin')
16 |
17 | dashboard = builder.build()
18 | dashboard_json = JSONEncoder(
19 | sort_keys=True, indent=2).encode(dashboard)
20 |
21 | pulumi_dashboard = grafana.dashboard.Dashboard(dashboard.uid,
22 | config_json=dashboard_json,
23 | opts=pulumi.ResourceOptions(providers=[provider]))
24 |
25 | # Export the Name of the repository
26 | pulumi.export('dashboardUID', pulumi_dashboard.uid)
27 |
--------------------------------------------------------------------------------
/.cog/templates/python/overrides/object_dashboardv2beta1_DataQueryKind_custom_unmarshal.tmpl.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "object_dashboardv2beta1_DataQueryKind_custom_unmarshal" }}
2 | @classmethod
3 | def from_json(cls, data: dict[str, typing.Any]) -> typing.Self:
4 | args: dict[str, typing.Any] = {}
5 | {{ range $field := .Object.Type.Struct.Fields }}
6 | {{- if eq $field.Name "spec" }}
7 | if "{{ $field.Name }}" in data:
8 | args["{{ $field.Name }}"] = {{ template "dashboardv2beta1_DataQueryKind_spec_unmarshal" (dict "Field" $field) }}
9 | {{- else if $field.Type.IsConcreteScalar }}
10 | {{ continue}}
11 | {{- else }}
12 | if "{{ $field.Name }}" in data:
13 | args["{{ $field.Name }}"] = data["{{ $field.Name }}"]
14 | {{ end -}}
15 | {{ end }}
16 | return cls(**args)
17 | {{- end }}
18 |
19 | {{- define "dashboardv2beta1_DataQueryKind_spec_unmarshal" -}}
20 | {{- $cogruntime := importModule "cogruntime" "..cog" "runtime" -}}
21 | {{ $cogruntime }}.dataquery_from_json(data["{{ .Field.Name }}"], data["group"])
22 | {{- end }}
23 |
--------------------------------------------------------------------------------
/.cog/templates/python/overrides/schema_variant_panelcfg.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "schema_variant_panelcfg" -}}
2 | {{- $_ := apiDeclareFunction (dict
3 | "pkg" .Schema.Package
4 | "name" "variant_config"
5 | "comments" (listStr
6 | (print "variant_config returns the configuration related to " (.Schema.Metadata.Identifier|lower) " panels.")
7 | "This configuration describes how to unmarshal it, convert it to code, …"
8 | )
9 | "return" "variants.PanelcfgConfig"
10 | ) -}}
11 | {{- $cogruntime := importModule "cogruntime" "..cog" "runtime" -}}
12 | {{- $options := ternary "Options.from_json" "None" (schemaHasObject .Schema "Options") -}}
13 | {{- $fieldConfig := ternary "FieldConfig.from_json" "None" (schemaHasObject .Schema "FieldConfig") -}}
14 |
15 | def variant_config() -> {{ $cogruntime }}.PanelCfgConfig:
16 | return {{ $cogruntime }}.PanelCfgConfig(
17 | identifier="{{ .Schema.Metadata.Identifier }}",
18 | options_from_json_hook={{ $options }},
19 | field_config_from_json_hook={{ $fieldConfig }},
20 | )
21 | {{ end }}
--------------------------------------------------------------------------------
/examples/go/custom-panel/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 |
7 | "github.com/grafana/grafana-foundation-sdk/go/cog"
8 | "github.com/grafana/grafana-foundation-sdk/go/cog/plugins"
9 | "github.com/grafana/grafana-foundation-sdk/go/dashboard"
10 | )
11 |
12 | func main() {
13 | // Required to correctly unmarshal panels and dataqueries
14 | plugins.RegisterDefaultPlugins()
15 |
16 | // This lets cog know about the newly created query type and how to unmarshal it.
17 | cog.NewRuntime().RegisterPanelcfgVariant(CustomPanelVariantConfig())
18 |
19 | builder := dashboard.NewDashboardBuilder("[Example] Custom panel").
20 | Uid("example-custom-panel").
21 | WithPanel(
22 | NewCustomPanelBuilder().
23 | Title("Sample custom panel").
24 | MakeBeautiful(),
25 | )
26 |
27 | sampleDashboard, err := builder.Build()
28 | if err != nil {
29 | panic(err)
30 | }
31 |
32 | dashboardJson, err := json.MarshalIndent(sampleDashboard, "", " ")
33 | if err != nil {
34 | panic(err)
35 | }
36 |
37 | fmt.Println(string(dashboardJson))
38 | }
39 |
--------------------------------------------------------------------------------
/.cog/templates/python/overrides/api_reference_object_dashboard_Dashboard_extra.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "api_reference_object_dashboard_Dashboard_extra" -}}
2 | ## Examples
3 |
4 | ### Marshalling to JSON
5 |
6 | ```python
7 | from grafana_foundation_sdk.cog.encoder import JSONEncoder
8 | from grafana_foundation_sdk.models.dashboard import Dashboard
9 |
10 |
11 | if __name__ == '__main__':
12 | dashboard = Dashboard()
13 |
14 | encoder = JSONEncoder(sort_keys=True, indent=2)
15 | print(encoder.encode(dashboard))
16 | ```
17 |
18 | ### Unmarshalling from JSON
19 |
20 | ```python
21 | import json
22 |
23 | from grafana_foundation_sdk.cog.plugins import register_default_plugins
24 | from grafana_foundation_sdk.models.dashboard import Dashboard as DashboardModel
25 |
26 |
27 | if __name__ == '__main__':
28 | # Required to correctly unmarshal panels and dataqueries
29 | register_default_plugins()
30 |
31 | with open("dashboard.json", "r") as f:
32 | decoded_dashboard = DashboardModel.from_json(json.load(f))
33 | print(decoded_dashboard)
34 | ```
35 | {{ end }}
36 |
--------------------------------------------------------------------------------
/examples/java/custom-query/src/main/java/customquery/Main.java:
--------------------------------------------------------------------------------
1 | package customquery;
2 |
3 | import com.fasterxml.jackson.core.JsonProcessingException;
4 | import com.grafana.foundation.cog.variants.Registry;
5 | import com.grafana.foundation.dashboard.Dashboard;
6 | import com.grafana.foundation.dashboard.DashboardBuilder;
7 | import com.grafana.foundation.timeseries.PanelBuilder;
8 |
9 | public class Main {
10 | public static void main(String[] args) {
11 | Registry.registerDataquery("custom-query", CustomQuery.class);
12 |
13 | Dashboard dashboard = new DashboardBuilder("[Example] Custom query").
14 | uid("example-custom-query").
15 | withPanel(new PanelBuilder().
16 | title("Sample panel").
17 | withTarget(new customquery.CustomQueryBuilder("query-here"))
18 | ).
19 | build();
20 |
21 | try {
22 | System.out.println(dashboard.toJSON());
23 | } catch (JsonProcessingException e) {
24 | e.printStackTrace();
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/examples/terraform/dashboards.tf:
--------------------------------------------------------------------------------
1 | locals {
2 | go_builders = toset([
3 | "${path.module}/../go/custom-panel",
4 | "${path.module}/../go/custom-query",
5 | "${path.module}/../go/grafana-agent-overview",
6 | "${path.module}/../go/linux-node-overview",
7 | "${path.module}/../go/red-method",
8 | ])
9 | }
10 |
11 | // List and run the go dashboard builders. Any of the languages would also work.
12 | // We are using jq to convert the output to a map of strings, as expected by the external data source.
13 | // The dashboard building could be done with a single Go program that outputs the expected TF format,
14 | // but this example does it in multiple Go calls in order to reuse the existing examples.
15 | data "external" "dashboards" {
16 | for_each = local.go_builders
17 | working_dir = each.value
18 | program = ["bash", "-c", <gridPos === null) {
4 | $panelResource->gridPos = new {{ "Dashboard\\GridPos" | fullNamespaceRef }}();
5 | }
6 | // The panel either has no position set, or it is the first panel of the dashboard.
7 | // In that case, we position it on the grid
8 | if ($panelResource->gridPos->x === 0 && $panelResource->gridPos->y === 0) {
9 | $panelResource->gridPos->x = $this->currentX;
10 | $panelResource->gridPos->y = $this->currentY;
11 | }
12 | {{- end }}
13 |
14 | {{- define "post_assignment_Dashboard_withPanel" }}
15 |
16 | // Prepare the coordinates for the next panel
17 | $this->currentX += $panelResource->gridPos->w;
18 | $this->lastPanelHeight = max($this->lastPanelHeight, $panelResource->gridPos->h);
19 |
20 | // Check for grid width overflow?
21 | if ($this->currentX >= 24) {
22 | $this->currentX = 0;
23 | $this->currentY += $this->lastPanelHeight;
24 | $this->lastPanelHeight = 0;
25 | }
26 | {{- end }}
27 |
--------------------------------------------------------------------------------
/examples/typescript/custom-query/src/customQuery.ts:
--------------------------------------------------------------------------------
1 | import { Builder, Dataquery } from '@grafana/grafana-foundation-sdk/cog';
2 |
3 | export interface CustomQuery {
4 | // refId and hide are expected on all queries
5 | refId?: string;
6 | hide?: boolean;
7 |
8 |
9 | // query is specific to the CustomQuery type
10 | query: string;
11 |
12 | // Let cog know that CustomQuery is a Dataquery variant
13 | _implementsDataqueryVariant(): void;
14 | }
15 |
16 | export const defaultCustomQuery = (): CustomQuery => ({
17 | query: "",
18 | _implementsDataqueryVariant() { },
19 | });
20 |
21 | export class CustomQueryBuilder implements Builder {
22 | private readonly internal: CustomQuery;
23 |
24 | constructor(query: string) {
25 | this.internal = defaultCustomQuery();
26 | this.internal.query = query;
27 | }
28 |
29 | build(): CustomQuery {
30 | return this.internal;
31 | }
32 |
33 | refId(refId: string): this {
34 | this.internal.refId = refId;
35 | return this;
36 | }
37 |
38 | hide(hide: boolean): this {
39 | this.internal.hide = hide;
40 | return this;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/.cog/compiler/dataqueries_refid.yaml:
--------------------------------------------------------------------------------
1 | passes:
2 | #################
3 | # DataSourceRef #
4 | #################
5 |
6 | # We have to set refId not required since dashboards v2 schema fails if exists
7 |
8 | - fields_set_not_required:
9 | fields: [
10 | athena.Dataquery.refId,
11 | azuremonitor.AzureMonitorQuery.refId,
12 | bigquery.Dataquery.refId,
13 | cloudwatch.CloudWatchMetricsQuery.refId,
14 | cloudwatch.CloudWatchLogsQuery.refId,
15 | cloudwatch.CloudWatchAnnotationQuery.refId,
16 | datasource.Dataquery.refId,
17 | elasticsearch.Dataquery.refId,
18 | expr.typeMath.refId,
19 | expr.typeReduce.refId,
20 | expr.typeResample.refId,
21 | expr.typeClassicConditions.refId,
22 | expr.typeThreshold.refId,
23 | expr.typeSql.refId,
24 | googlecloudmonitoring.CloudMonitoringQuery.refId,
25 | grafanapyroscope.Dataquery.refId,
26 | loki.Dataquery.refId,
27 | parca.Dataquery.refId,
28 | prometheus.Dataquery.refId,
29 | tempo.TempoQuery.refId,
30 | testdata.dataquery.refId,
31 | ]
32 |
--------------------------------------------------------------------------------
/examples/go/grafana-agent-overview/discovery.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/grafana/grafana-foundation-sdk/go/timeseries"
5 | "github.com/grafana/grafana-foundation-sdk/go/units"
6 | )
7 |
8 | func targetSyncTimeseries() *timeseries.PanelBuilder {
9 | return defaultTimeseries().
10 | Title("Target Sync").
11 | Description("Actual interval to sync the scrape pool.").
12 | Datasource(datasourceRef("$prometheus_datasource")).
13 | Unit(units.Seconds).
14 | WithTarget(prometheusQuery(
15 | `sum(rate(prometheus_target_sync_length_seconds_sum{job=~"$job", instance=~"$instance"}[$__rate_interval])) by (instance, scrape_job)`,
16 | "{{instance}}/{{scrape_job}}",
17 | ))
18 | }
19 |
20 | func targetsTimeseries() *timeseries.PanelBuilder {
21 | return defaultTimeseries().
22 | Title("Targets").
23 | Description("Discovered targets by prometheus service discovery.").
24 | Datasource(datasourceRef("$prometheus_datasource")).
25 | Unit(units.Short).
26 | WithTarget(prometheusQuery(
27 | `sum by (instance) (prometheus_sd_discovered_targets{job=~"$job", instance=~"$instance"})`,
28 | "{{instance}}",
29 | ))
30 | }
31 |
--------------------------------------------------------------------------------
/.cog/templates/typescript/extra/docs/How-To/building-a-dashboard.md:
--------------------------------------------------------------------------------
1 | # Building a dashboard
2 |
3 | ```typescript
4 | import { DashboardBuilder, RowBuilder } from '@grafana/grafana-foundation-sdk/dashboard';
5 | import { DataqueryBuilder } from '@grafana/grafana-foundation-sdk/prometheus';
6 | import { PanelBuilder } from '@grafana/grafana-foundation-sdk/timeseries';
7 |
8 | const builder = new DashboardBuilder('[TEST] Node Exporter / Raspberry')
9 | .uid('test-dashboard-raspberry')
10 | .tags(['generated', 'raspberrypi-node-integration'])
11 |
12 | .refresh('1m')
13 | .time({from: 'now-30m', to: 'now'})
14 | .timezone('browser')
15 |
16 | .withRow(new RowBuilder('Overview'))
17 | .withPanel(
18 | new PanelBuilder()
19 | .title('Network Received')
20 | .unit('bps')
21 | .min(0)
22 | .withTarget(
23 | new DataqueryBuilder()
24 | .expr('rate(node_network_receive_bytes_total{job="integrations/raspberrypi-node", device!="lo"}[$__rate_interval]) * 8')
25 | .legendFormat({{ `"{{ device }}"` }})
26 | )
27 | )
28 | ;
29 |
30 | console.log(JSON.stringify(builder.build(), null, 2));
31 | ```
32 |
--------------------------------------------------------------------------------
/examples/python/custom-query/main.py:
--------------------------------------------------------------------------------
1 | from grafana_foundation_sdk.builders.dashboard import Dashboard
2 | from grafana_foundation_sdk.builders.timeseries import Panel as Timeseries
3 | from grafana_foundation_sdk.cog.encoder import JSONEncoder
4 | from grafana_foundation_sdk.cog.plugins import register_default_plugins
5 | from grafana_foundation_sdk.cog.runtime import register_dataquery_variant
6 |
7 | from src.customquery import custom_query_variant_config, CustomQueryBuilder
8 |
9 |
10 | if __name__ == "__main__":
11 | # Required to correctly unmarshal panels and dataqueries
12 | register_default_plugins()
13 |
14 | # This lets cog know about the newly created query type and how to unmarshal it.
15 | register_dataquery_variant(custom_query_variant_config())
16 |
17 | dashboard = (
18 | Dashboard("[Example] Custom query")
19 | .uid("example-custom-query")
20 | .with_panel(
21 | Timeseries()
22 | .title("Sample panel")
23 | .with_target(CustomQueryBuilder("query here"))
24 | )
25 | ).build()
26 |
27 | print(JSONEncoder(sort_keys=True, indent=2).encode(dashboard))
28 |
--------------------------------------------------------------------------------
/examples/typescript/red-method/src/common.ts:
--------------------------------------------------------------------------------
1 | import * as common from '@grafana/grafana-foundation-sdk/common';
2 | import { PanelBuilder as TimeseriesBuilder } from '@grafana/grafana-foundation-sdk/timeseries';
3 |
4 | export const defaultTimeseries = (): TimeseriesBuilder => {
5 | return new TimeseriesBuilder()
6 | .lineWidth(1)
7 | .fillOpacity(30)
8 | .showPoints(common.VisibilityMode.Never)
9 | .drawStyle(common.GraphDrawStyle.Line)
10 | .gradientMode(common.GraphGradientMode.Opacity)
11 | .spanNulls(false)
12 | .axisBorderShow(false)
13 | .lineInterpolation(common.LineInterpolation.Smooth)
14 | .legend(
15 | new common.VizLegendOptionsBuilder()
16 | .showLegend(true)
17 | .placement(common.LegendPlacement.Bottom)
18 | .displayMode(common.LegendDisplayMode.List)
19 | )
20 | .tooltip(
21 | new common.VizTooltipOptionsBuilder()
22 | .mode(common.TooltipDisplayMode.Multi)
23 | .sort(common.SortOrder.Descending)
24 | )
25 | .thresholdsStyle(
26 | new common.GraphThresholdsStyleConfigBuilder()
27 | .mode(common.GraphThresholdsStyleMode.Off)
28 | );
29 | };
30 |
--------------------------------------------------------------------------------
/.cog/templates/go/overrides/variant_dataquery_field_unmarshal.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "variant_dataquery_field_unmarshal" -}}
2 | {{- $cog := importPkg "cog" }}
3 | if fields["{{ .Field.Name }}"] != nil {
4 | dataqueryTypeHint := ""
5 | {{ range $field := .Object.Type.Struct.Fields }}
6 | {{ if and ($field.Type.IsRef) (eq $field.Type.Ref.ReferredType "DataSourceRef") }}
7 | if resource.{{ $field.Name|formatFieldName }} != nil && resource.{{ $field.Name|formatFieldName }}.Type != nil {
8 | dataqueryTypeHint = *resource.{{ $field.Name|formatFieldName }}.Type
9 | }
10 | {{ end }}
11 | {{ end }}
12 | {{- if .Field.Type.IsArray -}}
13 | {{ .Field.Name }}, err := cog.UnmarshalDataqueryArray(fields["{{ .Field.Name }}"], dataqueryTypeHint)
14 | if err != nil {
15 | return err
16 | }
17 | resource.{{ .Field.Name|formatFieldName }} = {{ .Field.Name }}
18 | {{- else -}}
19 | {{ .Field.Name }}, err := cog.UnmarshalDataquery(fields["{{ .Field.Name }}"], dataqueryTypeHint)
20 | if err != nil {
21 | return err
22 | }
23 | resource.{{ .Field.Name|formatFieldName }} = {{ .Field.Name }}
24 | {{- end -}}
25 | }
26 | {{ end }}
--------------------------------------------------------------------------------
/examples/go/custom-query/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 |
7 | "github.com/grafana/grafana-foundation-sdk/go/cog"
8 | "github.com/grafana/grafana-foundation-sdk/go/cog/plugins"
9 | "github.com/grafana/grafana-foundation-sdk/go/dashboard"
10 | "github.com/grafana/grafana-foundation-sdk/go/timeseries"
11 | )
12 |
13 | func main() {
14 | // Required to correctly unmarshal panels and dataqueries
15 | plugins.RegisterDefaultPlugins()
16 |
17 | // This lets cog know about the newly created query type and how to unmarshal it.
18 | cog.NewRuntime().RegisterDataqueryVariant(CustomQueryVariantConfig())
19 |
20 | builder := dashboard.NewDashboardBuilder("[Example] Custom query").
21 | Uid("example-custom-query").
22 | WithPanel(
23 | timeseries.NewPanelBuilder().
24 | Title("Sample panel").
25 | WithTarget(
26 | NewCustomQueryBuilder("query here"),
27 | ),
28 | )
29 |
30 | sampleDashboard, err := builder.Build()
31 | if err != nil {
32 | panic(err)
33 | }
34 |
35 | dashboardJson, err := json.MarshalIndent(sampleDashboard, "", " ")
36 | if err != nil {
37 | panic(err)
38 | }
39 |
40 | fmt.Println(string(dashboardJson))
41 | }
42 |
--------------------------------------------------------------------------------
/examples/pulumi/go/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 |
6 | linuxNodeOverview "github.com/grafana/grafana-foundation-sdk/examples/go/linux-node-overview/builder"
7 | "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
8 | "github.com/pulumiverse/pulumi-grafana/sdk/go/grafana"
9 | )
10 |
11 | func main() {
12 | pulumi.Run(func(ctx *pulumi.Context) error {
13 | grafanaProvider, err := grafana.NewProvider(ctx, "grafana", &grafana.ProviderArgs{
14 | Auth: pulumi.String("admin:admin"),
15 | Url: pulumi.String("http://localhost:3000"),
16 | })
17 | if err != nil {
18 | return err
19 | }
20 |
21 | sampleDashboard, err := linuxNodeOverview.Build()
22 | if err != nil {
23 | return err
24 | }
25 |
26 | dashboardJson, err := json.MarshalIndent(sampleDashboard, "", " ")
27 | if err != nil {
28 | return err
29 | }
30 |
31 | pulumiDashboard, err := grafana.NewDashboard(ctx, *sampleDashboard.Uid, &grafana.DashboardArgs{
32 | ConfigJson: pulumi.String(dashboardJson),
33 | }, pulumi.Provider(grafanaProvider))
34 | if err != nil {
35 | return err
36 | }
37 |
38 | ctx.Export("dashboardUID", pulumiDashboard.Uid)
39 |
40 | return nil
41 | })
42 | }
43 |
--------------------------------------------------------------------------------
/.cog/templates/php/overrides/variant_dataquery_field_unmarshal.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "variant_dataquery_field_unmarshal" -}}
2 | {{- $dataqueryHint := "\"\"" -}}
3 | {{- range $candidate := .Object.Type.Struct.Fields -}}
4 | {{- if and ($candidate.Type.IsRef) (eq $candidate.Type.Ref.ReferredType "DataSourceRef") -}}
5 | {{- $dataqueryHint = include "dataquery_field_unmarshal_hint" (dict "Candidate" $candidate) -}}
6 | {{- end -}}
7 | {{- end -}}
8 | isset({{ .InputVar }}) ? (function ($in) {
9 | /** @var array{datasource?: array{type?: mixed}} $in */
10 | $hint = {{ $dataqueryHint }};
11 | {{ if .Type.IsArray -}}
12 | /** @var array> $in */
13 | return {{ "Cog\\Runtime"|fullNamespaceRef }}::get()->dataqueriesFromArray($in, $hint);
14 | {{- else }}
15 | /** @var array $in */
16 | return {{ "Cog\\Runtime"|fullNamespaceRef }}::get()->dataqueryFromArray($in, $hint);
17 | {{- end }}
18 | })({{ .InputVar }}) : null
19 | {{- end }}
20 |
21 | {{- define "dataquery_field_unmarshal_hint" -}}
22 | (isset($in["{{ .Candidate.Name }}"], $in["{{ .Candidate.Name }}"]["type"]) && is_string($in["{{ .Candidate.Name }}"]["type"])) ? $in["{{ .Candidate.Name }}"]["type"] : ""
23 | {{- end }}
--------------------------------------------------------------------------------
/examples/python/red-method/src/common.py:
--------------------------------------------------------------------------------
1 | from grafana_foundation_sdk.builders import timeseries, common as common_builder
2 | from grafana_foundation_sdk.models import common
3 |
4 |
5 | def default_timeseries() -> timeseries.Panel:
6 | return (
7 | timeseries.Panel()
8 | .line_width(1)
9 | .fill_opacity(30)
10 | .show_points(common.VisibilityMode.NEVER)
11 | .draw_style(common.GraphDrawStyle.LINE)
12 | .gradient_mode(common.GraphGradientMode.OPACITY)
13 | .span_nulls(False)
14 | .line_interpolation(common.LineInterpolation.SMOOTH)
15 | .legend(
16 | common_builder.VizLegendOptions()
17 | .display_mode(common.LegendDisplayMode.LIST)
18 | .placement(common.LegendPlacement.BOTTOM)
19 | .show_legend(True)
20 | )
21 | .tooltip(
22 | common_builder.VizTooltipOptions()
23 | .mode(common.TooltipDisplayMode.MULTI)
24 | .sort(common.SortOrder.DESCENDING)
25 | )
26 | .thresholds_style(
27 | common_builder.GraphThresholdsStyleConfig().mode(
28 | common.GraphThresholdsStyleMode.OFF
29 | )
30 | )
31 | )
32 |
--------------------------------------------------------------------------------
/scripts/libs/git.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | function git_run() {
4 | local repo_dir="${1}"
5 | shift
6 |
7 | git -C "${repo_dir}" "$@"
8 | }
9 |
10 | function git_has_branch() {
11 | local repo_dir=${1}
12 | shift
13 | local branch=${1}
14 | shift
15 |
16 | # test local branches
17 | local in_local
18 | in_local=$(git_run "${repo_dir}" branch --list "${branch}")
19 | if [ "${in_local}" != "" ]; then
20 | echo "0"
21 | return 0
22 | fi
23 |
24 | # test remote branches
25 | local in_remote
26 | in_remote=$(git_run "${repo_dir}" ls-remote --heads origin "${branch}")
27 | if [ "${in_remote}" != "" ]; then
28 | echo "0"
29 | return 0
30 | fi
31 |
32 | echo "1"
33 | }
34 |
35 | function git_has_changes() {
36 | local repo_dir=${1}
37 | shift
38 |
39 | local changes
40 | changes=$(git_run "${repo_dir}" status --porcelain=v1)
41 | if [ "${changes}" != "" ]; then
42 | echo "0"
43 | return 0
44 | fi
45 |
46 | echo "1"
47 | }
48 |
49 | function git_create_orphan_branch() {
50 | local repo_dir=${1}
51 | shift
52 | local branch=${1}
53 | shift
54 |
55 | git_run "${repo_dir}" checkout --orphan "${branch}"
56 | git_run "${repo_dir}" rm -rf .
57 | }
58 |
--------------------------------------------------------------------------------
/.cog/templates/python/overrides/schema_variant_dataquery.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "schema_variant_dataquery" -}}
2 | {{- $_ := apiDeclareFunction (dict
3 | "pkg" .Schema.Package
4 | "name" "variant_config"
5 | "comments" (listStr
6 | (print "variant_config returns the configuration related to " (.Schema.Metadata.Identifier|lower) " data queries.")
7 | "This configuration describes how to unmarshal it, convert it to code, …"
8 | )
9 | "return" "variants.DataqueryConfig"
10 | ) -}}
11 | {{- $cogruntime := importModule "cogruntime" "..cog" "runtime" -}}
12 | {{- $fromJsonSetup := "" -}}
13 | {{- $fromJson := print (.Schema.EntryPoint|formatObjectName) ".from_json" -}}
14 | {{- if resolvesToDisjunction .Schema.EntryPointType -}}
15 | {{- $code := unmarshalForType .Schema.EntryPointType "data" "entrypoint" -}}
16 | {{- $fromJsonSetup = print $code.Setup "\n " -}}
17 | {{- $fromJson = print "lambda data: " $code.DecodingCall -}}
18 | {{- end -}}
19 |
20 | def variant_config() -> {{ $cogruntime }}.DataqueryConfig:
21 | {{ $fromJsonSetup }}return {{ $cogruntime }}.DataqueryConfig(
22 | identifier="{{ .Schema.Metadata.Identifier }}",
23 | from_json_hook={{ $fromJson }},
24 | )
25 | {{ end }}
26 |
--------------------------------------------------------------------------------
/.cog/veneers/dashboard.python.yaml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/grafana/cog/main/schemas/veneers.json
2 |
3 | language: python
4 |
5 | package: dashboard
6 |
7 | builders:
8 | ##############
9 | # Dashboards #
10 | ##############
11 |
12 | # We don't want these builders at all
13 | - omit: { by_object: DashboardDashboardTime }
14 | - omit: { by_object: ValueMappingResult }
15 |
16 | options:
17 | ##############
18 | # Dashboards #
19 | ##############
20 |
21 | # Time(from, to) instead of time(struct {From string `json:"from"`, To string `json:"to"`}{From: "lala", To: "lala})
22 | - struct_fields_as_arguments:
23 | by_name: Dashboard.time
24 |
25 | ##############
26 | # Panels #
27 | ##############
28 |
29 | # WithOverride(matcher, properties) instead of WithOverride(struct{...})
30 | - struct_fields_as_arguments:
31 | by_name: Panel.withOverride
32 |
33 | ########################
34 | # AnnotationPermission #
35 | ########################
36 |
37 | - rename:
38 | by_name: AnnotationPermission.dashboard
39 | as: dashboard_permissions
40 | - rename:
41 | by_name: AnnotationPermission.organization
42 | as: organization_permissions
43 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | COG_VERSION = v0.0.46
2 | COG_DIR = $(shell go env GOPATH)/bin/cog-$(COG_VERSION)
3 | COG_BIN = $(COG_DIR)/cli
4 |
5 | GRAFANA_VERSION="v12.2.1"
6 | KIND_REGISTRY_VERSION="next"
7 | KIND_REGISTRY_PATH="./kind-registry"
8 |
9 | .PHONY: install-cog
10 | install-cog: echodir $(COG_BIN)
11 |
12 | .PHONY: echodir
13 |
14 | $(COG_BIN):
15 | @echo "Installing Cog version $(COG_VERSION)"
16 | @mkdir -p $(COG_DIR)
17 | GOBIN=$(COG_DIR) go install github.com/grafana/cog/cmd/cli@$(COG_VERSION)
18 | @touch $@
19 |
20 | .PHONY: update-cog
21 | update-app-sdk: ## Update the Grafana App SDK dependency in go.mod
22 | @pwd
23 | go get github.com/grafana/cog@$(COG_VERSION)
24 | go mod tidy
25 |
26 | .PHONY: clone-kind-registry
27 | clone-kind-registry:
28 | ./scripts/fetch-kind-registry.sh
29 |
30 | .PHONY: generate
31 | generate: install-cog clone-kind-registry
32 | bash -c 'source ./scripts/versions.sh && \
33 | $(COG_BIN) generate --config .cog/config.yaml \
34 | --parameters "output_dir=%l,kind_registry_path=$(KIND_REGISTRY_PATH),kind_registry_version=$(KIND_REGISTRY_VERSION),grafana_version=$(GRAFANA_VERSION),release_branch=main,all_grafana_versions=$$ALL_GRAFANA_VERSIONS,cog_version=$$COG_VERSION",repository_templates_dir=""'
35 |
--------------------------------------------------------------------------------
/.cog/templates/php/overrides/object_dashboardv2beta1_DataQueryKind_custom_unmarshal.tmpl.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "object_dashboardv2beta1_DataQueryKind_custom_unmarshal" }}
2 | /**
3 | * @param array $inputData
4 | */
5 | public static function fromArray(array $inputData): self
6 | {
7 | /** @var {{ typeShape .Object.Type }} $inputData */
8 | $data = $inputData;
9 | return new self(
10 | {{- range $field := .Object.Type.Struct.Fields }}
11 | {{ if eq $field.Name "spec" -}}
12 | {{ $field.Name }}: {{ template "dashboardv2beta1_DataQueryKind_spec_unmarshal" }}
13 | {{- else if or $field.Type.IsConcreteScalar $field.Type.IsConstantRef }}
14 | {{ continue }}
15 | {{- else -}}
16 | {{ $field.Name }}: {{ unmarshalForType $field.Type (print "$data[\"" $field.Name "\"]") }}
17 | {{- end -}},
18 | {{- end }}
19 | );
20 | }
21 | {{- end }}
22 |
23 | {{- define "dashboardv2beta1_DataQueryKind_spec_unmarshal" -}}
24 | isset($data['spec']) ? (function($input) {
25 | /** @var array $spec */
26 | $spec = $input['spec'];
27 | return \Grafana\Foundation\Cog\Runtime::get()->dataqueryFromArray($spec, $input['group'] ?? '');
28 | })($data) : null
29 | {{- end }}
30 |
--------------------------------------------------------------------------------
/.cog/veneers/heatmap.common.yaml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/grafana/cog/main/schemas/veneers.json
2 |
3 | language: all
4 |
5 | package: heatmap
6 |
7 | builders: ~
8 |
9 | options:
10 | # ExemplarsColor(color: string) instead of Exemplars(exemplarsConfig: ExemplarConfig)
11 | # ExemplarConfig only includes (color: string) field.
12 | - struct_fields_as_arguments:
13 | by_builder: Panel.exemplars
14 | - rename:
15 | by_builder: Panel.exemplars
16 | as: exemplarsColor
17 |
18 | # ShowLegend/HideLegends instead of Legend(show: bool)
19 | - struct_fields_as_arguments:
20 | by_builder: Panel.legend
21 | - unfold_boolean:
22 | by_builder: Panel.legend
23 | true_as: showLegend
24 | false_as: hideLegend
25 |
26 | # Tooltip(show: bool, yHistogram: bool) split into:
27 | # - ShowTooltip/HideTooltip
28 | # - ShowYHistogram/HideYHistogram
29 | - struct_fields_as_options:
30 | by_builder: Panel.tooltip
31 | - unfold_boolean:
32 | by_builder: Panel.show
33 | true_as: showTooltip
34 | false_as: hideTooltip
35 | - unfold_boolean:
36 | by_builder: Panel.yHistogram
37 | true_as: showYHistogram
38 | false_as: hideYHistogram
39 |
--------------------------------------------------------------------------------
/examples/typescript/grafana-agent-overview/src/discovery.ts:
--------------------------------------------------------------------------------
1 | import * as timeseries from "@grafana/grafana-foundation-sdk/timeseries";
2 | import * as units from "@grafana/grafana-foundation-sdk/units";
3 | import { defaultTimeseries, prometheusQuery } from "./common";
4 |
5 | export const targetSyncTimeseries = (): timeseries.PanelBuilder => {
6 | return defaultTimeseries()
7 | .title("Target Sync")
8 | .description("Actual interval to sync the scrape pool.")
9 | .datasource({ uid: "$prometheus_datasource" })
10 | .unit(units.Seconds)
11 | .withTarget(prometheusQuery(
12 | 'sum(rate(prometheus_target_sync_length_seconds_sum{job=~"$job", instance=~"$instance"}[$__rate_interval])) by (instance, scrape_job)',
13 | "{{instance}}/{{scrape_job}}"
14 | ));
15 | };
16 |
17 | export const targetsTimeseries = (): timeseries.PanelBuilder => {
18 | return defaultTimeseries()
19 | .title("Targets")
20 | .description("Discovered targets by prometheus service discovery.")
21 | .datasource({ uid: "$prometheus_datasource" })
22 | .unit(units.Short)
23 | .withTarget(prometheusQuery(
24 | 'sum by (instance) (prometheus_sd_discovered_targets{job=~"$job", instance=~"$instance"})',
25 | "{{instance}}"
26 | ));
27 | };
28 |
--------------------------------------------------------------------------------
/.cog/templates/php/extra/docs/How-To/building-a-dashboard.md:
--------------------------------------------------------------------------------
1 | # Building a dashboard
2 |
3 | ```php
4 | uid('generated-from-php')
16 | ->tags(['generated', 'from', 'php'])
17 | ->refresh('1m')
18 | ->time('now-30m', 'now')
19 | ->timezone(Common\Constants::TIME_ZONE_BROWSER)
20 | ->withRow(new RowBuilder('Overview'))
21 | ->withPanel(
22 | (new Timeseries\PanelBuilder())
23 | ->title('Network received')
24 | ->unit('bps')
25 | ->min(0)
26 | ->withTarget(
27 | (new Prometheus\DataqueryBuilder())
28 | ->expr('rate(node_network_receive_bytes_total{job="integrations/raspberrypi-node", device!="lo"}[$__rate_interval]) * 8')
29 | ->legendFormat({{ `'{{ device }}'` }})
30 | )
31 | )
32 | ;
33 |
34 | echo(json_encode($builder->build(), JSON_PRETTY_PRINT).PHP_EOL);
35 | ```
36 |
--------------------------------------------------------------------------------
/.cog/templates/typescript/overrides/api_reference_builder_dashboard_Dashboard_extra.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "api_reference_builder_dashboard_Dashboard_extra" -}}
2 | ## Examples
3 |
4 | ### Building a dashboard
5 |
6 | ```typescript
7 | import { DashboardBuilder, RowBuilder } from '@grafana/grafana-foundation-sdk/dashboard';
8 | import { DataqueryBuilder } from '@grafana/grafana-foundation-sdk/prometheus';
9 | import { PanelBuilder } from '@grafana/grafana-foundation-sdk/timeseries';
10 |
11 | const builder = new DashboardBuilder('[TEST] Node Exporter / Raspberry')
12 | .uid('test-dashboard-raspberry')
13 | .tags(['generated', 'raspberrypi-node-integration'])
14 |
15 | .refresh('1m')
16 | .time({from: 'now-30m', to: 'now'})
17 | .timezone('browser')
18 |
19 | .withRow(new RowBuilder('Overview'))
20 | .withPanel(
21 | new PanelBuilder()
22 | .title('Network Received')
23 | .unit('bps')
24 | .min(0)
25 | .withTarget(
26 | new DataqueryBuilder()
27 | .expr('rate(node_network_receive_bytes_total{job="integrations/raspberrypi-node", device!="lo"}[$__rate_interval]) * 8')
28 | .legendFormat({{ `"{{ device }}"` }})
29 | )
30 | )
31 | ;
32 |
33 | console.log(JSON.stringify(builder.build(), null, 2));
34 | ```
35 | {{ end }}
36 |
--------------------------------------------------------------------------------
/.cog/templates/java/extra/src/main/java/com/grafana/foundation/cog/variants/PanelConfig.java:
--------------------------------------------------------------------------------
1 | package com.grafana.foundation.cog.variants;
2 | {{ if .Data.Config.GenerateConverters }}
3 | import com.grafana.foundation.dashboard.Panel;
4 | import com.grafana.foundation.cog.Converter;
5 | {{- end }}
6 |
7 | public class PanelConfig {
8 | private final Class> optionsClass;
9 | private final Class> fieldConfigClass;
10 | {{- if .Data.Config.GenerateConverters }}
11 | private final Converter converter;
12 | {{- end }}
13 |
14 | public PanelConfig(Class> optionsClass, Class> fieldConfigClass{{ if .Data.Config.GenerateConverters }}, Converter converter{{ end }}) {
15 | this.optionsClass = optionsClass;
16 | this.fieldConfigClass = fieldConfigClass;
17 | {{ if .Data.Config.GenerateConverters -}}
18 | this.converter = converter;
19 | {{- end }}
20 | }
21 |
22 | public Class> getOptionsClass() {
23 | return optionsClass;
24 | }
25 |
26 | public Class> getFieldConfigClass() {
27 | return fieldConfigClass;
28 | }
29 |
30 | {{- if .Data.Config.GenerateConverters }}
31 | public Converter getConverter() {
32 | return converter;
33 | }
34 | {{- end }}
35 | }
36 |
--------------------------------------------------------------------------------
/.cog/templates/go/overrides/object_dashboard_Panel_field_fieldConfig_custom_strict_unmarshal.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "object_dashboard_Panel_field_fieldConfig_custom_strict_unmarshal" -}}
2 | {{- /* Non-standard unmarshalling to parse the correct FieldConfig struct based on the panel type */}}
3 | if err := json.Unmarshal(fields["fieldConfig"], &resource.FieldConfig); err != nil {
4 | errs = append(errs, cog.MakeBuildErrors("fieldConfig", err)...)
5 | }
6 |
7 | variantCfg, found := cog.ConfigForPanelcfgVariant(resource.Type)
8 | if found && variantCfg.StrictFieldConfigUnmarshaler != nil {
9 | fakeFieldConfigSource := struct {
10 | Defaults struct {
11 | Custom json.RawMessage `json:"custom"`
12 | } `json:"defaults"`
13 | }{}
14 | if err := json.Unmarshal(fields["fieldConfig"], &fakeFieldConfigSource); err != nil {
15 | errs = append(errs, cog.MakeBuildErrors("fieldConfig", err)...)
16 | }
17 |
18 | if fakeFieldConfigSource.Defaults.Custom != nil {
19 | customFieldConfig, err := variantCfg.StrictFieldConfigUnmarshaler(fakeFieldConfigSource.Defaults.Custom)
20 | if err != nil {
21 | errs = append(errs, cog.MakeBuildErrors("fieldConfig.defaults.custom", err)...)
22 | } else {
23 | resource.FieldConfig.Defaults.Custom = customFieldConfig
24 | }
25 | }
26 | }
27 |
28 | {{ end }}
29 |
--------------------------------------------------------------------------------
/examples/java/custom-panel/src/main/java/custompanel/CustomPanelBuilder.java:
--------------------------------------------------------------------------------
1 | package custompanel;
2 |
3 | import com.grafana.foundation.cog.Builder;
4 | import com.grafana.foundation.cog.variants.Dataquery;
5 | import com.grafana.foundation.dashboard.Panel;
6 |
7 | public class CustomPanelBuilder implements Builder {
8 | private final Panel internal;
9 |
10 | public CustomPanelBuilder() {
11 | this.internal = new Panel();
12 | this.internal.type = "custom-panel";
13 | }
14 |
15 | public CustomPanelBuilder title(String title) {
16 | this.internal.title = title;
17 | return this;
18 | }
19 |
20 | public CustomPanelBuilder withTarget(Builder target) {
21 | this.internal.targets.add(target.build());
22 | return this;
23 | }
24 |
25 | public CustomPanelBuilder makeItBeautiful() {
26 | if (this.internal.options == null) {
27 | this.internal.options = new CustomPanelOptions();
28 | }
29 |
30 | CustomPanelOptions options = (CustomPanelOptions) this.internal.options;
31 | options.setMakeItBeautiful(true);
32 |
33 | this.internal.options = options;
34 | return this;
35 | }
36 |
37 | @Override
38 | public Panel build() {
39 | return internal;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/examples/java/red-method/src/main/java/red/Common.java:
--------------------------------------------------------------------------------
1 | package red;
2 |
3 | import com.grafana.foundation.common.*;
4 | import com.grafana.foundation.timeseries.PanelBuilder;
5 |
6 | public class Common {
7 |
8 | static PanelBuilder defaultTimeSeries() {
9 | return new PanelBuilder().
10 | lineWidth(1.0).
11 | fillOpacity(30.0).
12 | showPoints(VisibilityMode.NEVER).
13 | drawStyle(GraphDrawStyle.LINE).
14 | gradientMode(GraphGradientMode.OPACITY).
15 | spanNulls(BoolOrFloat64.createBool(false)).
16 | axisBorderShow(false).
17 | lineInterpolation(LineInterpolation.SMOOTH).
18 | legend(new VizLegendOptionsBuilder().
19 | displayMode(LegendDisplayMode.LIST).
20 | placement(LegendPlacement.BOTTOM).
21 | showLegend(true)
22 | ).
23 | tooltip(new VizTooltipOptionsBuilder().
24 | mode(TooltipDisplayMode.MULTI).
25 | sort(SortOrder.DESCENDING)
26 | ).
27 | thresholdsStyle(new GraphThresholdsStyleConfigBuilder().
28 | mode(GraphThresholdsStyleMode.OFF)
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/.cog/veneers/dashboardv2/dashboardv2beta1.go.yaml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/grafana/cog/main/schemas/veneers.json
2 |
3 | language: go
4 |
5 | package: dashboardv2beta1
6 |
7 | options:
8 | #############
9 | # Variables #
10 | #############
11 |
12 | - disjunction_as_options:
13 | by_builder: Dashboard.variable
14 | - rename:
15 | by_builder: Dashboard.QueryVariableKind
16 | as: queryVariable
17 | - rename:
18 | by_builder: Dashboard.TextVariableKind
19 | as: textVariable
20 | - rename:
21 | by_builder: Dashboard.ConstantVariableKind
22 | as: constantVariable
23 | - rename:
24 | by_builder: Dashboard.DatasourceVariableKind
25 | as: datasourceVariable
26 | - rename:
27 | by_builder: Dashboard.IntervalVariableKind
28 | as: intervalVariable
29 | - rename:
30 | by_builder: Dashboard.CustomVariableKind
31 | as: customVariable
32 | - rename:
33 | by_builder: Dashboard.GroupByVariableKind
34 | as: groupByVariable
35 | - rename:
36 | by_builder: Dashboard.AdhocVariableKind
37 | as: adhocVariable
38 |
39 | ##########
40 | # Panels #
41 | ##########
42 |
43 | # WithOverride(matcher, properties) instead of WithOverride(struct{...})
44 | - struct_fields_as_arguments:
45 | by_name: VizConfigKind.override
46 |
--------------------------------------------------------------------------------
/.cog/templates/php/overrides/api_reference_builder_dashboard_Dashboard_extra.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "api_reference_builder_dashboard_Dashboard_extra" -}}
2 | ## Examples
3 |
4 | ### Building a dashboard
5 |
6 | ```php
7 | use Grafana\Foundation\Common;
8 | use Grafana\Foundation\Dashboard\DashboardBuilder;
9 | use Grafana\Foundation\Dashboard\RowBuilder;
10 | use Grafana\Foundation\Prometheus;
11 | use Grafana\Foundation\Timeseries;
12 |
13 | require_once __DIR__.'/vendor/autoload.php';
14 |
15 | $builder = (new DashboardBuilder(title: 'Sample dashboard'))
16 | ->uid('generated-from-php')
17 | ->tags(['generated', 'from', 'php'])
18 | ->refresh('1m')
19 | ->time('now-30m', 'now')
20 | ->timezone(Common\Constants::TIME_ZONE_BROWSER)
21 | ->withRow(new RowBuilder('Overview'))
22 | ->withPanel(
23 | (new Timeseries\PanelBuilder())
24 | ->title('Network received')
25 | ->unit('bps')
26 | ->min(0)
27 | ->withTarget(
28 | (new Prometheus\DataqueryBuilder())
29 | ->expr('rate(node_network_receive_bytes_total{job="integrations/raspberrypi-node", device!="lo"}[$__rate_interval]) * 8')
30 | ->legendFormat({{ `'{{ device }}'` }})
31 | )
32 | )
33 | ;
34 |
35 | echo(json_encode($builder->build(), JSON_PRETTY_PRINT).PHP_EOL);
36 | ```
37 | {{ end }}
38 |
--------------------------------------------------------------------------------
/.cog/templates/python/overrides/api_reference_builder_dashboard_Dashboard_extra.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "api_reference_builder_dashboard_Dashboard_extra" -}}
2 | ## Examples
3 |
4 | ### Building a dashboard
5 |
6 | ```python
7 | from grafana_foundation_sdk.builders.dashboard import Dashboard, Row
8 | from grafana_foundation_sdk.builders.prometheus import Dataquery as PrometheusQuery
9 | from grafana_foundation_sdk.builders.timeseries import Panel as Timeseries
10 | from grafana_foundation_sdk.models.common import TimeZoneBrowser
11 |
12 | def build_dashboard() -> Dashboard:
13 | return (
14 | Dashboard("[TEST] Node Exporter / Raspberry")
15 | .uid("test-dashboard-raspberry")
16 | .tags(["generated", "raspberrypi-node-integration"])
17 |
18 | .refresh("1m")
19 | .time("now-30m", "now")
20 | .timezone(TimeZoneBrowser)
21 |
22 | .with_row(Row("Overview"))
23 | .with_panel(
24 | Timeseries()
25 | .title("Network Received")
26 | .unit("bps")
27 | .min_val(0)
28 | .with_target(
29 | PrometheusQuery()
30 | .expr('rate(node_network_receive_bytes_total{job="integrations/raspberrypi-node", device!="lo"}[$__rate_interval]) * 8')
31 | .legend_format({{ `"{{ device }}"` }})
32 | )
33 | )
34 | )
35 | ```
36 | {{ end }}
37 |
--------------------------------------------------------------------------------
/.cog/repository_templates/python/.github/workflows/python-release.tmpl:
--------------------------------------------------------------------------------
1 | name: Python Release
2 | on:
3 | push:
4 | branches:
5 | - '{{ .Extra.ReleaseBranch|replace "+" "\\+" }}'
6 |
7 | env:
8 | PYTHON_VERSION: '3.12'
9 |
10 | jobs:
11 | release:
12 | name: Build and release
13 | runs-on: ubuntu-latest
14 |
15 | permissions:
16 | contents: read
17 | id-token: write # mandatory for trusted publishing
18 |
19 | environment:
20 | name: pypi
21 | url: https://pypi.org/p/grafana_foundation_sdk
22 |
23 | defaults:
24 | run:
25 | shell: bash
26 | working-directory: ./python
27 |
28 | steps:
29 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
30 | with:
31 | persist-credentials: false
32 |
33 | - name: Setup Python {{ `${{ env.PYTHON_VERSION }}` }}
34 | uses: actions/setup-python@v5
35 | with:
36 | python-version: {{ `${{ env.PYTHON_VERSION }}` }}
37 |
38 | - name: Install pypa/build
39 | run: python3 -m pip install build --user
40 |
41 | - name: Build a binary wheel and a source tarball
42 | run: python3 -m build
43 |
44 | - name: Publish distribution 📦 to PyPI
45 | uses: pypa/gh-action-pypi-publish@release/v1
46 | with:
47 | packages-dir: python/dist/
48 | attestations: false
49 |
--------------------------------------------------------------------------------
/examples/go/red-method/common.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/grafana/grafana-foundation-sdk/go/cog"
5 | "github.com/grafana/grafana-foundation-sdk/go/common"
6 | "github.com/grafana/grafana-foundation-sdk/go/dashboard"
7 | "github.com/grafana/grafana-foundation-sdk/go/timeseries"
8 | )
9 |
10 | func grafanaDatasourceRef() dashboard.DataSourceRef {
11 | return dashboard.DataSourceRef{
12 | Uid: cog.ToPtr("grafana"),
13 | Type: cog.ToPtr("grafana"),
14 | }
15 | }
16 |
17 | func defaultTimeseries() *timeseries.PanelBuilder {
18 | return timeseries.NewPanelBuilder().
19 | LineWidth(1).
20 | FillOpacity(30).
21 | ShowPoints(common.VisibilityModeNever).
22 | DrawStyle(common.GraphDrawStyleLine).
23 | GradientMode(common.GraphGradientModeOpacity).
24 | SpanNulls(common.BoolOrFloat64{Bool: cog.ToPtr[bool](false)}).
25 | AxisBorderShow(false).
26 | LineInterpolation(common.LineInterpolationSmooth).
27 | Legend(common.NewVizLegendOptionsBuilder().
28 | DisplayMode(common.LegendDisplayModeList).
29 | Placement(common.LegendPlacementBottom).
30 | ShowLegend(true),
31 | ).
32 | Tooltip(common.NewVizTooltipOptionsBuilder().
33 | Mode(common.TooltipDisplayModeMulti).
34 | Sort(common.SortOrderDescending),
35 | ).
36 | ThresholdsStyle(
37 | common.NewGraphThresholdsStyleConfigBuilder().
38 | Mode(common.GraphThresholdsStyleModeOff),
39 | )
40 | }
41 |
--------------------------------------------------------------------------------
/.cog/templates/php/extra/src/Cog/PanelcfgConfig.php:
--------------------------------------------------------------------------------
1 | ): object)|null
20 | */
21 | public $optionsFromArray;
22 |
23 | /**
24 | * @var (callable(array): object)|null
25 | */
26 | public $fieldConfigFromArray;
27 |
28 | /**
29 | * @param (callable({{ $convertReturn }}): string)|null $convert
30 | * @param (callable(array): object)|null $optionsFromArray
31 | * @param (callable(array): object)|null $fieldConfigFromArray
32 | */
33 | public function __construct(string $identifier, ?callable $convert = null, ?callable $optionsFromArray = null, ?callable $fieldConfigFromArray = null)
34 | {
35 | $this->identifier = $identifier;
36 | $this->convert = $convert;
37 | $this->optionsFromArray = $optionsFromArray;
38 | $this->fieldConfigFromArray = $fieldConfigFromArray;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/.cog/templates/python/extra/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = ["hatchling"]
3 | build-backend = "hatchling.build"
4 |
5 | [project]
6 | name = "grafana_foundation_sdk"
7 | description = "A set of tools, types and libraries for building and manipulating Grafana objects."
8 | keywords = [
9 | "observability",
10 | "sdk",
11 | "grafana",
12 | "logs",
13 | "traces",
14 | "metrics"
15 | ]
16 | version = "{{ if eq .Extra.GrafanaVersion "next" }}{{ .Extra.BuildTimestamp }}{{ else }}{{ .Extra.BuildTimestamp }}!{{ .Extra.GrafanaVersion|registryToSemver }}{{ end }}"
17 | dependencies = []
18 | requires-python = ">=3.11"
19 | classifiers = [
20 | "Development Status :: 3 - Alpha",
21 | "Intended Audience :: Developers",
22 | "Intended Audience :: System Administrators",
23 | "License :: OSI Approved :: Apache Software License",
24 | "Operating System :: OS Independent",
25 | "Programming Language :: Python :: 3.11",
26 | "Programming Language :: Python :: 3.12",
27 | "Topic :: Software Development :: Libraries",
28 | "Topic :: System :: Monitoring",
29 | ]
30 | readme = "README.md"
31 | authors = [
32 | { name = "Grafana Labs" },
33 | ]
34 |
35 | [project.urls]
36 | Homepage = "https://github.com/grafana/grafana-foundation-sdk"
37 | Repository = "https://github.com/grafana/grafana-foundation-sdk.git"
38 | Issues = "https://github.com/grafana/grafana-foundation-sdk/issues"
39 |
--------------------------------------------------------------------------------
/.cog/compiler/dashboardv2beta1.yaml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/grafana/cog/main/schemas/compiler_passes.json
2 |
3 | passes:
4 | ######################
5 | # Dashboard v2beta1 #
6 | ######################
7 |
8 | # Some future-proofing
9 | - constant_to_enum:
10 | objects:
11 | - dashboardv2beta1.RepeatMode
12 |
13 | # To make our composability veneers shenanigans work
14 | - retype_field:
15 | field: dashboardv2beta1.VizConfigSpec.options
16 | as:
17 | kind: scalar
18 | scalar: { scalar_kind: any }
19 | nullable: true
20 |
21 | - retype_field:
22 | field: dashboardv2beta1.FieldConfig.custom
23 | as:
24 | kind: scalar
25 | scalar: { scalar_kind: any }
26 | nullable: true
27 |
28 | - retype_field:
29 | field: dashboardv2beta1.DataQueryKind.spec
30 | as:
31 | kind: scalar
32 | scalar: { scalar_kind: any }
33 | nullable: true
34 |
35 | # Is this object meant for frontend usage only?
36 | - omit:
37 | objects: [ dashboardv2beta1.VariableCustomFormatterFn ]
38 |
39 | - retype_field:
40 | field: dashboardv2beta1.CustomVariableValue.formatter
41 | as:
42 | kind: scalar
43 | scalar: { scalar_kind: string }
44 | nullable: true
45 |
46 | - rename_object:
47 | from: dashboardv2beta1.DashboardSpec
48 | to: Dashboard
49 |
--------------------------------------------------------------------------------
/.cog/veneers/dashboardv2/dashboardv2beta1.java.yaml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/grafana/cog/main/schemas/veneers.json
2 |
3 | language: java
4 |
5 | package: dashboardv2beta1
6 |
7 | options:
8 | #############
9 | # Variables #
10 | #############
11 |
12 | - disjunction_as_options:
13 | by_builder: Dashboard.variable
14 | - rename:
15 | by_builder: Dashboard.queryVariableKind
16 | as: queryVariable
17 | - rename:
18 | by_builder: Dashboard.textVariableKind
19 | as: textVariable
20 | - rename:
21 | by_builder: Dashboard.constantVariableKind
22 | as: constantVariable
23 | - rename:
24 | by_builder: Dashboard.datasourceVariableKind
25 | as: datasourceVariable
26 | - rename:
27 | by_builder: Dashboard.intervalVariableKind
28 | as: intervalVariable
29 | - rename:
30 | by_builder: Dashboard.customVariableKind
31 | as: customVariable
32 | - rename:
33 | by_builder: Dashboard.groupByVariableKind
34 | as: groupByVariable
35 | - rename:
36 | by_builder: Dashboard.adhocVariableKind
37 | as: adhocVariable
38 |
39 | - disjunction_as_options:
40 | by_builder: QueryVariable.query
41 |
42 | ##########
43 | # Panels #
44 | ##########
45 |
46 | # WithOverride(matcher, properties) instead of WithOverride(struct{...})
47 | - struct_fields_as_arguments:
48 | by_name: VizConfigKind.override
49 |
--------------------------------------------------------------------------------
/.cog/templates/go/overrides/object_dashboardv2beta1_DataQueryKind_custom_unmarshal.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "object_dashboardv2beta1_DataQueryKind_custom_unmarshal" }}
2 | {{- $fmt := importStdPkg "fmt" -}}
3 | {{- $json := importStdPkg "encoding/json" -}}
4 | func (resource *{{ .Object.Name|upperCamelCase }}) UnmarshalJSON(raw []byte) error {
5 | if raw == nil {
6 | return nil
7 | }
8 |
9 | fields := make(map[string]json.RawMessage)
10 | if err := json.Unmarshal(raw, &fields); err != nil {
11 | return err
12 | }
13 | {{- range $field := .Object.Type.Struct.Fields }}
14 | {{- if eq $field.Name "spec" }}
15 | {{ continue }}
16 | {{- else }}
17 | if fields["{{ $field.Name }}"] != nil {
18 | if err := json.Unmarshal(fields["{{ $field.Name }}"], &resource.{{ $field.Name|upperCamelCase }}); err != nil {
19 | return fmt.Errorf("error decoding field '{{ $field.Name }}': %w", err)
20 | }
21 | }
22 | {{- end }}
23 | {{- end }}
24 |
25 | {{ template "unmarshal_dashboardv2beta1_DataQueryKind_spec" }}
26 |
27 | return nil
28 | }
29 |
30 | {{ end }}
31 |
32 | {{- define "unmarshal_dashboardv2beta1_DataQueryKind_spec" -}}
33 | {{- $fmt := importStdPkg "fmt" -}}
34 | {{- $cog := importPkg "cog" }}
35 | if fields["spec"] != nil {
36 | dataquery, err := cog.UnmarshalDataquery(fields["spec"], resource.Group)
37 | if err != nil {
38 | return fmt.Errorf("error decoding field 'spec': %w", err)
39 | }
40 | resource.Spec = dataquery
41 | }
42 | {{- end -}}
43 |
--------------------------------------------------------------------------------
/.cog/repository_templates/typescript/.github/workflows/typescript-release.tmpl:
--------------------------------------------------------------------------------
1 | name: TypeScript Release
2 | on:
3 | push:
4 | branches:
5 | - '{{ .Extra.ReleaseBranch|replace "+" "\\+" }}'
6 |
7 | env:
8 | NODE_VERSION: '20'
9 |
10 | jobs:
11 | release:
12 | name: Build and release
13 | runs-on: ubuntu-latest
14 |
15 | permissions:
16 | contents: read
17 | id-token: write
18 |
19 | environment:
20 | name: typescript
21 | url: https://www.npmjs.com/package/@grafana/grafana-foundation-sdk
22 |
23 | defaults:
24 | run:
25 | shell: bash
26 | working-directory: ./typescript
27 |
28 | steps:
29 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
30 | with:
31 | persist-credentials: false
32 |
33 | - name: Use Node.js {{ `${{ env.NODE_VERSION }}` }}
34 | uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
35 | with:
36 | node-version: {{ `${{ env.NODE_VERSION }}` }}
37 | scope: '@grafana'
38 | registry-url: 'https://registry.npmjs.org'
39 |
40 | - name: Ensure npm latest version
41 | run: npm install -g npm@latest
42 |
43 | - name: Install dependencies
44 | run: npm install
45 |
46 | - name: Build
47 | run: npm run build
48 |
49 | - name: Publish to NPM registry
50 | run: npm publish --access public --tag {{ .Extra.TypescriptTag }}
51 |
--------------------------------------------------------------------------------
/.cog/templates/php/extra/src/Cog/DataqueryConfig.php:
--------------------------------------------------------------------------------
1 | ): Dataquery
11 | */
12 | public $fromArray;
13 |
14 | /**
15 | * @var (callable(Dataquery): string)|null
16 | */
17 | public $convert;
18 |
19 | {{- if objectExists "dashboardv2beta1" "DataQueryKind" }}
20 | /**
21 | * @var (callable(\Grafana\Foundation\Dashboardv2beta1\DataQueryKind): string)|null
22 | */
23 | public $convertv2;
24 | {{- end }}
25 |
26 | /**
27 | * @param callable(array): Dataquery $fromArray
28 | * @param (callable(Dataquery): string)|null $convert
29 | {{- if objectExists "dashboardv2beta1" "DataQueryKind" }}
30 | * @param (callable(\Grafana\Foundation\Dashboardv2beta1\DataQueryKind): string)|null $convertv2
31 | {{- end }}
32 | */
33 | public function __construct(string $identifier, callable $fromArray, ?callable $convert = null{{ if objectExists "dashboardv2beta1" "DataQueryKind" }}, ?callable $convertv2 = null{{ end }})
34 | {
35 | $this->identifier = $identifier;
36 | $this->fromArray = $fromArray;
37 | $this->convert = $convert;
38 | {{- if objectExists "dashboardv2beta1" "DataQueryKind" }}
39 | $this->convertv2 = $convertv2;
40 | {{- end }}
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/examples/java/linux-node-overview/src/main/java/linuxnode/linux/Network.java:
--------------------------------------------------------------------------------
1 | package linuxnode.linux;
2 |
3 | import com.grafana.foundation.timeseries.PanelBuilder;
4 | import com.grafana.foundation.units.Constants;
5 |
6 | public class Network {
7 |
8 | public static PanelBuilder networkReceivedTimeseries() {
9 | return Common.defaultTimeSeries().
10 | title("Network Received").
11 | description("Network received (bits/s)").
12 | min(0.0).
13 | unit(Constants.BitsPerSecondSI).
14 | fillOpacity(0.0).
15 | withTarget(
16 | Common.basicPrometheusQuery("rate(node_network_receive_bytes_total{job=\"integrations/raspberrypi-node\", instance=\"$instance\", device!=\"lo\"}[$__rate_interval]) * 8", "{{ device }}")
17 | );
18 | }
19 | public static PanelBuilder networkTransmittedTimeseries() {
20 | return Common.defaultTimeSeries().
21 | title("Network Transmitted").
22 | description("Network transmitted (bits/s)").
23 | min(0.0).
24 | unit(Constants.BitsPerSecondSI).
25 | fillOpacity(0.0).
26 | withTarget(
27 | Common.basicPrometheusQuery("rate(node_network_transmit_bytes_total{job=\"integrations/raspberrypi-node\", instance=\"$instance\", device!=\"lo\"}[$__rate_interval]) * 8", "{{ device }}")
28 | );
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/examples/python/grafana-agent-overview/src/discovery.py:
--------------------------------------------------------------------------------
1 | from grafana_foundation_sdk.builders import timeseries
2 | from grafana_foundation_sdk.models.dashboard import DataSourceRef
3 | from grafana_foundation_sdk.models import units
4 |
5 | from .common import prometheus_query, default_timeseries
6 |
7 |
8 | def target_sync_timeseries() -> timeseries.Panel:
9 | return (
10 | default_timeseries()
11 | .title("Target Sync")
12 | .description("Actual interval to sync the scrape pool.")
13 | .datasource(DataSourceRef(uid="$prometheus_datasource"))
14 | .unit(units.Seconds)
15 | .with_target(
16 | prometheus_query(
17 | query='sum(rate(prometheus_target_sync_length_seconds_sum{job=~"$job", instance=~"$instance"}[$__rate_interval])) by (instance, scrape_job)',
18 | legend="{{instance}}/{{scrape_job}}",
19 | )
20 | )
21 | )
22 |
23 |
24 | def target_timeseries() -> timeseries.Panel:
25 | return (
26 | default_timeseries()
27 | .title("Targets")
28 | .description("Discovered targets by prometheus service discovery.")
29 | .datasource(DataSourceRef(uid="$prometheus_datasource"))
30 | .unit(units.Short)
31 | .with_target(
32 | prometheus_query(
33 | query='sum by (instance) (prometheus_sd_discovered_targets{job=~"$job", instance=~"$instance"})',
34 | legend="{{instance}}",
35 | )
36 | )
37 | )
38 |
--------------------------------------------------------------------------------
/examples/typescript/grafana-agent-overview/src/overview.ts:
--------------------------------------------------------------------------------
1 | import * as common from '@grafana/grafana-foundation-sdk/common';
2 | import * as table from "@grafana/grafana-foundation-sdk/table";
3 | import { tablePrometheusQuery } from "./common";
4 |
5 | export const runningInstancesTable = (): table.PanelBuilder => {
6 | return new table.PanelBuilder()
7 | .title("Running Instances")
8 | .description("General statistics of running grafana agent instances.")
9 | .height(7)
10 | .span(24)
11 | .footer(
12 | new common.TableFooterOptionsBuilder()
13 | .countRows(false)
14 | .reducer(["sum"])
15 | )
16 | .datasource({ uid: "$prometheus_datasource" })
17 | .withTarget(
18 | tablePrometheusQuery('count by (instance, version) (agent_build_info{job=~"$job", instance=~"$instance"})', "A"),
19 | )
20 | .withTarget(
21 | tablePrometheusQuery('max by (instance) (time() - process_start_time_seconds{job=~"$job", instance=~"$instance"})', "B"),
22 | )
23 | // Transformations
24 | .withTransformation({
25 | id: "merge",
26 | options: {}
27 | })
28 | .withTransformation({
29 | id: "organize",
30 | options: {
31 | excludeByName: {
32 | "Time": true,
33 | "Value #A": true,
34 | },
35 | "renameByName": {
36 | "Value #B": "Uptime",
37 | },
38 | },
39 | })
40 | // Overrides
41 | .overrideByName("Value #B", [
42 | { id: "unit", value: "s" },
43 | ]);
44 | };
45 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/0-bug-report.yaml:
--------------------------------------------------------------------------------
1 | name: New bug report
2 | description: Report a new bug
3 | title: "[Bug]: "
4 | labels: [bug]
5 |
6 | body:
7 | - type: markdown
8 | attributes:
9 | value: |
10 | Thanks for taking the time to fill out this bug report!
11 |
12 | This is helpful for us to improve the library and make it better :smile:
13 |
14 | - type: markdown
15 | attributes:
16 | value: |
17 | #
18 |
19 | - type: dropdown
20 | id: version
21 | attributes:
22 | label: version
23 | description: What's version are you using?
24 | options:
25 | - 11.3.x
26 | - 11.2.x
27 | - 11.1.x
28 | - 11.0.x
29 | - 10.4.x
30 | - 10.3.x
31 | - 10.2.x
32 | - 10.1.x
33 | default: 0
34 | validations:
35 | required: true
36 |
37 | - type: checkboxes
38 | id: language
39 | attributes:
40 | label: language
41 | description: What language(s) are you using?
42 | options:
43 | - label: Go
44 | - label: Java
45 | - label: PHP
46 | - label: Python
47 | - label: Typescript
48 |
49 | - type: textarea
50 | attributes:
51 | label: Describe your bug
52 | description: Put code examples could be helpful for us.
53 | validations:
54 | required: true
55 |
56 | - type: textarea
57 | attributes:
58 | label: What did you expect to happen?
59 | validations:
60 | required: true
61 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/1-missing-fields.yaml:
--------------------------------------------------------------------------------
1 | name: Missing fields
2 | description: Report a missing field/builder in any model.
3 | title: "[Schemas]: Missing field for "
4 |
5 | body:
6 | - type: markdown
7 | attributes:
8 | value: |
9 | Code generated is based on schemas and they could miss some fields.
10 | - type: markdown
11 | attributes:
12 | value: |
13 | #
14 |
15 | - type: dropdown
16 | id: version
17 | attributes:
18 | label: version
19 | description: What's version are you using?
20 | options:
21 | - 11.3.x
22 | - 11.2.x
23 | - 11.1.x
24 | - 11.0.x
25 | - 10.4.x
26 | - 10.3.x
27 | - 10.2.x
28 | - 10.1.x
29 | default: 0
30 | validations:
31 | required: true
32 |
33 | - type: input
34 | id: schema
35 | attributes:
36 | label: Missing field.
37 | description: In which model is the field missing?
38 | placeholder: "Example: Missing abc field in Dashboard"
39 | validations:
40 | required: true
41 |
42 | - type: input
43 | id: documentation
44 | attributes:
45 | label: Link to documentation.
46 | description: Link the documentation where is the field defined.
47 | placeholder: "Example: https://grafana.com/docs/grafana/latest/dashboards/build-dashboards/view-dashboard-json-model/#panel-size-and-position"
48 |
49 | - type: textarea
50 | attributes:
51 | label: Do you want to add any other information?
52 |
53 |
--------------------------------------------------------------------------------
/examples/php/custom-query/src/Custom/Query.php:
--------------------------------------------------------------------------------
1 | expr = $expr ?: "";
24 | $this->refId = $refId ?: "";
25 | $this->hide = $hide;
26 | }
27 |
28 | /**
29 | * @param array{expr?: string, refId?: string, hide?: bool} $data
30 | */
31 | public static function fromArray(array $data): self
32 | {
33 | return new self(
34 | expr: $data["expr"] ?? null,
35 | refId: $data["refId"] ?? null,
36 | hide: $data["hide"] ?? null,
37 | );
38 | }
39 |
40 | public function jsonSerialize(): array
41 | {
42 | $data = [
43 | "expr" => $this->expr,
44 | "refId" => $this->refId,
45 | ];
46 | if (isset($this->hide)) {
47 | $data["hide"] = $this->hide;
48 | }
49 | return $data;
50 | }
51 |
52 | public function dataqueryType(): string
53 | {
54 | return "custom";
55 | }
56 | }
--------------------------------------------------------------------------------
/examples/php/custom-query/src/Custom/QueryBuilder.php:
--------------------------------------------------------------------------------
1 |
9 | */
10 | class QueryBuilder implements Cog\Builder
11 | {
12 | protected Query $internal;
13 |
14 | public function __construct(string $query)
15 | {
16 | $this->internal = new Query(expr: $query);
17 | }
18 |
19 | /**
20 | * @return Query
21 | */
22 | public function build()
23 | {
24 | return $this->internal;
25 | }
26 |
27 | /**
28 | * The actual expression/query that will be evaluated by Prometheus
29 | */
30 | public function expr(string $expr): static
31 | {
32 | $this->internal->expr = $expr;
33 | return $this;
34 | }
35 |
36 | /**
37 | * A unique identifier for the query within the list of targets.
38 | * In server side expressions, the refId is used as a variable name to identify results.
39 | * By default, the UI will assign A->Z; however setting meaningful names may be useful.
40 | */
41 | public function refId(string $refId): static
42 | {
43 | $this->internal->refId = $refId;
44 | return $this;
45 | }
46 |
47 | /**
48 | * If hide is set to true, Grafana will filter out the response(s) associated with this query before returning it to the panel.
49 | */
50 | public function hide(bool $hide): static
51 | {
52 | $this->internal->hide = $hide;
53 | return $this;
54 | }
55 | }
--------------------------------------------------------------------------------
/.cog/templates/java/overrides/assigment_Dashboard_WithPanel.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "pre_assignment_Dashboard_withPanel" }}
2 |
3 | if (panelOrRowPanel.panel.gridPos == null) {
4 | panelOrRowPanel.panel.gridPos = new GridPos();
5 | }
6 | if (panelOrRowPanel.panel.gridPos.x == null) {
7 | panelOrRowPanel.panel.gridPos.x = 0;
8 | }
9 | if (panelOrRowPanel.panel.gridPos.y == null) {
10 | panelOrRowPanel.panel.gridPos.y = 0;
11 | }
12 | if (panelOrRowPanel.panel.gridPos.w == null) {
13 | panelOrRowPanel.panel.gridPos.w = 0;
14 | }
15 | if (panelOrRowPanel.panel.gridPos.h == null) {
16 | panelOrRowPanel.panel.gridPos.h = 0;
17 | }
18 | // The panel either has no position set, or it is the first panel of the dashboard.
19 | // In that case, we position it on the grid
20 | if (panelOrRowPanel.panel.gridPos.x == 0 && panelOrRowPanel.panel.gridPos.y == 0) {
21 | panelOrRowPanel.panel.gridPos.x = this.currentX;
22 | panelOrRowPanel.panel.gridPos.y = this.currentY;
23 | }
24 | {{- end }}
25 |
26 | {{- define "post_assignment_Dashboard_withPanel" }}
27 |
28 | // Prepare the coordinates for the next panel
29 | this.currentX += panelOrRowPanel.panel.gridPos.w;
30 | this.lastPanelHeight = java.lang.Math.max(this.lastPanelHeight, panelOrRowPanel.panel.gridPos.h);
31 |
32 | // Check for grid width overflow?
33 | if (this.currentX >= 24) {
34 | this.currentX = 0;
35 | this.currentY += this.lastPanelHeight;
36 | this.lastPanelHeight = 0;
37 | }
38 | {{- end }}
39 |
--------------------------------------------------------------------------------
/examples/typescript/alert-rule/src/index.ts:
--------------------------------------------------------------------------------
1 | import {
2 | QueryBuilder,
3 | RuleBuilder,
4 | RuleGroupBuilder,
5 | } from '@grafana/grafana-foundation-sdk/alerting';
6 |
7 | import { DataqueryBuilder} from '@grafana/grafana-foundation-sdk/prometheus';
8 | import { TypeThresholdBuilder } from '@grafana/grafana-foundation-sdk/expr';
9 |
10 | const datasourceUid = 'DS_PROMETHEUS_UID';
11 | const ruleGroupUid = '1m';
12 | const folderUid = 'folder-foo-uid';
13 |
14 | const queryA = new QueryBuilder('A')
15 | .datasourceUid(datasourceUid)
16 | .relativeTimeRange({ from: 600, to: 0 })
17 | .model(
18 | new DataqueryBuilder()
19 | .expr('vector(1)')
20 | .instant()
21 | .refId('A')
22 | );
23 |
24 | const queryB = new QueryBuilder('B')
25 | .datasourceUid('__expr__')
26 | .model(
27 | new TypeThresholdBuilder().conditions([{
28 | evaluator: { type: 'gt', params: [0] },
29 | },
30 | ])
31 | .datasource({ uid: '__expr__', type: '__expr__' })
32 | .expression('A')
33 | .refId('B')
34 | );
35 |
36 | const ruleBuilder = new RuleBuilder('[Example] Rule')
37 | .queries([queryA, queryB])
38 | .condition('B')
39 | .forDuration('0m')
40 | .ruleGroup(ruleGroupUid)
41 | .folderUID(folderUid)
42 | .labels({ severity: 'critical' })
43 | .annotations({ summary: 'Demo rule' });
44 |
45 | const ruleGroupBuilder = new RuleGroupBuilder(ruleGroupUid)
46 | .interval(60)
47 | .folderUid(folderUid)
48 | .rules([ruleBuilder]);
49 | console.log(JSON.stringify(ruleGroupBuilder.build(), null, 2));
50 |
51 |
--------------------------------------------------------------------------------
/.cog/templates/python/extra/docs/How-To/building-a-dashboard.md:
--------------------------------------------------------------------------------
1 | # Building a dashboard
2 |
3 | ```python
4 | from grafana_foundation_sdk.builders.dashboard import Dashboard, Row
5 | from grafana_foundation_sdk.builders import prometheus, timeseries
6 | from grafana_foundation_sdk.cog.encoder import JSONEncoder
7 | from grafana_foundation_sdk.models.common import TimeZoneBrowser
8 | from grafana_foundation_sdk.models import units
9 |
10 |
11 | def build_dashboard() -> Dashboard:
12 | builder = (
13 | Dashboard("[TEST] Node Exporter / Raspberry")
14 | .uid("test-dashboard-raspberry")
15 | .tags(["generated", "raspberrypi-node-integration"])
16 | .refresh("1m")
17 | .time("now-30m", "now")
18 | .timezone(TimeZoneBrowser)
19 | .with_row(Row("Overview"))
20 | .with_panel(
21 | timeseries.Panel()
22 | .title("Network Received")
23 | .unit(units.BitsPerSecondSI)
24 | .min(0)
25 | .with_target(
26 | prometheus.Dataquery()
27 | .expr(
28 | 'rate(node_network_receive_bytes_total{job="integrations/raspberrypi-node", device!="lo"}[$__rate_interval]) * 8'
29 | )
30 | .legend_format({{ `"{{ device }}"` }})
31 | )
32 | )
33 | )
34 |
35 | return builder
36 |
37 |
38 | if __name__ == "__main__":
39 | dashboard = build_dashboard().build()
40 | encoder = JSONEncoder(sort_keys=True, indent=2)
41 |
42 | print(encoder.encode(dashboard))
43 | ```
44 |
--------------------------------------------------------------------------------
/.cog/templates/typescript/overrides/assignment_Dashboard_withRow.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "pre_assignment_Dashboard_withRow" }}
2 |
3 | // Position the row on the grid
4 | if (!rowPanelResource.gridPos || (rowPanelResource.gridPos.x == 0 && rowPanelResource.gridPos.y == 0)) {
5 | rowPanelResource.gridPos = {
6 | x: 0, // beginning of the line
7 | y: this.currentY + this.lastPanelHeight,
8 |
9 | h: 1,
10 | w: 24, // full width
11 | };
12 | }
13 | {{- end }}
14 |
15 | {{- define "post_assignment_Dashboard_withRow" }}
16 |
17 | // Reset the state for the next row
18 | this.currentX = 0;
19 | this.currentY = rowPanelResource.gridPos.y + 1;
20 | this.lastPanelHeight = 0;
21 |
22 | // Position the row's panels on the grid
23 | rowPanelResource.panels.forEach(panel => {
24 | if (!panel.gridPos) {
25 | panel.gridPos = dashboard.defaultGridPos();
26 | }
27 |
28 | // The panel either has no position set, or it is the first panel of the dashboard.
29 | // In that case, we position it on the grid
30 | if (panel.gridPos.x == 0 && panel.gridPos.y == 0) {
31 | panel.gridPos.x = this.currentX;
32 | panel.gridPos.y = this.currentY;
33 | }
34 |
35 | // Prepare the coordinates for the next panel
36 | this.currentX += panel.gridPos.w;
37 | this.lastPanelHeight = Math.max(this.lastPanelHeight, panel.gridPos.h);
38 |
39 | // Check for grid width overflow?
40 | if (this.currentX >= 24) {
41 | this.currentX = 0;
42 | this.currentY += this.lastPanelHeight;
43 | this.lastPanelHeight = 0;
44 | }
45 | });
46 | {{- end }}
47 |
--------------------------------------------------------------------------------
/examples/java/grafana-agent-overview/src/main/java/agent/Discovery.java:
--------------------------------------------------------------------------------
1 | package agent;
2 |
3 | import com.grafana.foundation.timeseries.PanelBuilder;
4 | import com.grafana.foundation.units.Constants;
5 |
6 | import static agent.Common.*;
7 |
8 | public class Discovery {
9 | static PanelBuilder targetSyncTimeSeries() {
10 | return defaultTimeSeries().
11 | title("Target Sync").
12 | description("Actual interval to sync the scrape pool.").
13 | datasource(datasourceRef()).
14 | unit(Constants.Seconds).
15 | withTarget(
16 | prometheusQuery(
17 | "sum(rate(prometheus_target_sync_length_seconds_sum{job=~\"$job\", instance=~\"$instance\"}[$__rate_interval])) by (instance, scrape_job)",
18 | "{{instance}}/{{scrape_job}}"
19 | )
20 | );
21 | }
22 |
23 | static PanelBuilder targetsTimeSeries() {
24 | return defaultTimeSeries().
25 | title("Targets").
26 | description("Discovered targets by prometheus service discovery.").
27 | datasource(datasourceRef()).
28 | unit(Constants.Short).
29 | withTarget(
30 | prometheusQuery(
31 | "sum by (instance) (prometheus_sd_discovered_targets{job=~\"$job\", instance=~\"$instance\"})",
32 | "{{instance}}"
33 | )
34 | );
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/.cog/templates/python/overrides/assignment_Dashboard_withRow.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "pre_assignment_Dashboard_withRow" }}
2 |
3 | # Position the row on the grid
4 | if row_panel_resource.grid_pos is None or (row_panel_resource.grid_pos.x == 0 and row_panel_resource.grid_pos.y == 0):
5 | row_panel_resource.grid_pos = dashboard.GridPos(
6 | x=0,
7 | y=self.__current_y + self.__last_panel_height,
8 | h=1,
9 | w=24,
10 | )
11 | {{- end }}
12 |
13 | {{- define "post_assignment_Dashboard_withRow" }}
14 |
15 | # Reset the state for the next row
16 | self.__current_x = 0
17 | self.__current_y = row_panel_resource.grid_pos.y + 1
18 | self.__last_panel_height = 0
19 |
20 | # Position the row's panels on the grid
21 | for panel in row_panel_resource.panels:
22 | # Position the panel on the grid
23 | if panel.grid_pos is None:
24 | panel.grid_pos = dashboard.GridPos()
25 |
26 | # The panel either has no position set, or it is the first panel of the dashboard.
27 | # In that case, we position it on the grid
28 | if panel.grid_pos.x == 0 and panel.grid_pos.y == 0:
29 | panel.grid_pos.x = self.__current_x
30 | panel.grid_pos.y = self.__current_y
31 |
32 | # Prepare the coordinates for the next panel
33 | self.__current_x += panel.grid_pos.w
34 | self.__last_panel_height = max(self.__last_panel_height, panel.grid_pos.h)
35 |
36 | # Check for grid width overflow?
37 | if self.__current_x >= 24:
38 | self.__current_x = 0
39 | self.__current_y += self.__last_panel_height
40 | self.__last_panel_height = 0
41 | {{- end }}
42 |
--------------------------------------------------------------------------------
/.cog/templates/go/extra/docs/How-To/building-a-dashboard.md:
--------------------------------------------------------------------------------
1 | # Building a dashboard
2 |
3 | ```go
4 | package main
5 |
6 | import (
7 | "encoding/json"
8 | "fmt"
9 |
10 | "github.com/grafana/grafana-foundation-sdk/go/common"
11 | "github.com/grafana/grafana-foundation-sdk/go/dashboard"
12 | "github.com/grafana/grafana-foundation-sdk/go/prometheus"
13 | "github.com/grafana/grafana-foundation-sdk/go/timeseries"
14 | )
15 |
16 | func main() {
17 | builder := dashboard.NewDashboardBuilder("Sample dashboard").
18 | Uid("generated-from-go").
19 | Tags([]string{"generated", "from", "go"}).
20 | Refresh("1m").
21 | Time("now-30m", "now").
22 | Timezone(common.TimeZoneBrowser).
23 | WithRow(dashboard.NewRowBuilder("Overview")).
24 | WithPanel(
25 | timeseries.NewPanelBuilder().
26 | Title("Network Received").
27 | Unit("bps").
28 | Min(0).
29 | WithTarget(
30 | prometheus.NewDataqueryBuilder().
31 | Expr(`rate(node_network_receive_bytes_total{job="integrations/raspberrypi-node", device!="lo"}[$__rate_interval]) * 8`).
32 | LegendFormat({{ `"{{ device }}"` }}),
33 | ),
34 | )
35 |
36 | sampleDashboard, err := builder.Build()
37 | if err != nil {
38 | panic(err)
39 | }
40 | dashboardJson, err := json.MarshalIndent(sampleDashboard, "", " ")
41 | if err != nil {
42 | panic(err)
43 | }
44 |
45 | fmt.Println(string(dashboardJson))
46 | }
47 | ```
48 |
--------------------------------------------------------------------------------
/.cog/templates/go/overrides/api_reference_object_dashboard_Dashboard_extra.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "api_reference_object_dashboard_Dashboard_extra" -}}
2 | ## Examples
3 |
4 | ### Marshalling to JSON
5 |
6 | ```go
7 | package main
8 |
9 | import (
10 | "encoding/json"
11 | "fmt"
12 | "os"
13 |
14 | "github.com/grafana/grafana-foundation-sdk/go/cog"
15 | "github.com/grafana/grafana-foundation-sdk/go/dashboard"
16 | )
17 |
18 | func main() {
19 | sampleDashboard := &dashboard.Dashboard{
20 | Uid: cog.ToPtr("sample-dashboard-uid"),
21 | Title: cog.ToPtr("Sample dashboard"),
22 | }
23 |
24 | dashboardJson, err := json.MarshalIndent(sampleDashboard, "", " ")
25 | if err != nil {
26 | panic(err)
27 | }
28 |
29 | fmt.Println(string(dashboardJson))
30 | }
31 | ```
32 |
33 | ### Unmarshalling from JSON
34 |
35 | ```go
36 | package main
37 |
38 | import (
39 | "encoding/json"
40 | "fmt"
41 | "os"
42 |
43 | "github.com/grafana/grafana-foundation-sdk/go/cog/plugins"
44 | "github.com/grafana/grafana-foundation-sdk/go/dashboard"
45 | )
46 |
47 | func main() {
48 | // Required to correctly unmarshal panels and dataqueries
49 | plugins.RegisterDefaultPlugins()
50 |
51 | dashboardJSON, err := os.ReadFile("dashboard.json")
52 | if err != nil {
53 | panic(err)
54 | }
55 |
56 | sampleDashboard := &dashboard.Dashboard{}
57 | if err := json.Unmarshal(dashboardJSON, sampleDashboard); err != nil {
58 | panic(fmt.Sprintf("%s", err))
59 | }
60 |
61 | fmt.Printf("%#v\n", sampleDashboard)
62 | }
63 | ```
64 | {{ end }}
65 |
--------------------------------------------------------------------------------
/examples/go/grafana-agent-overview/overview.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/grafana/grafana-foundation-sdk/go/common"
5 | "github.com/grafana/grafana-foundation-sdk/go/dashboard"
6 | "github.com/grafana/grafana-foundation-sdk/go/table"
7 | "github.com/grafana/grafana-foundation-sdk/go/units"
8 | )
9 |
10 | func runningInstancesTable() *table.PanelBuilder {
11 | return table.NewPanelBuilder().
12 | Title("Running Instances").
13 | Description("General statistics of running grafana agent instances.").
14 | Height(7).
15 | Span(24).
16 | Footer(common.NewTableFooterOptionsBuilder().CountRows(false).Reducer([]string{"sum"})).
17 | Datasource(datasourceRef("$prometheus_datasource")).
18 | WithTarget(
19 | tablePrometheusQuery(`count by (instance, version) (agent_build_info{job=~"$job", instance=~"$instance"})`, "A"),
20 | ).
21 | WithTarget(
22 | tablePrometheusQuery(`max by (instance) (time() - process_start_time_seconds{job=~"$job", instance=~"$instance"})`, "B"),
23 | ).
24 | // Transformations
25 | WithTransformation(dashboard.DataTransformerConfig{
26 | Id: "merge",
27 | Options: map[string]any{},
28 | }).
29 | WithTransformation(dashboard.DataTransformerConfig{
30 | Id: "organize",
31 | Options: map[string]any{
32 | "excludeByName": map[string]any{
33 | "Time": true,
34 | "Value #A": true,
35 | },
36 | "renameByName": map[string]any{
37 | "Value #B": "Uptime",
38 | },
39 | },
40 | }).
41 | // Overrides
42 | OverrideByName("Value #B", []dashboard.DynamicConfigValue{
43 | {Id: "unit", Value: units.Seconds},
44 | })
45 | }
46 |
--------------------------------------------------------------------------------
/.cog/repository_templates/common/README.md:
--------------------------------------------------------------------------------
1 | # Grafana Foundation SDK
2 |
3 | A set of foundational tools meant to be used to manipulate Grafana resources
4 | as-code.
5 |
6 | **_Raw types_** and **_builder libraries_** are provided for a range
7 | of versions of Grafana, in the following languages:
8 |
9 | * Go
10 | * Java
11 | * PHP
12 | * Python
13 | * Typescript
14 |
15 | > [!NOTE]
16 | > The content of this repository is generated by [`cog`][cog] from
17 | > [schemas exposed by Grafana][kind-registry].
18 |
19 | > [!TIP]
20 | > This branch contains **types and builders generated for Grafana `{{ .Extra.GrafanaVersion }}`.**
21 |
22 | ## Navigating the SDK
23 |
24 | The following table can be used to select a version of the SDK suitable for
25 | your Grafana instance.
26 |
27 | | Grafana Version | `cog` Version | Branch |
28 | | ------------------------------ | ------------- | ------ |
29 | {{- range $version := (split ";" .Extra.AllGrafanaVersions) }}
30 | | `{{ $version }}`{{ if eq $version "next" }} (Grafana's main branch){{ end }} | `v0.0.x` | [{{ $version }}+cog-v0.0.x](https://github.com/grafana/grafana-foundation-sdk/tree/{{ $version }}%2Bcog-v0.0.x) |
31 | {{- end }}
32 |
33 | ## Maturity
34 |
35 | The code in this repository should be considered as "public preview". While it is used by Grafana Labs in production, it still is under active development.
36 |
37 | > [!NOTE]
38 | > Bugs and issues are handled solely by Engineering teams. On-call support or SLAs are not available.
39 |
40 | ## License
41 |
42 | [Apache 2.0 License](./LICENSE)
43 |
44 | [cog]:
45 | [kind-registry]:
46 |
--------------------------------------------------------------------------------
/examples/go/grafana-openapi-client-go/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/grafana/grafana-foundation-sdk/examples/go/grafana-openapi-client-go
2 |
3 | go 1.22.0
4 |
5 | require (
6 | github.com/go-openapi/strfmt v0.23.0
7 | github.com/grafana/grafana-foundation-sdk/go v0.0.0-20250501220944-e22983a17bec
8 | github.com/grafana/grafana-openapi-client-go v0.0.0-20241018134006-9d96c2007bd8
9 | )
10 |
11 | require (
12 | github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
13 | github.com/go-logr/logr v1.4.2 // indirect
14 | github.com/go-logr/stdr v1.2.2 // indirect
15 | github.com/go-openapi/analysis v0.23.0 // indirect
16 | github.com/go-openapi/errors v0.22.0 // indirect
17 | github.com/go-openapi/jsonpointer v0.21.0 // indirect
18 | github.com/go-openapi/jsonreference v0.21.0 // indirect
19 | github.com/go-openapi/loads v0.22.0 // indirect
20 | github.com/go-openapi/runtime v0.28.0 // indirect
21 | github.com/go-openapi/spec v0.21.0 // indirect
22 | github.com/go-openapi/swag v0.23.0 // indirect
23 | github.com/go-openapi/validate v0.24.0 // indirect
24 | github.com/google/uuid v1.6.0 // indirect
25 | github.com/josharian/intern v1.0.0 // indirect
26 | github.com/mailru/easyjson v0.7.7 // indirect
27 | github.com/mitchellh/mapstructure v1.5.0 // indirect
28 | github.com/oklog/ulid v1.3.1 // indirect
29 | github.com/opentracing/opentracing-go v1.2.0 // indirect
30 | go.mongodb.org/mongo-driver v1.17.1 // indirect
31 | go.opentelemetry.io/otel v1.31.0 // indirect
32 | go.opentelemetry.io/otel/metric v1.31.0 // indirect
33 | go.opentelemetry.io/otel/trace v1.31.0 // indirect
34 | golang.org/x/sync v0.8.0 // indirect
35 | gopkg.in/yaml.v3 v3.0.1 // indirect
36 | )
37 |
--------------------------------------------------------------------------------
/.cog/templates/go/overrides/assignment_Dashboard_withRow.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "pre_assignment_Dashboard_withRow" }}
2 |
3 | // Position the row on the grid
4 | if rowPanelResource.GridPos == nil || (rowPanelResource.GridPos.X == 0 && rowPanelResource.GridPos.Y == 0) {
5 | rowPanelResource.GridPos = &GridPos{
6 | X: 0, // beginning of the line
7 | Y: builder.currentY + builder.lastPanelHeight,
8 |
9 | H: 1,
10 | W: 24, // full width
11 | }
12 | }
13 | {{- end }}
14 |
15 | {{- define "post_assignment_Dashboard_withRow" }}
16 |
17 | // Reset the state for the next row
18 | builder.currentX = 0
19 | builder.currentY = rowPanelResource.GridPos.Y + 1
20 | builder.lastPanelHeight = 0
21 |
22 | // Position the row's panels on the grid
23 | for _, panel := range rowPanelResource.Panels {
24 | // If the panel does not have a GridPos set, set it to the default one.
25 | if panel.GridPos == nil {
26 | panel.GridPos = NewGridPos()
27 | }
28 |
29 | // The panel either has no position set, or it is the first panel of the dashboard.
30 | // In that case, we position it on the grid
31 | if panel.GridPos.X == 0 && panel.GridPos.Y == 0 {
32 | panel.GridPos.X = builder.currentX
33 | panel.GridPos.Y = builder.currentY
34 | }
35 |
36 | // Prepare the coordinates for the next panel
37 | builder.currentX += panel.GridPos.W
38 | builder.lastPanelHeight = max(builder.lastPanelHeight, panel.GridPos.H)
39 |
40 | // Check for grid width overflow?
41 | if builder.currentX >= 24 {
42 | builder.currentX = 0
43 | builder.currentY += builder.lastPanelHeight
44 | builder.lastPanelHeight = 0
45 | }
46 | }
47 | {{- end }}
48 |
--------------------------------------------------------------------------------
/.cog/templates/php/overrides/api_reference_package_dashboard_extra.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "api_reference_package_dashboard_extra" -}}
2 | ## Examples
3 |
4 | ### Building a dashboard
5 |
6 | ```php
7 | use Grafana\Foundation\Common;
8 | use Grafana\Foundation\Dashboard\DashboardBuilder;
9 | use Grafana\Foundation\Dashboard\RowBuilder;
10 | use Grafana\Foundation\Prometheus;
11 | use Grafana\Foundation\Timeseries;
12 |
13 | require_once __DIR__.'/vendor/autoload.php';
14 |
15 | $builder = (new DashboardBuilder(title: 'Sample dashboard'))
16 | ->uid('generated-from-php')
17 | ->tags(['generated', 'from', 'php'])
18 | ->refresh('1m')
19 | ->time('now-30m', 'now')
20 | ->timezone(Common\Constants::TIME_ZONE_BROWSER)
21 | ->withRow(new RowBuilder('Overview'))
22 | ->withPanel(
23 | (new Timeseries\PanelBuilder())
24 | ->title('Network received')
25 | ->unit('bps')
26 | ->min(0)
27 | ->withTarget(
28 | (new Prometheus\DataqueryBuilder())
29 | ->expr('rate(node_network_receive_bytes_total{job="integrations/raspberrypi-node", device!="lo"}[$__rate_interval]) * 8')
30 | ->legendFormat({{ `'{{ device }}'` }})
31 | )
32 | )
33 | ;
34 |
35 | echo(json_encode($builder->build(), JSON_PRETTY_PRINT).PHP_EOL);
36 | ```
37 |
38 | ### Unmarshaling a dashboard
39 |
40 | ```php
41 | use Grafana\Foundation\Dashboard\Dashboard;
42 |
43 | require_once __DIR__.'/vendor/autoload.php';
44 |
45 | $dashboardJSON = file_get_contents(__DIR__.'/dashboard.json');
46 |
47 | $dashboard = Dashboard::fromArray(json_decode($dashboardJSON, true));
48 |
49 | var_dump($dashboard);
50 | ```
51 | {{ end }}
52 |
--------------------------------------------------------------------------------
/examples/java/README.md:
--------------------------------------------------------------------------------
1 | # Examples
2 |
3 | This folder contains a collection of Grafana dashboards written in Java.
4 |
5 | Each example showcases different aspects of building dashboards as code:
6 |
7 | * [`alert-rule`](./alert-rule): definition and usage of alert rule and rule group types
8 | * [`custom-panel`](./custom-panel): definition and usage of a _custom_ Panel type
9 | * [`custom-query`](./custom-query): definition and usage of a _custom_ Query type
10 | * [`grafana-agent-overview`](./grafana-agent-overview):
11 | * reproduction of the "Grafana Agent Overview" dashboard from
12 | the [Grafana Agent integration](https://grafana.com/docs/grafana-cloud/monitor-infrastructure/integrations/integration-reference/integration-grafana-agent/)
13 | available in Grafana Cloud.
14 | * dashboard variables
15 | * `table` panels
16 | * `timeseries` panels
17 | * `prometheus` queries
18 | * [`linux-node-overview`](./linux-node-overview):
19 | * reproduction of the "Grafana Agent Overview" dashboard from
20 | the [Linux Server integration](https://grafana.com/docs/grafana-cloud/monitor-infrastructure/integrations/integration-reference/integration-linux-node/#dashboards)
21 | available in Grafana Cloud.
22 | * dashboard variables
23 | * dashboard links
24 | * `stat` panels
25 | * `table` panels
26 | * `timeseries` panels
27 | * `prometheus` queries
28 | * [`red-method`](./red-method):
29 | * example of a dashboard following
30 | the [RED method](https://grafana.com/blog/2018/08/02/the-red-method-how-to-instrument-your-services/#the-red-method)
31 |
32 | ## Running the examples
33 |
34 | From an example's folder:
35 |
36 | ```console
37 | $ gradle run
38 | ```
39 |
--------------------------------------------------------------------------------
/examples/python/custom-panel/src/custompanel.py:
--------------------------------------------------------------------------------
1 | from typing import Any, Self
2 |
3 | from grafana_foundation_sdk.cog import builder
4 | from grafana_foundation_sdk.cog import runtime as cogruntime
5 | from grafana_foundation_sdk.builders.dashboard import Panel as PanelBuilder
6 | from grafana_foundation_sdk.models import dashboard
7 |
8 |
9 | class CustomPanelOptions:
10 | make_beautiful: bool
11 |
12 | def __init__(self, make_beautiful: bool = False):
13 | self.make_beautiful = make_beautiful
14 |
15 | def to_json(self) -> dict[str, object]:
16 | return {
17 | "makeBeautiful": self.make_beautiful,
18 | }
19 |
20 | @classmethod
21 | def from_json(cls, data: dict[str, Any]) -> Self:
22 | args: dict[str, Any] = {}
23 |
24 | if "makeBeautiful" in data:
25 | args["make_beautiful"] = data["makeBeautiful"]
26 |
27 | return cls(**args)
28 |
29 |
30 | def custom_panel_variant_config() -> cogruntime.PanelCfgConfig:
31 | return cogruntime.PanelCfgConfig(
32 | # plugin ID
33 | identifier="custom-panel",
34 | options_from_json_hook=CustomPanelOptions.from_json,
35 | )
36 |
37 |
38 | class CustomPanelBuilder(PanelBuilder, builder.Builder[dashboard.Panel]):
39 | def __init__(self):
40 | super().__init__()
41 | # plugin ID
42 | self._internal.type_val = "custom-panel"
43 |
44 | def make_beautiful(self) -> Self:
45 | if self._internal.options is None:
46 | self._internal.options = CustomPanelOptions()
47 |
48 | assert isinstance(self._internal.options, CustomPanelOptions)
49 |
50 | self._internal.options.make_beautiful = True
51 |
52 | return self
53 |
--------------------------------------------------------------------------------
/examples/typescript/grafana-agent-overview/src/common.ts:
--------------------------------------------------------------------------------
1 | import * as common from '@grafana/grafana-foundation-sdk/common';
2 | import * as prometheus from '@grafana/grafana-foundation-sdk/prometheus';
3 | import { PanelBuilder as TimeseriesBuilder } from '@grafana/grafana-foundation-sdk/timeseries';
4 |
5 | export const prometheusQuery = (query: string, legend: string): prometheus.DataqueryBuilder => {
6 | return new prometheus.DataqueryBuilder()
7 | .expr(query)
8 | .legendFormat(legend);
9 | };
10 |
11 | export const tablePrometheusQuery = (query: string, ref: string): prometheus.DataqueryBuilder => {
12 | return new prometheus.DataqueryBuilder()
13 | .expr(query)
14 | .instant()
15 | .format(prometheus.PromQueryFormat.Table)
16 | .refId(ref);
17 | };
18 |
19 | export const defaultTimeseries = (): TimeseriesBuilder => {
20 | return new TimeseriesBuilder()
21 | .height(7)
22 | .span(12)
23 | .lineWidth(1)
24 | .fillOpacity(0)
25 | .pointSize(5)
26 | .showPoints(common.VisibilityMode.Auto)
27 | .drawStyle(common.GraphDrawStyle.Line)
28 | .gradientMode(common.GraphGradientMode.None)
29 | .spanNulls(false)
30 | .axisBorderShow(false)
31 | .legend(
32 | new common.VizLegendOptionsBuilder()
33 | .showLegend(true)
34 | .placement(common.LegendPlacement.Bottom)
35 | .displayMode(common.LegendDisplayMode.List)
36 | )
37 | .tooltip(
38 | new common.VizTooltipOptionsBuilder()
39 | .mode(common.TooltipDisplayMode.Single)
40 | .sort(common.SortOrder.None)
41 | )
42 | .thresholdsStyle(
43 | new common.GraphThresholdsStyleConfigBuilder()
44 | .mode(common.GraphThresholdsStyleMode.Off)
45 | );
46 | };
47 |
--------------------------------------------------------------------------------
/.cog/templates/go/overrides/api_reference_builder_dashboard_Dashboard_extra.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "api_reference_builder_dashboard_Dashboard_extra" -}}
2 | ## Examples
3 |
4 | ### Building a dashboard
5 |
6 | ```go
7 | package main
8 |
9 | import (
10 | "encoding/json"
11 | "fmt"
12 |
13 | "github.com/grafana/grafana-foundation-sdk/go/common"
14 | "github.com/grafana/grafana-foundation-sdk/go/dashboard"
15 | "github.com/grafana/grafana-foundation-sdk/go/prometheus"
16 | "github.com/grafana/grafana-foundation-sdk/go/timeseries"
17 | )
18 |
19 | func main() {
20 | builder := dashboard.NewDashboardBuilder("Sample dashboard").
21 | Uid("generated-from-go").
22 | Tags([]string{"generated", "from", "go"}).
23 | Refresh("1m").
24 | Time("now-30m", "now").
25 | Timezone(common.TimeZoneBrowser).
26 | WithRow(dashboard.NewRowBuilder("Overview")).
27 | WithPanel(
28 | timeseries.NewPanelBuilder().
29 | Title("Network Received").
30 | Unit("bps").
31 | Min(0).
32 | WithTarget(
33 | prometheus.NewDataqueryBuilder().
34 | Expr(`rate(node_network_receive_bytes_total{job="integrations/raspberrypi-node", device!="lo"}[$__rate_interval]) * 8`).
35 | LegendFormat({{ `"{{ device }}"` }}),
36 | ),
37 | )
38 |
39 | sampleDashboard, err := builder.Build()
40 | if err != nil {
41 | panic(err)
42 | }
43 | dashboardJson, err := json.MarshalIndent(sampleDashboard, "", " ")
44 | if err != nil {
45 | panic(err)
46 | }
47 |
48 | fmt.Println(string(dashboardJson))
49 | }
50 | ```
51 | {{ end }}
52 |
--------------------------------------------------------------------------------
/.cog/templates/typescript/extra/docs/How-To/custom-panel-type.md:
--------------------------------------------------------------------------------
1 | # Defining a custom panel type
2 |
3 | While the SDK ships with support for all core panels, it can be extended for
4 | private/third-party plugins.
5 |
6 | To do so, define a type and a builder for the custom panel's options:
7 |
8 | ```typescript
9 | // customPanel.ts
10 | import * as dashboard from '@grafana/grafana-foundation-sdk/dashboard';
11 |
12 | export interface CustomPanelOptions {
13 | makeBeautiful?: boolean;
14 | }
15 |
16 | export const defaultCustomPanelOptions = (): CustomPanelOptions => ({
17 | });
18 |
19 | export class CustomPanelBuilder extends dashboard.PanelBuilder {
20 | constructor() {
21 | super();
22 | this.internal.type = "custom-panel"; // panel plugin ID
23 | }
24 |
25 | makeBeautiful(): this {
26 | if (!this.internal.options) {
27 | this.internal.options = defaultCustomPanelOptions();
28 | }
29 | this.internal.options.makeBeautiful = true;
30 | return this;
31 | }
32 | }
33 | ```
34 |
35 | The custom panel type can now be used as usual to build a dashboard:
36 |
37 | ```typescript
38 | import { DashboardBuilder, RowBuilder } from '@grafana/grafana-foundation-sdk/dashboard';
39 | import { CustomPanelBuilder } from "./customPanel";
40 |
41 | const builder = new DashboardBuilder('Custom panel type')
42 | .uid('test-custom-panel-type')
43 |
44 | .refresh('1m')
45 | .time({ from: 'now-30m', to: 'now' })
46 |
47 | .withRow(new RowBuilder('Overview'))
48 | .withPanel(
49 | new CustomPanelBuilder()
50 | .title('Sample custom panel')
51 | .makeBeautiful()
52 | );
53 |
54 | console.log(JSON.stringify(builder.build(), null, 2));
55 | ```
56 |
--------------------------------------------------------------------------------
/scripts/docs/_pull_versions.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Exit on error. Append "|| true" if you expect an error.
4 | set -o errexit
5 | # Exit on error inside any functions or subshells.
6 | set -o errtrace
7 | # Do not allow use of undefined vars. Use ${VAR:-} to use an undefined VAR
8 | set -o nounset
9 | # Catch the error in case mysqldump fails (but gzip succeeds) in `mysqldump |gzip`
10 | set -o pipefail
11 |
12 | __dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13 | source "${__dir}/../versions.sh"
14 |
15 | tmp_dir=${1:-"./"}
16 |
17 | FOUNDATION_SDK_REPO=${FOUNDATION_SDK_REPO:-'https://github.com/grafana/grafana-foundation-sdk.git'}
18 |
19 | # Cleanup potential leftovers from previous runs.
20 | rm -rf "${tmp_dir}/tmp-foundation-sdk"
21 | rm -rf "${tmp_dir}/versions"
22 |
23 | mkdir -p "${tmp_dir}/versions"
24 | git clone "${FOUNDATION_SDK_REPO}" "${tmp_dir}/tmp-foundation-sdk"
25 |
26 | for version in ${ALL_GRAFANA_VERSIONS//;/ } ; do
27 | full_version="${version}+cog-${COG_VERSION}"
28 |
29 | echo "🪧 Pulling documentation for Foundation SDK version ${full_version}"
30 |
31 | git -C "${tmp_dir}/tmp-foundation-sdk" fetch origin "${full_version}"
32 | git -C "${tmp_dir}/tmp-foundation-sdk" checkout "${full_version}"
33 | git -C "${tmp_dir}/tmp-foundation-sdk" pull --ff-only origin "${full_version}"
34 |
35 | find "${tmp_dir}/tmp-foundation-sdk" -maxdepth 1 -mindepth 1 -type d -print | while read -r target; do
36 | language_name=${target#"${tmp_dir}/tmp-foundation-sdk"}
37 |
38 | if [ -d "${target}/docs" ]; then
39 | mkdir -p "${tmp_dir}/versions/${full_version}/${language_name}"
40 | cp -R ${target}/docs/* "${tmp_dir}/versions/${full_version}/${language_name}"
41 | fi
42 | done
43 | done
44 |
--------------------------------------------------------------------------------
/.cog/compiler/testdata_passes.yaml:
--------------------------------------------------------------------------------
1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/grafana/cog/main/schemas/compiler_passes.json
2 |
3 | passes:
4 | - anonymous_structs_to_named: {}
5 |
6 | # To stay close to the pre-v11 object names
7 |
8 | - omit:
9 | objects:
10 | - 'testdata.Testdata'
11 | - 'testdata.TestdataTestdataTargetsDatasource'
12 |
13 | - rename_object:
14 | from: 'testdata.TestdataTestdataTargets'
15 | to: 'dataquery'
16 |
17 | - schema_set_entry_point:
18 | package: testdata
19 | entry_point: dataquery
20 |
21 | - retype_field:
22 | field: testdata.dataquery.datasource
23 | as:
24 | kind: ref
25 | ref: { referred_pkg: common, referred_type: DataSourceRef }
26 |
27 | - rename_object:
28 | from: 'testdata.TestdataTestdataTargetsCsvWave'
29 | to: 'CSVWave'
30 |
31 | - rename_object:
32 | from: 'testdata.TestdataTestdataTargetsNodes'
33 | to: 'NodesQuery'
34 |
35 | - rename_object:
36 | from: 'testdata.TestdataTestdataTargetsPulseWave'
37 | to: 'PulseWaveQuery'
38 |
39 | - rename_object:
40 | from: 'testdata.TestdataTestdataTargetsResultAssertions'
41 | to: 'ResultAssertions'
42 |
43 | - rename_object:
44 | from: 'testdata.TestdataTestdataTargetsSimKey'
45 | to: 'Key'
46 |
47 | - rename_object:
48 | from: 'testdata.TestdataTestdataTargetsSim'
49 | to: 'SimulationQuery'
50 |
51 | - rename_object:
52 | from: 'testdata.TestdataTestdataTargetsStream'
53 | to: 'StreamingQuery'
54 |
55 | - rename_object:
56 | from: 'testdata.TestdataTestdataTargetsTimeRange'
57 | to: 'TimeRange'
58 |
59 | - rename_object:
60 | from: 'testdata.TestdataTestdataTargetsUsa'
61 | to: 'USAQuery'
62 |
--------------------------------------------------------------------------------
/examples/python/grafana-agent-overview/src/common.py:
--------------------------------------------------------------------------------
1 | from grafana_foundation_sdk.builders import (
2 | timeseries,
3 | common as common_builder,
4 | prometheus,
5 | )
6 | from grafana_foundation_sdk.models import common, prometheus as prom
7 |
8 |
9 | def prometheus_query(query: str, legend: str) -> prometheus.Dataquery:
10 | return prometheus.Dataquery().expr(query).legend_format(legend)
11 |
12 |
13 | def table_prometheus_query(query: str, ref_id: str) -> prometheus.Dataquery:
14 | return (
15 | prometheus.Dataquery()
16 | .expr(query)
17 | .format(prom.PromQueryFormat.TABLE)
18 | .instant()
19 | .interval_factor(2)
20 | .ref_id(ref_id)
21 | )
22 |
23 |
24 | def default_timeseries() -> timeseries.Panel:
25 | return (
26 | timeseries.Panel()
27 | .height(7)
28 | .span(12)
29 | .line_width(1)
30 | .fill_opacity(0)
31 | .point_size(5)
32 | .show_points(common.VisibilityMode.AUTO)
33 | .draw_style(common.GraphDrawStyle.LINE)
34 | .gradient_mode(common.GraphGradientMode.NONE)
35 | .span_nulls(False)
36 | .axis_border_show(False)
37 | .legend(
38 | common_builder.VizLegendOptions()
39 | .display_mode(common.LegendDisplayMode.LIST)
40 | .placement(common.LegendPlacement.BOTTOM)
41 | .show_legend(True)
42 | )
43 | .tooltip(
44 | common_builder.VizTooltipOptions()
45 | .mode(common.TooltipDisplayMode.SINGLE)
46 | .sort(common.SortOrder.NONE)
47 | )
48 | .thresholds_style(
49 | common_builder.GraphThresholdsStyleConfig().mode(
50 | common.GraphThresholdsStyleMode.OFF
51 | )
52 | )
53 | )
54 |
--------------------------------------------------------------------------------
/examples/php/README.md:
--------------------------------------------------------------------------------
1 | # Examples
2 |
3 | This folder contains a collection of Grafana dashboards written in PHP.
4 |
5 | Each example showcases different aspects of building dashboards as code:
6 |
7 | * [`custom-panel`](./custom-panel): definition and usage of a _custom_ Panel type
8 | * [`custom-query`](./custom-query): definition and usage of a _custom_ Query type
9 | * [`grafana-agent-overview`](./grafana-agent-overview):
10 | * reproduction of the "Grafana Agent Overview" dashboard from
11 | the [Grafana Agent integration](https://grafana.com/docs/grafana-cloud/monitor-infrastructure/integrations/integration-reference/integration-grafana-agent/)
12 | available in Grafana Cloud.
13 | * dashboard variables
14 | * `table` panels
15 | * `timeseries` panels
16 | * `prometheus` queries
17 | * [`linux-node-overview`](./linux-node-overview):
18 | * reproduction of the "Grafana Agent Overview" dashboard from
19 | the [Linux Server integration](https://grafana.com/docs/grafana-cloud/monitor-infrastructure/integrations/integration-reference/integration-linux-node/#dashboards)
20 | available in Grafana Cloud.
21 | * dashboard variables
22 | * dashboard links
23 | * `stat` panels
24 | * `table` panels
25 | * `timeseries` panels
26 | * `prometheus` queries
27 | * [`red-method`](./red-method):
28 | * example of a dashboard following
29 | the [RED method](https://grafana.com/blog/2018/08/02/the-red-method-how-to-instrument-your-services/#the-red-method)
30 |
31 | ## Running the examples
32 |
33 | From an example's folder:
34 |
35 | ```console
36 | $ composer install
37 | $ php index.php
38 | ```
39 |
40 | > [!NOTE]
41 | > [Grizzly](https://github.com/grafana/grizzly/) can be used to preview the examples locally:
42 | >
43 | > `grr serve -w -S 'php index.php' .`
44 |
--------------------------------------------------------------------------------
/.cog/templates/php/extra/src/Cog/UnknownDataquery.php:
--------------------------------------------------------------------------------
1 |
7 | */
8 | final class UnknownDataquery implements \ArrayAccess, \JsonSerializable, Dataquery
9 | {
10 | /**
11 | * @var array
12 | */
13 | private $data = [];
14 |
15 | /**
16 | * @param array $data
17 | */
18 | public function __construct(array $data)
19 | {
20 | $this->data = $data;
21 | }
22 |
23 | /**
24 | * @return array
25 | */
26 | public function toArray(): array
27 | {
28 | return $this->data;
29 | }
30 |
31 | public function dataqueryType(): string
32 | {
33 | return 'unknown';
34 | }
35 |
36 | /**
37 | * @param string $offset
38 | * @param mixed $value
39 | */
40 | public function offsetSet($offset, $value): void
41 | {
42 | $this->data[$offset] = $value;
43 | }
44 |
45 | /**
46 | * @param string $offset
47 | */
48 | public function offsetExists($offset): bool
49 | {
50 | return \array_key_exists($offset, $this->data);
51 | }
52 |
53 | /**
54 | * @param string $offset
55 | */
56 | public function offsetUnset($offset): void
57 | {
58 | unset($this->data[$offset]);
59 | }
60 |
61 | /**
62 | * @param string $offset
63 | */
64 | public function offsetGet($offset): mixed
65 | {
66 | if (!\array_key_exists($offset, $this->data)) {
67 | throw new \ValueError("offset '$offset' does not exist");
68 | }
69 | return $this->data[$offset] ?? null;
70 | }
71 |
72 | public function jsonSerialize(): mixed
73 | {
74 | return $this->data;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/.cog/templates/go/overrides/object_common_TableFooterOptions_custom_unmarshal.tmpl:
--------------------------------------------------------------------------------
1 | {{- define "object_common_TableFooterOptions_custom_unmarshal" }}
2 | {{- /* Non-standard unmarshalling needed because even though the "fields" field
3 | is typed as []string in the schema, Grafana uses `""` as an empty value
4 | */ -}}
5 | {{- $fmt := importStdPkg "fmt" -}}
6 | {{- $json := importStdPkg "encoding/json" -}}
7 | func (resource *{{ .Object.Name|upperCamelCase }}) UnmarshalJSON(raw []byte) error {
8 | if raw == nil {
9 | return nil
10 | }
11 |
12 | fields := make(map[string]json.RawMessage)
13 | if err := json.Unmarshal(raw, &fields); err != nil {
14 | return err
15 | }
16 | {{- range $field := .Object.Type.Struct.Fields }}
17 | {{- if eq $field.Name "fields" }}
18 | {{ template "unmarshal_common_TableFooterOptions_fields" }}
19 | {{- else }}
20 | if fields["{{ $field.Name }}"] != nil {
21 | if err := json.Unmarshal(fields["{{ $field.Name }}"], &resource.{{ $field.Name|upperCamelCase }}); err != nil {
22 | return fmt.Errorf("error decoding field '{{ $field.Name }}': %w", err)
23 | }
24 | }
25 | {{- end }}
26 | {{- end }}
27 |
28 | return nil
29 | }
30 |
31 | {{ end }}
32 |
33 | {{- define "unmarshal_common_TableFooterOptions_fields" -}}
34 | rawFields := fields["fields"]
35 |
36 | if rawFields != nil {
37 | if len(rawFields) != 0 && rawFields[0] == '"' {
38 | var field string
39 | if err := json.Unmarshal(rawFields, &field); err != nil {
40 | return fmt.Errorf("error decoding field 'fields': %w", err)
41 | }
42 | resource.Fields = []string{field}
43 | } else {
44 | if err := json.Unmarshal(rawFields, &resource.Fields); err != nil {
45 | return fmt.Errorf("error decoding field 'fields': %w", err)
46 | }
47 | }
48 | }
49 | {{- end -}}
50 |
--------------------------------------------------------------------------------
/examples/go/linux-node-overview/builder/host.go:
--------------------------------------------------------------------------------
1 | package builder
2 |
3 | import (
4 | "github.com/grafana/grafana-foundation-sdk/go/cog"
5 | "github.com/grafana/grafana-foundation-sdk/go/common"
6 | "github.com/grafana/grafana-foundation-sdk/go/dashboard"
7 | "github.com/grafana/grafana-foundation-sdk/go/stat"
8 | "github.com/grafana/grafana-foundation-sdk/go/units"
9 | )
10 |
11 | func uptimeStat() *stat.PanelBuilder {
12 | return defaultStat().
13 | Title("Uptime").
14 | Description("The duration of time that has passed since the last reboot or system start.").
15 | WithTarget(
16 | prometheusQuery(`time() - node_boot_time_seconds{job=~"integrations/(node_exporter|unix)",cluster=~"$cluster",job=~"$job",instance=~"$instance"}`, ""),
17 | ).
18 | Unit(units.DurationSeconds).
19 | Thresholds(dashboard.NewThresholdsConfigBuilder().
20 | Mode(dashboard.ThresholdsModeAbsolute).
21 | Steps([]dashboard.Threshold{
22 | {Value: nil, Color: "orange"},
23 | {Value: cog.ToPtr[float64](600), Color: "text"},
24 | }),
25 | )
26 | }
27 |
28 | func hostnameStat() *stat.PanelBuilder {
29 | return unameStat(
30 | "Hostname",
31 | "System's hostname.",
32 | "nodename",
33 | )
34 | }
35 |
36 | func kernelVersionStat() *stat.PanelBuilder {
37 | return unameStat(
38 | "Kernel version",
39 | "Kernel version of linux host.",
40 | "release",
41 | )
42 | }
43 |
44 | func osStat() *stat.PanelBuilder {
45 | return defaultStat().
46 | Title("OS").
47 | Description("Operating system.").
48 | WithTarget(
49 | tablePrometheusQuery(`node_os_info{job=~"integrations/(node_exporter|unix)",cluster=~"$cluster",job=~"$job",instance=~"$instance"}`, "A"),
50 | ).
51 | ReduceOptions(common.NewReduceDataOptionsBuilder().Calcs([]string{"lastNotNull"}).Fields("/^pretty_name$/")).
52 | ColorMode(common.BigValueColorModeNone)
53 | }
54 |
--------------------------------------------------------------------------------
/examples/go/grafana-agent-overview/common.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/grafana/grafana-foundation-sdk/go/cog"
5 | "github.com/grafana/grafana-foundation-sdk/go/common"
6 | "github.com/grafana/grafana-foundation-sdk/go/dashboard"
7 | "github.com/grafana/grafana-foundation-sdk/go/prometheus"
8 | "github.com/grafana/grafana-foundation-sdk/go/timeseries"
9 | )
10 |
11 | func datasourceRef(uid string) dashboard.DataSourceRef {
12 | return dashboard.DataSourceRef{Uid: &uid}
13 | }
14 |
15 | func prometheusQuery(query string, legend string) *prometheus.DataqueryBuilder {
16 | return prometheus.NewDataqueryBuilder().
17 | Expr(query).
18 | LegendFormat(legend)
19 | }
20 |
21 | func tablePrometheusQuery(query string, refID string) *prometheus.DataqueryBuilder {
22 | return prometheus.NewDataqueryBuilder().
23 | Expr(query).
24 | Format(prometheus.PromQueryFormatTable).
25 | Instant().
26 | IntervalFactor(2).
27 | RefId(refID)
28 | }
29 |
30 | func defaultTimeseries() *timeseries.PanelBuilder {
31 | return timeseries.NewPanelBuilder().
32 | Height(7).
33 | Span(12).
34 | LineWidth(1).
35 | FillOpacity(0).
36 | PointSize(5).
37 | ShowPoints(common.VisibilityModeAuto).
38 | DrawStyle(common.GraphDrawStyleLine).
39 | GradientMode(common.GraphGradientModeNone).
40 | Legend(common.NewVizLegendOptionsBuilder().
41 | DisplayMode(common.LegendDisplayModeList).
42 | Placement(common.LegendPlacementBottom).
43 | ShowLegend(true),
44 | ).
45 | Tooltip(common.NewVizTooltipOptionsBuilder().
46 | Mode(common.TooltipDisplayModeSingle).
47 | Sort(common.SortOrderNone),
48 | ).
49 | ThresholdsStyle(
50 | common.NewGraphThresholdsStyleConfigBuilder().
51 | Mode(common.GraphThresholdsStyleModeOff),
52 | ).
53 | SpanNulls(common.BoolOrFloat64{Bool: cog.ToPtr(false)}).
54 | AxisBorderShow(false)
55 | }
56 |
--------------------------------------------------------------------------------