├── .cog ├── compiler │ ├── alerting.yaml │ ├── athena.yaml │ ├── common_passes.yaml │ ├── dataqueries.yaml │ ├── expr_passes.yaml │ ├── kind_registry.yaml │ ├── prometheus.yaml │ ├── team.yaml │ └── testdata_passes.yaml ├── config.yaml ├── repository_templates │ ├── common │ │ ├── LICENSE │ │ └── README.md │ ├── java │ │ └── .github │ │ │ └── workflows │ │ │ └── java-release.yaml │ ├── php │ │ ├── .config │ │ │ └── ci │ │ │ │ └── php │ │ │ │ └── phpstan.neon │ │ └── composer.json │ ├── python │ │ └── .github │ │ │ └── workflows │ │ │ └── python-release.yaml │ └── typescript │ │ └── .github │ │ └── workflows │ │ └── typescript-release.yaml ├── schemas │ ├── composable │ │ ├── athena │ │ │ └── dataquery.cue │ │ ├── bigquery │ │ │ └── dataquery.cue │ │ ├── datasource │ │ │ └── dataquery.cue │ │ └── prometheus │ │ │ └── dataquery.cue │ ├── resource │ │ └── manifest.cue │ └── units │ │ └── units.cue ├── templates │ ├── README.md │ ├── go │ │ ├── extra │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── cog │ │ │ │ ├── plugins │ │ │ │ │ └── variants.go │ │ │ │ ├── runtime.go │ │ │ │ └── variants │ │ │ │ │ └── variants.go │ │ │ ├── docs │ │ │ │ ├── Examples.md │ │ │ │ ├── How-To │ │ │ │ │ ├── building-a-dashboard.md │ │ │ │ │ ├── converting-a-dashboard.md │ │ │ │ │ ├── custom-panel-type.md │ │ │ │ │ └── custom-query-type.md │ │ │ │ └── Installing.md │ │ │ └── go.mod │ │ └── overrides │ │ │ ├── api_reference_builder_dashboard_Dashboard_extra.tmpl │ │ │ ├── api_reference_object_dashboard_Dashboard_extra.tmpl │ │ │ ├── assignment_Dashboard_withPanel.tmpl │ │ │ ├── assignment_Dashboard_withRow.tmpl │ │ │ ├── object_common_TableFooterOptions_custom_unmarshal.tmpl │ │ │ ├── object_common_TableFooterOptions_field_fields_custom_strict_unmarshal.tmpl │ │ │ ├── object_dashboard_DataSourceRef_custom_unmarshal.tmpl │ │ │ ├── object_dashboard_Panel_custom_unmarshal.tmpl │ │ │ ├── object_dashboard_Panel_field_fieldConfig_custom_strict_unmarshal.tmpl │ │ │ ├── object_dashboard_Panel_field_options_custom_strict_unmarshal.tmpl │ │ │ ├── object_dashboard_Panel_field_targets_custom_strict_unmarshal.tmpl │ │ │ ├── object_variant_dataquery.tmpl │ │ │ ├── schema_variant_dataquery.tmpl │ │ │ ├── schema_variant_panelcfg.tmpl │ │ │ └── variant_dataquery_field_unmarshal.tmpl │ ├── java │ │ ├── extra │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── build.gradle │ │ │ ├── docs │ │ │ │ ├── Examples.md │ │ │ │ ├── How-To │ │ │ │ │ ├── building-a-dashboard.md │ │ │ │ │ ├── custom-panel-type.md │ │ │ │ │ └── custom-query-type.md │ │ │ │ └── Installing.md │ │ │ ├── gradle.properties │ │ │ ├── settings.gradle │ │ │ └── src │ │ │ │ └── main │ │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── grafana │ │ │ │ └── foundation │ │ │ │ └── cog │ │ │ │ └── variants │ │ │ │ ├── Dataquery.java │ │ │ │ ├── DataqueryConfig.java │ │ │ │ ├── PanelConfig.java │ │ │ │ ├── Registry.java │ │ │ │ ├── UnknownDataquery.java │ │ │ │ └── UnknownDataquerySerializer.java │ │ └── overrides │ │ │ ├── api_reference_builder_dashboard_Dashboard_extra.tmpl │ │ │ ├── api_reference_object_dashboard_Dashboard_extra.tmpl │ │ │ ├── assigment_Dashboard_WithPanel.tmpl │ │ │ └── assigment_Dashboard_WithRow.tmpl │ ├── php │ │ ├── extra │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── docs │ │ │ │ ├── Examples.md │ │ │ │ ├── How-To │ │ │ │ │ ├── building-a-dashboard.md │ │ │ │ │ ├── converting-a-dashboard.md │ │ │ │ │ ├── custom-panel-type.md │ │ │ │ │ └── custom-query-type.md │ │ │ │ └── Installing.md │ │ │ └── src │ │ │ │ └── Cog │ │ │ │ ├── Dataquery.php │ │ │ │ ├── DataqueryConfig.php │ │ │ │ ├── PanelcfgConfig.php │ │ │ │ ├── Runtime.php │ │ │ │ ├── UnknownDataquery.php │ │ │ │ └── UnknownDataqueryBuilder.php │ │ └── overrides │ │ │ ├── api_reference_builder_dashboard_Dashboard_extra.tmpl │ │ │ ├── api_reference_object_dashboard_Dashboard_extra.tmpl │ │ │ ├── api_reference_package_dashboard_extra.tmpl │ │ │ ├── assignment_Dashboard_withPanel.tmpl │ │ │ ├── assignment_Dashboard_withRow.tmpl │ │ │ ├── dynamic_files.tmpl │ │ │ ├── object_dashboard_Panel_custom_unmarshal.tmpl │ │ │ ├── object_variant_dataquery.tmpl │ │ │ └── variant_dataquery_field_unmarshal.tmpl │ ├── python │ │ ├── extra │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── docs │ │ │ │ ├── Examples.md │ │ │ │ ├── How-To │ │ │ │ │ ├── building-a-dashboard.md │ │ │ │ │ ├── custom-panel-type.md │ │ │ │ │ └── custom-query-type.md │ │ │ │ └── Installing.md │ │ │ ├── grafana_foundation_sdk │ │ │ │ └── cog │ │ │ │ │ ├── plugins.py │ │ │ │ │ ├── runtime.py │ │ │ │ │ └── variants.py │ │ │ └── pyproject.toml │ │ └── overrides │ │ │ ├── api_reference_builder_dashboard_Dashboard_extra.tmpl │ │ │ ├── api_reference_object_dashboard_Dashboard_extra.tmpl │ │ │ ├── assignment_Dashboard_withPanel.tmpl │ │ │ ├── assignment_Dashboard_withRow.tmpl │ │ │ ├── object_dashboard_Panel_custom_unmarshal.tmpl │ │ │ ├── schema_variant_dataquery.tmpl │ │ │ ├── schema_variant_panelcfg.tmpl │ │ │ └── variant_dataquery_field_unmarshal.tmpl │ └── typescript │ │ ├── extra │ │ ├── LICENSE │ │ ├── README.md │ │ ├── babel.config.json │ │ ├── docs │ │ │ ├── Examples.md │ │ │ ├── How-To │ │ │ │ ├── building-a-dashboard.md │ │ │ │ ├── custom-panel-type.md │ │ │ │ └── custom-query-type.md │ │ │ └── Installing.md │ │ ├── package.json │ │ └── tsconfig.json │ │ └── overrides │ │ ├── api_reference_builder_dashboard_Dashboard_extra.tmpl │ │ ├── assignment_Dashboard_withPanel.tmpl │ │ └── assignment_Dashboard_withRow.tmpl └── veneers │ ├── accesspolicy.common.yaml │ ├── alerting.common.yaml │ ├── alerting.go.yaml │ ├── alerting.typescript.yaml │ ├── cloudwatch.go.yaml │ ├── common.common.yaml │ ├── dashboard.common.yaml │ ├── dashboard.go.yaml │ ├── dashboard.php.yaml │ ├── dashboard.python.yaml │ ├── dashboard.variables.common.yaml │ ├── datasource.common.yaml │ ├── elasticsearch.common.yaml │ ├── expr.common.yaml │ ├── folder.common.yaml │ ├── heatmap.common.yaml │ ├── prometheus.yaml │ ├── team.common.yaml │ └── tempo.go.yaml ├── .editorconfig ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── 0-bug-report.yaml │ ├── 1-missing-fields.yaml │ ├── 2-feature-request.yaml │ ├── 3-general-issue.yaml │ └── config.yml ├── actions │ └── setup-cog │ │ └── action.yaml └── workflows │ ├── docs.yaml │ ├── release.yaml │ └── sdk-ci.yaml ├── .gitignore ├── .mkdocs ├── docs │ ├── assets │ │ ├── custom.css │ │ ├── logo.svg │ │ └── versions.js │ └── index.md ├── mkdocs-version.yml ├── mkdocs.yml └── overrides │ └── main.html ├── LICENSE ├── README.md ├── catalog-info.yaml ├── composer.json ├── devbox.json ├── devbox.lock ├── docs └── releasing.md ├── examples ├── go │ ├── .gitignore │ ├── README.md │ ├── custom-panel │ │ ├── custompanel.go │ │ ├── go.mod │ │ ├── go.sum │ │ └── main.go │ ├── custom-query │ │ ├── customquery.go │ │ ├── go.mod │ │ ├── go.sum │ │ └── main.go │ ├── grafana-agent-overview │ │ ├── common.go │ │ ├── discovery.go │ │ ├── go.mod │ │ ├── go.sum │ │ ├── main.go │ │ ├── overview.go │ │ └── retrieval.go │ ├── grafana-openapi-client-go │ │ ├── go.mod │ │ ├── go.sum │ │ └── main.go │ ├── linux-node-overview │ │ ├── builder │ │ │ ├── builder.go │ │ │ ├── common.go │ │ │ ├── cpu.go │ │ │ ├── disks.go │ │ │ ├── host.go │ │ │ ├── memory.go │ │ │ └── network.go │ │ ├── go.mod │ │ ├── go.sum │ │ └── main.go │ └── red-method │ │ ├── common.go │ │ ├── go.mod │ │ ├── go.sum │ │ ├── main.go │ │ └── red.go ├── java │ ├── README.md │ ├── custom-panel │ │ ├── build.gradle │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ └── src │ │ │ └── main │ │ │ └── java │ │ │ └── custompanel │ │ │ ├── CustomPanelBuilder.java │ │ │ ├── CustomPanelOptions.java │ │ │ └── Main.java │ ├── custom-query │ │ ├── build.gradle │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ └── src │ │ │ └── main │ │ │ └── java │ │ │ └── customquery │ │ │ ├── CustomQuery.java │ │ │ ├── CustomQueryBuilder.java │ │ │ └── Main.java │ ├── grafana-agent-overview │ │ ├── build.gradle │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ └── src │ │ │ └── main │ │ │ └── java │ │ │ └── agent │ │ │ ├── Common.java │ │ │ ├── Discovery.java │ │ │ ├── Main.java │ │ │ ├── Overview.java │ │ │ └── Retrieval.java │ ├── linux-node-overview │ │ ├── build.gradle │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ └── src │ │ │ └── main │ │ │ └── java │ │ │ └── linuxnode │ │ │ ├── Main.java │ │ │ └── linux │ │ │ ├── CPU.java │ │ │ ├── Common.java │ │ │ ├── Disk.java │ │ │ ├── Logs.java │ │ │ ├── Memory.java │ │ │ ├── Network.java │ │ │ └── NodeExporter.java │ └── red-method │ │ ├── build.gradle │ │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ └── src │ │ └── main │ │ └── java │ │ └── red │ │ ├── Common.java │ │ ├── Main.java │ │ └── Red.java ├── php │ ├── .gitignore │ ├── README.md │ ├── custom-panel │ │ ├── composer.json │ │ ├── composer.lock │ │ ├── index.php │ │ └── src │ │ │ └── Custom │ │ │ ├── Options.php │ │ │ └── PanelBuilder.php │ ├── custom-query │ │ ├── composer.json │ │ ├── composer.lock │ │ ├── index.php │ │ └── src │ │ │ └── Custom │ │ │ ├── Query.php │ │ │ └── QueryBuilder.php │ ├── grafana-agent-overview │ │ ├── composer.json │ │ ├── composer.lock │ │ ├── index.php │ │ └── src │ │ │ └── Agent │ │ │ └── Dashboard.php │ ├── linux-node-overview │ │ ├── composer.json │ │ ├── composer.lock │ │ ├── index.php │ │ └── src │ │ │ └── Linux │ │ │ ├── CPU.php │ │ │ ├── Common.php │ │ │ ├── Dashboard.php │ │ │ ├── Disk.php │ │ │ ├── Host.php │ │ │ ├── Memory.php │ │ │ └── Network.php │ └── red-method │ │ ├── composer.json │ │ ├── composer.lock │ │ ├── index.php │ │ └── src │ │ └── Red │ │ └── Dashboard.php ├── pulumi │ ├── README.md │ ├── go │ │ ├── Pulumi.dev.yaml │ │ ├── Pulumi.yaml │ │ ├── go.mod │ │ ├── go.sum │ │ └── main.go │ ├── python │ │ ├── .gitignore │ │ ├── Pulumi.dev.yaml │ │ ├── Pulumi.yaml │ │ ├── __main__.py │ │ └── requirements.txt │ └── typescript │ │ ├── .gitignore │ │ ├── Pulumi.dev.yaml │ │ ├── Pulumi.yaml │ │ ├── index.ts │ │ ├── package-lock.json │ │ ├── package.json │ │ └── tsconfig.json ├── python │ ├── .gitignore │ ├── README.md │ ├── custom-panel │ │ ├── main.py │ │ ├── requirements.txt │ │ └── src │ │ │ ├── __init__.py │ │ │ └── custompanel.py │ ├── custom-query │ │ ├── main.py │ │ ├── requirements.txt │ │ └── src │ │ │ ├── __init__.py │ │ │ └── customquery.py │ ├── grafana-agent-overview │ │ ├── main.py │ │ ├── requirements.txt │ │ └── src │ │ │ ├── __init__.py │ │ │ ├── common.py │ │ │ ├── discovery.py │ │ │ ├── overview.py │ │ │ └── retrieval.py │ ├── linux-node-overview │ │ ├── main.py │ │ ├── requirements.txt │ │ └── src │ │ │ ├── __init__.py │ │ │ ├── common.py │ │ │ ├── cpu.py │ │ │ ├── disk.py │ │ │ ├── host.py │ │ │ ├── memory.py │ │ │ └── network.py │ └── red-method │ │ ├── main.py │ │ ├── requirements.txt │ │ └── src │ │ ├── __init__.py │ │ ├── common.py │ │ └── red.py ├── terraform │ ├── .gitignore │ ├── README.md │ ├── dashboards.tf │ └── main.tf └── typescript │ ├── .gitignore │ ├── README.md │ ├── custom-panel │ ├── package.json │ ├── src │ │ ├── customPanel.ts │ │ └── index.ts │ ├── tsconfig.json │ └── yarn.lock │ ├── custom-query │ ├── package.json │ ├── src │ │ ├── customQuery.ts │ │ └── index.ts │ ├── tsconfig.json │ └── yarn.lock │ ├── grafana-agent-overview │ ├── package.json │ ├── src │ │ ├── common.ts │ │ ├── discovery.ts │ │ ├── index.ts │ │ ├── overview.ts │ │ └── retrieval.ts │ ├── tsconfig.json │ └── yarn.lock │ ├── linux-node-overview │ ├── package.json │ ├── src │ │ ├── common.ts │ │ ├── cpu.ts │ │ ├── disk.ts │ │ ├── host.ts │ │ ├── index.ts │ │ ├── memory.ts │ │ └── network.ts │ ├── tsconfig.json │ └── yarn.lock │ └── red-method │ ├── package.json │ ├── src │ ├── common.ts │ ├── index.ts │ └── red.ts │ ├── tsconfig.json │ └── yarn.lock ├── gradle.properties ├── requirements.txt └── scripts ├── docs ├── _pull_versions.sh └── build.sh ├── libs ├── git.sh └── logs.sh ├── release-all.sh ├── release-validate.sh ├── release-version.sh ├── validate ├── go.sh ├── java.sh ├── php.sh ├── python.sh └── typescript.sh └── versions.sh /.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: dashboard, referred_type: DataSourceRef } 17 | -------------------------------------------------------------------------------- /.cog/compiler/common_passes.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/grafana/cog/main/schemas/compiler_passes.json 2 | 3 | passes: 4 | - entrypoint_identification: {} 5 | - disjunction_with_constant_to_default: {} 6 | 7 | # Ensure consistent DataSourceRef 8 | - replace_reference: 9 | from: common.DataSourceRef 10 | to: dashboard.DataSourceRef 11 | - omit: { objects: [ common.DataSourceRef ] } 12 | -------------------------------------------------------------------------------- /.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: dashboard, 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/compiler/team.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/grafana/cog/main/schemas/compiler_passes.json 2 | 3 | passes: 4 | ######### 5 | # Teams # 6 | ######### 7 | 8 | - rename_object: 9 | from: team.CreateTeamCommand 10 | to: Team 11 | 12 | - fields_set_required: 13 | fields: [ team.Team.name ] 14 | -------------------------------------------------------------------------------- /.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: dashboard, 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 | -------------------------------------------------------------------------------- /.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 | * PHP 11 | * Python 12 | * Typescript 13 | 14 | > [!NOTE] 15 | > The content of this repository is generated by [`cog`][cog] from 16 | > [schemas exposed by Grafana][kind-registry]. 17 | 18 | > [!TIP] 19 | > This branch contains **types and builders generated for Grafana `{{ .Extra.GrafanaVersion }}`.** 20 | 21 | ## Navigating the SDK 22 | 23 | The following table can be used to select a version of the SDK suitable for 24 | your Grafana instance. 25 | 26 | | Grafana Version | `cog` Version | Branch | 27 | | ------------------------------ | ------------- | ------ | 28 | {{- range $version := (split ";" .Extra.AllGrafanaVersions) }} 29 | | `{{ $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) | 30 | {{- end }} 31 | 32 | ## Maturity 33 | 34 | 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. 35 | 36 | > [!NOTE] 37 | > Bugs and issues are handled solely by Engineering teams. On-call support or SLAs are not available. 38 | 39 | ## License 40 | 41 | [Apache 2.0 License](./LICENSE) 42 | 43 | [cog]: 44 | [kind-registry]: 45 | -------------------------------------------------------------------------------- /.cog/repository_templates/java/.github/workflows/java-release.yaml: -------------------------------------------------------------------------------- 1 | name: Java Release 2 | on: 3 | push: 4 | branches: 5 | - '{{ .Extra.ReleaseBranch|replace "+" "\\+" }}' 6 | 7 | env: 8 | JAVA_VERSION: '17' 9 | 10 | jobs: 11 | release: 12 | name: Build and release 13 | runs-on: ubuntu-latest 14 | 15 | permissions: 16 | contents: read 17 | 18 | defaults: 19 | run: 20 | shell: bash 21 | working-directory: ./java 22 | 23 | steps: 24 | - uses: actions/checkout@v4 25 | 26 | - name: Uses Java SDK {{ `${{ env.JAVA_VERSION }}` }} 27 | uses: actions/setup-java@v4 28 | with: 29 | java-version: {{ `${{ env.JAVA_VERSION }}` }} 30 | distribution: 'temurin' 31 | check-latest: true 32 | 33 | - name: Java setup gradle 34 | uses: gradle/actions/setup-gradle@v3 35 | with: 36 | gradle-version: '8.8' 37 | 38 | - name: Publish package 📦 39 | env: 40 | OSSRH_USERNAME: {{ `${{ secrets.OSSRH_USERNAME }}` }} 41 | OSSRH_PASSWORD: {{ `${{ secrets.OSSRH_PASSWORD }}` }} 42 | SIGNING_KEY: {{ `${{ secrets.SIGNING_KEY }}` }} 43 | SIGNING_PASSWORD: {{ `${{ secrets.SIGNING_PASSWORD }}` }} 44 | run: 45 | gradle publishToSonatype closeAndReleaseSonatypeStagingRepository 46 | 47 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.cog/repository_templates/python/.github/workflows/python-release.yaml: -------------------------------------------------------------------------------- 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@v4 30 | 31 | - name: Setup Python {{ `${{ env.PYTHON_VERSION }}` }} 32 | uses: actions/setup-python@v5 33 | with: 34 | python-version: {{ `${{ env.PYTHON_VERSION }}` }} 35 | 36 | - name: Install pypa/build 37 | run: python3 -m pip install build --user 38 | 39 | - name: Build a binary wheel and a source tarball 40 | run: python3 -m build 41 | 42 | - name: Publish distribution 📦 to PyPI 43 | uses: pypa/gh-action-pypi-publish@release/v1 44 | with: 45 | packages-dir: python/dist/ 46 | attestations: false 47 | -------------------------------------------------------------------------------- /.cog/repository_templates/typescript/.github/workflows/typescript-release.yaml: -------------------------------------------------------------------------------- 1 | name: TypeScript Release 2 | on: 3 | push: 4 | branches: 5 | - '{{ .Extra.ReleaseBranch|replace "+" "\\+" }}' 6 | 7 | env: 8 | NODE_VERSION: '18' 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 | defaults: 20 | run: 21 | shell: bash 22 | working-directory: ./typescript 23 | 24 | steps: 25 | - uses: actions/checkout@v4 26 | 27 | - name: Use Node.js {{ `${{ env.NODE_VERSION }}` }} 28 | uses: actions/setup-node@v4 29 | with: 30 | node-version: {{ `${{ env.NODE_VERSION }}` }} 31 | scope: '@grafana' 32 | registry-url: 'https://registry.npmjs.org' 33 | 34 | - name: Install dependencies 35 | run: yarn install 36 | 37 | - name: Build 38 | run: yarn build 39 | 40 | - name: Publish to NPM registry 41 | run: yarn publish --access public 42 | env: 43 | NODE_AUTH_TOKEN: {{ `${{ secrets.NPM_TOKEN }}` }} 44 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.cog/schemas/composable/datasource/dataquery.cue: -------------------------------------------------------------------------------- 1 | package datasource 2 | 3 | import ( 4 | "github.com/grafana/grafana/packages/grafana-schema/src/common" 5 | ) 6 | 7 | Dataquery: { 8 | common.DataQuery 9 | 10 | // Panel ID from wich the queries will be reused. 11 | panelId: uint32 12 | } 13 | -------------------------------------------------------------------------------- /.cog/schemas/resource/manifest.cue: -------------------------------------------------------------------------------- 1 | package resource 2 | 3 | Manifest: { 4 | apiVersion: string 5 | kind: string 6 | metadata: #Metadata 7 | spec: _ 8 | } 9 | 10 | #Metadata: { 11 | name: string 12 | namespace?: string 13 | labels?: [string]: string 14 | annotations?: [string]: string 15 | uid?: string 16 | resourceVersion?: string 17 | generation?: int64 18 | creationTimestamp?: string 19 | updateTimestamp?: string 20 | deletionTimestamp?: string 21 | } -------------------------------------------------------------------------------- /.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/go/extra/cog/plugins/variants.go: -------------------------------------------------------------------------------- 1 | package plugins 2 | 3 | {{- $panelPackages := .Context.PackagesForVariant "panelcfg" -}} 4 | {{- $dataqueryPackages := .Context.PackagesForVariant "dataquery" -}} 5 | 6 | {{- if or (ne (len $panelPackages) 0) (ne (len $dataqueryPackages) 0) }} 7 | import ( 8 | cog "{{ .Data.PackageRoot }}/cog" 9 | {{- range $pkg := $panelPackages }} 10 | {{ $pkg }} "{{ $.Data.PackageRoot }}/{{ $pkg }}" 11 | {{- end }} 12 | {{- range $pkg := $dataqueryPackages }} 13 | {{ $pkg }} "{{ $.Data.PackageRoot }}/{{ $pkg }}" 14 | {{- end }} 15 | ) 16 | {{- end }} 17 | 18 | func RegisterDefaultPlugins() { 19 | {{- if or (ne (len $panelPackages) 0) (ne (len $dataqueryPackages) 0) }} 20 | runtime := cog.NewRuntime() 21 | {{- end }} 22 | 23 | // Panelcfg variants 24 | {{- range $pkg := $panelPackages }} 25 | runtime.RegisterPanelcfgVariant({{ $pkg | formatPackageName }}.VariantConfig()) 26 | {{- end }} 27 | 28 | // Dataquery variants 29 | {{- range $pkg := $dataqueryPackages }} 30 | runtime.RegisterDataqueryVariant({{ $pkg | formatPackageName }}.VariantConfig()) 31 | {{- end }} 32 | } 33 | -------------------------------------------------------------------------------- /.cog/templates/go/extra/docs/Examples.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 10 3 | --- 4 | # Examples 5 | 6 | A collection of sample Grafana dashboards written in Go is available in the [grafana/grafana-foundation-sdk](https://github.com/grafana/grafana-foundation-sdk/) repository. 7 | 8 | Each example showcases different aspects of building dashboards as code: 9 | 10 | * [`custom-panel`](https://github.com/grafana/grafana-foundation-sdk/blob/main/examples/go/custom-panel): definition and usage of a _custom_ Panel type 11 | * [`custom-query`](https://github.com/grafana/grafana-foundation-sdk/blob/main/examples/go/custom-query): definition and usage of a _custom_ Query type 12 | * [`grafana-agent-overview`](https://github.com/grafana/grafana-foundation-sdk/blob/main/examples/go/grafana-agent-overview): 13 | * reproduction of the "Grafana Agent Overview" dashboard from 14 | the [Grafana Agent integration](https://grafana.com/docs/grafana-cloud/monitor-infrastructure/integrations/integration-reference/integration-grafana-agent/) 15 | available in Grafana Cloud. 16 | * dashboard variables 17 | * `table` panels 18 | * `timeseries` panels 19 | * `prometheus` queries 20 | * [`linux-node-overview`](https://github.com/grafana/grafana-foundation-sdk/blob/main/examples/go/linux-node-overview): 21 | * reproduction of the "Grafana Agent Overview" dashboard from 22 | the [Linux Server integration](https://grafana.com/docs/grafana-cloud/monitor-infrastructure/integrations/integration-reference/integration-linux-node/#dashboards) 23 | available in Grafana Cloud. 24 | * dashboard variables 25 | * dashboard links 26 | * `stat` panels 27 | * `table` panels 28 | * `timeseries` panels 29 | * `prometheus` queries 30 | * [`red-method`](https://github.com/grafana/grafana-foundation-sdk/blob/main/examples/go/red-method): 31 | * example of a dashboard following 32 | the [RED method](https://grafana.com/blog/2018/08/02/the-red-method-how-to-instrument-your-services/#the-red-method) 33 | -------------------------------------------------------------------------------- /.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/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 | 10 | "github.com/grafana/grafana-foundation-sdk/go/cog/plugins" 11 | "github.com/grafana/grafana-foundation-sdk/go/dashboard" 12 | ) 13 | 14 | func main() { 15 | // Required to correctly unmarshal panels and dataqueries 16 | plugins.RegisterDefaultPlugins() 17 | 18 | dashboardJSON, err := os.ReadFile("dashboard.json") 19 | if err != nil { 20 | panic(err) 21 | } 22 | 23 | dash := dashboard.Dashboard{} 24 | if err = json.Unmarshal(dashboardJSON, &dash); err != nil { 25 | panic(err) 26 | } 27 | 28 | converted := dashboard.DashboardConverter(dash) 29 | fmt.Println(converted) 30 | } 31 | ``` 32 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.cog/templates/go/extra/go.mod: -------------------------------------------------------------------------------- 1 | {{- if not .Data.Debug -}} 2 | module {{ .Data.PackageRoot }} 3 | 4 | go 1.21 5 | 6 | {{- end -}} -------------------------------------------------------------------------------- /.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/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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | // The panel either has no position set, or it is the first panel of the dashboard. 25 | // In that case, we position it on the grid 26 | if panel.GridPos.X == 0 && panel.GridPos.Y == 0 { 27 | panel.GridPos.X = builder.currentX 28 | panel.GridPos.Y = builder.currentY 29 | } 30 | 31 | // Prepare the coordinates for the next panel 32 | builder.currentX += panel.GridPos.W 33 | builder.lastPanelHeight = max(builder.lastPanelHeight, panel.GridPos.H) 34 | 35 | // Check for grid width overflow? 36 | if builder.currentX >= 24 { 37 | builder.currentX = 0 38 | builder.currentY += builder.lastPanelHeight 39 | builder.lastPanelHeight = 0 40 | } 41 | } 42 | {{- end }} 43 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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/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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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/object_variant_dataquery.tmpl: -------------------------------------------------------------------------------- 1 | {{- define "object_variant_dataquery" -}} 2 | func (resource {{ .Object.Name|formatObjectName }}) DataqueryType() string { 3 | return "{{ .Schema.Metadata.Identifier|lower }}" 4 | } 5 | 6 | {{ end }} -------------------------------------------------------------------------------- /.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 }} -------------------------------------------------------------------------------- /.cog/templates/java/extra/docs/How-To/building-a-dashboard.md: -------------------------------------------------------------------------------- 1 | # Building a dashboard 2 | 3 | ```java 4 | package example; 5 | 6 | import com.fasterxml.jackson.core.JsonProcessingException; 7 | import com.grafana.foundation.dashboard.Dashboard; 8 | import com.grafana.foundation.common.Constants; 9 | import com.grafana.foundation.dashboard.DashboardBuilder; 10 | import com.grafana.foundation.dashboard.DashboardDashboardTimeBuilder; 11 | import com.grafana.foundation.dashboard.RowBuilder; 12 | import com.grafana.foundation.prometheus.DataqueryBuilder; 13 | import com.grafana.foundation.timeseries.PanelBuilder; 14 | 15 | import java.util.List; 16 | 17 | public class Main { 18 | public static void main(String[] args) throws JsonProcessingException { 19 | Dashboard dashboard = new DashboardBuilder("Sample Dashboard"). 20 | uid("generated-from-java"). 21 | tags(List.of("generated", "from", "java")). 22 | refresh("1m"). 23 | time(new DashboardDashboardTimeBuilder(). 24 | from("now-30m"). 25 | to("now") 26 | ). 27 | timezone(Constants.TimeZoneBrowser). 28 | withRow(new RowBuilder("Overview")). 29 | withPanel(new PanelBuilder(). 30 | title("Network Received"). 31 | unit("bps"). 32 | min(0.0). 33 | withTarget(new DataqueryBuilder(). 34 | expr("rate(node_network_receive_bytes_total{job=\"integrations/raspberrypi-node\", device!=\"lo\"}[$__rate_interval]) * 8"). 35 | legendFormat({{ `"{{ device }}"` }}) 36 | ) 37 | ).build(); 38 | 39 | System.out.println(dashboard.toJSON()); 40 | } 41 | } 42 | ``` 43 | -------------------------------------------------------------------------------- /.cog/templates/java/extra/docs/Installing.md: -------------------------------------------------------------------------------- 1 | # Installing 2 | 3 | === "Gradle" 4 | ```kotlin 5 | implementation("com.grafana:grafana-foundation-sdk:{{ .Extra.GrafanaVersion|registryToSemver }}-{{ .Extra.BuildTimestamp }}") 6 | ``` 7 | === "Maven" 8 | ```xml 9 | 10 | com.grafana 11 | grafana-foundation-sdk 12 | {{ .Extra.GrafanaVersion|registryToSemver }}-{{ .Extra.BuildTimestamp }} 13 | 14 | ``` 15 | -------------------------------------------------------------------------------- /.cog/templates/java/extra/gradle.properties: -------------------------------------------------------------------------------- 1 | grafanaFoundationSDKVersion={{ if .Data.Debug }}0.0{{ else }}{{ .Extra.GrafanaVersion|registryToSemver }}-{{ .Extra.BuildTimestamp }}{{ end }} 2 | -------------------------------------------------------------------------------- /.cog/templates/java/extra/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'grafana-foundation-sdk' 2 | -------------------------------------------------------------------------------- /.cog/templates/java/extra/src/main/java/com/grafana/foundation/cog/variants/Dataquery.java: -------------------------------------------------------------------------------- 1 | package com.grafana.foundation.cog.variants; 2 | 3 | public interface Dataquery { 4 | String dataqueryName(); 5 | } 6 | -------------------------------------------------------------------------------- /.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 dataquery; 8 | {{ if .Data.Config.GenerateConverters }}private final Converter converter;{{ end }} 9 | 10 | public DataqueryConfig(Class 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 getDataquery() { 16 | return dataquery; 17 | } 18 | 19 | {{- if .Data.Config.GenerateConverters }} 20 | public Converter getConverter() { 21 | return converter; 22 | } 23 | {{- end }} 24 | } 25 | -------------------------------------------------------------------------------- /.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/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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.cog/templates/java/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 | ```java 7 | package example; 8 | 9 | import com.fasterxml.jackson.core.JsonProcessingException; 10 | import com.grafana.foundation.dashboard.Dashboard; 11 | import com.grafana.foundation.common.Constants; 12 | import com.grafana.foundation.dashboard.DashboardBuilder; 13 | import com.grafana.foundation.dashboard.DashboardDashboardTimeBuilder; 14 | import com.grafana.foundation.dashboard.RowBuilder; 15 | import com.grafana.foundation.prometheus.DataqueryBuilder; 16 | import com.grafana.foundation.timeseries.PanelBuilder; 17 | 18 | import java.util.List; 19 | 20 | public class Main { 21 | public static void main(String[] args) throws JsonProcessingException { 22 | Dashboard dashboard = new DashboardBuilder("Sample Dashboard"). 23 | uid("generated-from-java"). 24 | tags(List.of("generated", "from", "java")). 25 | refresh("1m"). 26 | time(new DashboardDashboardTimeBuilder(). 27 | from("now-30m"). 28 | to("now") 29 | ). 30 | timezone(Constants.TimeZoneBrowser). 31 | withRow(new RowBuilder("Overview")). 32 | withPanel(new PanelBuilder(). 33 | title("Network Received"). 34 | unit("bps"). 35 | min(0.0). 36 | withTarget(new DataqueryBuilder(). 37 | expr("rate(node_network_receive_bytes_total{job=\"integrations/raspberrypi-node\", device!=\"lo\"}[$__rate_interval]) * 8"). 38 | legendFormat({{ `"{{ device }}"` }}) 39 | ) 40 | ).build(); 41 | 42 | System.out.println(dashboard.toJSON()); 43 | } 44 | } 45 | ``` 46 | {{ end }} 47 | -------------------------------------------------------------------------------- /.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/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 | -------------------------------------------------------------------------------- /.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/templates/php/extra/docs/Examples.md: -------------------------------------------------------------------------------- 1 | --- 2 | weight: 10 3 | --- 4 | # Examples 5 | 6 | A collection of sample Grafana dashboards written in PHP is available in the [grafana/grafana-foundation-sdk](https://github.com/grafana/grafana-foundation-sdk/) repository. 7 | 8 | Each example showcases different aspects of building dashboards as code: 9 | 10 | * [`custom-panel`](https://github.com/grafana/grafana-foundation-sdk/blob/main/examples/php/custom-panel): definition and usage of a _custom_ Panel type 11 | * [`custom-query`](https://github.com/grafana/grafana-foundation-sdk/blob/main/examples/php/custom-query): definition and usage of a _custom_ Query type 12 | * [`grafana-agent-overview`](https://github.com/grafana/grafana-foundation-sdk/blob/main/examples/php/grafana-agent-overview): 13 | * reproduction of the "Grafana Agent Overview" dashboard from 14 | the [Grafana Agent integration](https://grafana.com/docs/grafana-cloud/monitor-infrastructure/integrations/integration-reference/integration-grafana-agent/) 15 | available in Grafana Cloud. 16 | * dashboard variables 17 | * `table` panels 18 | * `timeseries` panels 19 | * `prometheus` queries 20 | * [`linux-node-overview`](https://github.com/grafana/grafana-foundation-sdk/blob/main/examples/php/linux-node-overview): 21 | * reproduction of the "Grafana Agent Overview" dashboard from 22 | the [Linux Server integration](https://grafana.com/docs/grafana-cloud/monitor-infrastructure/integrations/integration-reference/integration-linux-node/#dashboards) 23 | available in Grafana Cloud. 24 | * dashboard variables 25 | * dashboard links 26 | * `stat` panels 27 | * `table` panels 28 | * `timeseries` panels 29 | * `prometheus` queries 30 | * [`red-method`](https://github.com/grafana/grafana-foundation-sdk/blob/main/examples/php/red-method): 31 | * example of a dashboard following 32 | the [RED method](https://grafana.com/blog/2018/08/02/the-red-method-how-to-instrument-your-services/#the-red-method) 33 | -------------------------------------------------------------------------------- /.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/php/extra/docs/How-To/converting-a-dashboard.md: -------------------------------------------------------------------------------- 1 | # Converting a dashboard 2 | 3 | ```php 4 | ): Dataquery 11 | */ 12 | public $fromArray; 13 | 14 | /** 15 | * @var (callable(Dataquery): string)|null 16 | */ 17 | public $convert; 18 | 19 | /** 20 | * @param callable(array): Dataquery $fromArray 21 | * @param (callable(Dataquery): string)|null $convert 22 | */ 23 | public function __construct(string $identifier, callable $fromArray, ?callable $convert = null) 24 | { 25 | $this->identifier = $identifier; 26 | $this->fromArray = $fromArray; 27 | $this->convert = $convert; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.cog/templates/php/extra/src/Cog/PanelcfgConfig.php: -------------------------------------------------------------------------------- 1 | ): object)|null 16 | */ 17 | public $optionsFromArray; 18 | 19 | /** 20 | * @var (callable(array): object)|null 21 | */ 22 | public $fieldConfigFromArray; 23 | 24 | /** 25 | * @param (callable(\Grafana\Foundation\Dashboard\Panel): string)|null $convert 26 | * @param (callable(array): object)|null $optionsFromArray 27 | * @param (callable(array): object)|null $fieldConfigFromArray 28 | */ 29 | public function __construct(string $identifier, ?callable $convert = null, ?callable $optionsFromArray = null, ?callable $fieldConfigFromArray = null) 30 | { 31 | $this->identifier = $identifier; 32 | $this->convert = $convert; 33 | $this->optionsFromArray = $optionsFromArray; 34 | $this->fieldConfigFromArray = $fieldConfigFromArray; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /.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/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 | -------------------------------------------------------------------------------- /.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/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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.cog/templates/php/overrides/assignment_Dashboard_withPanel.tmpl: -------------------------------------------------------------------------------- 1 | {{- define "pre_assignment_Dashboard_withPanel" }} 2 | 3 | if ($panelResource->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 | -------------------------------------------------------------------------------- /.cog/templates/php/overrides/assignment_Dashboard_withRow.tmpl: -------------------------------------------------------------------------------- 1 | {{- define "pre_assignment_Dashboard_withRow" }} 2 | 3 | // Position the row on the grid 4 | if ($rowPanelResource->gridPos === null || ($rowPanelResource->gridPos->x === 0 && $rowPanelResource->gridPos->y === 0)) { 5 | $rowPanelResource->gridPos = new {{ "Dashboard\\GridPos" | fullNamespaceRef }}( 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 | foreach ($rowPanelResource->panels as $panel) { 24 | if ($panel->gridPos === null) { 25 | $panel->gridPos = new {{ "Dashboard\\GridPos" | fullNamespaceRef }}(); 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 = 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 | -------------------------------------------------------------------------------- /.cog/templates/php/overrides/object_variant_dataquery.tmpl: -------------------------------------------------------------------------------- 1 | {{- define "object_variant_dataquery" -}} 2 | {{- $_ := apiDeclareMethod (dict 3 | "object" .Object 4 | "name" "dataqueryType" 5 | "comments" (listStr 6 | "Returns the type of this dataquery object." 7 | ) 8 | "return" "string" 9 | ) -}} 10 | public function dataqueryType(): string 11 | { 12 | return '{{ .Schema.Metadata.Identifier|lower }}'; 13 | } 14 | {{- end }} -------------------------------------------------------------------------------- /.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 }} -------------------------------------------------------------------------------- /.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/python/extra/docs/Installing.md: -------------------------------------------------------------------------------- 1 | # Installing 2 | 3 | ```shell 4 | python3 -m pip install 'grafana_foundation_sdk=={{ .Extra.BuildTimestamp }}!{{ .Extra.GrafanaVersion|registryToSemver }}' 5 | ``` 6 | -------------------------------------------------------------------------------- /.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/python/extra/grafana_foundation_sdk/cog/variants.py: -------------------------------------------------------------------------------- 1 | from abc import ABC 2 | 3 | 4 | class Dataquery(ABC): 5 | ... 6 | -------------------------------------------------------------------------------- /.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 = "{{ .Extra.BuildTimestamp }}!{{ .Extra.GrafanaVersion|registryToSemver }}" 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/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/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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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/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/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 }} -------------------------------------------------------------------------------- /.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 }} -------------------------------------------------------------------------------- /.cog/templates/typescript/extra/babel.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env", 4 | "@babel/preset-typescript" 5 | ], 6 | "plugins": [ 7 | "@babel/plugin-proposal-class-properties", 8 | "@babel/plugin-transform-runtime" 9 | ] 10 | } -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.cog/templates/typescript/extra/docs/Installing.md: -------------------------------------------------------------------------------- 1 | # Installing 2 | 3 | ```shell 4 | yarn add '@grafana/grafana-foundation-sdk@~{{ .Extra.GrafanaVersion|registryToSemver }}-cog{{ .Extra.CogVersion }}.{{ .Extra.BuildTimestamp }}' 5 | ``` 6 | -------------------------------------------------------------------------------- /.cog/templates/typescript/extra/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@grafana/grafana-foundation-sdk", 3 | "version": "{{ .Extra.GrafanaVersion|registryToSemver }}-cog{{ .Extra.CogVersion }}.{{ .Extra.BuildTimestamp }}", 4 | "description": "A set of tools, types and libraries for building and manipulating Grafana objects.", 5 | "keywords": [ 6 | "observability", 7 | "sdk", 8 | "grafana", 9 | "logs", 10 | "traces", 11 | "metrics" 12 | ], 13 | "publishConfig": { 14 | "registry": "https://registry.npmjs.org/", 15 | "access": "public", 16 | "provenance": true 17 | }, 18 | "license": "Apache-2.0", 19 | "author": "Grafana Labs", 20 | "homepage": "https://github.com/grafana/grafana-foundation-sdk", 21 | "repository": { 22 | "type": "git", 23 | "url": "https://github.com/grafana/grafana-foundation-sdk.git", 24 | "directory": "typescript" 25 | }, 26 | "sideEffects": false, 27 | "types": "dist/index.d.ts", 28 | "main": "dist/index.js", 29 | "files": [ 30 | "dist/**/*", 31 | "package.json" 32 | ], 33 | "exports": { 34 | "./cog": { 35 | "types": "./dist/cog/index.d.ts", 36 | "default": "./dist/cog/index.js" 37 | }, 38 | {{- range $i, $pkg := .Packages }} 39 | "./{{ $pkg | lowerCamelCase }}": { 40 | "types": "./dist/{{ $pkg | lowerCamelCase }}/index.d.ts", 41 | "default": "./dist/{{ $pkg | lowerCamelCase }}/index.js" 42 | }{{- if ne (add1 $i) (len $.Packages) }},{{- end }} 43 | {{- end }} 44 | }, 45 | "scripts": { 46 | "build": "tsc -p ./tsconfig.json" 47 | }, 48 | "devDependencies": { 49 | "@babel/core": "^7.12.9", 50 | "@babel/plugin-transform-classes": "7.10.4", 51 | "@babel/plugin-transform-runtime": "^7.12.10", 52 | "@babel/preset-env": "^7.12.7", 53 | "@babel/preset-typescript": "^7.12.7", 54 | "@grafana/tsconfig": "^1.3.0-rc1", 55 | "babel-loader": "^8.2.2", 56 | "typescript": "^5.0.0" 57 | }, 58 | "dependencies": { 59 | "tslib": "^2.6.2" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /.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 | } -------------------------------------------------------------------------------- /.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/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/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 | -------------------------------------------------------------------------------- /.cog/veneers/accesspolicy.common.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/grafana/cog/main/schemas/veneers.json 2 | 3 | language: all 4 | 5 | package: accesspolicy 6 | 7 | builders: ~ 8 | 9 | options: 10 | - array_to_append: 11 | by_name: AccessPolicy.rules 12 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.cog/veneers/alerting.go.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/grafana/cog/main/schemas/veneers.json 2 | 3 | language: go 4 | 5 | package: alerting 6 | 7 | options: 8 | - struct_fields_as_arguments: 9 | by_name: Query.relativeTimeRange 10 | -------------------------------------------------------------------------------- /.cog/veneers/alerting.typescript.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/grafana/cog/main/schemas/veneers.json 2 | 3 | language: typescript 4 | 5 | package: alerting 6 | 7 | options: 8 | - rename: 9 | by_name: Rule.for 10 | as: forDuration 11 | -------------------------------------------------------------------------------- /.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/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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.cog/veneers/datasource.common.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/grafana/cog/main/schemas/veneers.json 2 | 3 | language: all 4 | 5 | package: datasource 6 | 7 | options: 8 | - omit: { by_name: Dataquery.queryType } 9 | -------------------------------------------------------------------------------- /.cog/veneers/elasticsearch.common.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/grafana/cog/main/schemas/veneers.json 2 | 3 | language: all 4 | 5 | package: elasticsearch 6 | 7 | builders: 8 | - omit: { by_name: InlineScript } 9 | -------------------------------------------------------------------------------- /.cog/veneers/expr.common.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/grafana/cog/main/schemas/veneers.json 2 | 3 | language: all 4 | 5 | package: expr 6 | 7 | builders: 8 | - omit: { by_object: Expr } 9 | -------------------------------------------------------------------------------- /.cog/veneers/folder.common.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/grafana/cog/main/schemas/veneers.json 2 | 3 | language: all 4 | 5 | package: folder 6 | 7 | builders: 8 | ################ 9 | # Constructors # 10 | ################ 11 | - promote_options_to_constructor: 12 | by_name: Folder 13 | options: [name] 14 | 15 | options: ~ 16 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.cog/veneers/prometheus.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/grafana/cog/main/schemas/veneers.json 2 | 3 | language: all 4 | 5 | package: prometheus 6 | 7 | builders: 8 | # Like the UI, support a "both instant and range" query 9 | - add_option: 10 | by_object: Dataquery 11 | option: 12 | name: rangeAndInstant 13 | assignments: 14 | - path: range 15 | method: direct 16 | value: { constant: true } 17 | - path: instant 18 | method: direct 19 | value: { constant: true } 20 | 21 | options: 22 | # Ensure that enabling "range query mode" disables other modes 23 | - unfold_boolean: 24 | by_name: Dataquery.range 25 | true_as: range 26 | false_as: notRange 27 | - omit: { by_name: Dataquery.notRange } 28 | - add_assignment: 29 | by_name: Dataquery.range 30 | assignment: 31 | path: instant 32 | method: direct 33 | value: { constant: false } 34 | 35 | # Ensure that enabling "instant query mode" disables other modes 36 | - unfold_boolean: 37 | by_name: Dataquery.instant 38 | true_as: instant 39 | false_as: notInstant 40 | - omit: { by_name: Dataquery.notInstant } 41 | - add_assignment: 42 | by_name: Dataquery.instant 43 | assignment: 44 | path: range 45 | method: direct 46 | value: { constant: false } 47 | -------------------------------------------------------------------------------- /.cog/veneers/team.common.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/grafana/cog/main/schemas/veneers.json 2 | 3 | language: all 4 | 5 | package: team 6 | 7 | builders: 8 | ################ 9 | # Constructors # 10 | ################ 11 | - promote_options_to_constructor: 12 | by_name: Team 13 | options: [name] 14 | 15 | options: ~ 16 | -------------------------------------------------------------------------------- /.cog/veneers/tempo.go.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/grafana/cog/main/schemas/veneers.json 2 | 3 | language: go 4 | 5 | package: tempo 6 | 7 | builders: ~ 8 | 9 | options: 10 | - struct_fields_as_arguments: 11 | by_name: TraceqlFilter.value 12 | fields: [ ArrayOfString ] 13 | - rename_arguments: 14 | by_name: TraceqlFilter.value 15 | as: [values] 16 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | 2 | 3 | # EditorConfig is awesome: https://editorconfig.org 4 | 5 | # top-most EditorConfig file 6 | root = true 7 | 8 | [*] 9 | end_of_line = lf 10 | insert_final_newline = true 11 | charset = utf-8 12 | 13 | [*.py] 14 | indent_style = space 15 | indent_size = 4 16 | 17 | [*.ts] 18 | indent_style = space 19 | indent_size = 2 20 | 21 | [*.php] 22 | indent_style = space 23 | indent_size = 4 24 | 25 | [*.go] 26 | indent_style = tab 27 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @grafana/platform-monitoring 2 | -------------------------------------------------------------------------------- /.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> field for <model>" 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 | -------------------------------------------------------------------------------- /.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]: <title>" 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 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/3-general-issue.yaml: -------------------------------------------------------------------------------- 1 | name: General issue 2 | description: Ask for information, doubts, etc... 3 | title: "[Question]: <title>" 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 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: Grafana Community 4 | url: https://community.grafana.com 5 | about: Please ask and answer questions here. 6 | - name: Grafana Slack 7 | url: https://grafana.slack.com/archives/C024B5R8T60 8 | about: Dashboards-as-code related Slack channel. 9 | -------------------------------------------------------------------------------- /.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.34" 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 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | .gradle 3 | /examples/java/*/build/ 4 | -------------------------------------------------------------------------------- /.mkdocs/mkdocs-version.yml: -------------------------------------------------------------------------------- 1 | INHERIT: ./mkdocs.yml 2 | 3 | docs_dir: !ENV SOURCE_VERSION_FOLDER 4 | 5 | nav: ~ 6 | 7 | plugins: 8 | - search 9 | - mkdocs-nav-weight 10 | 11 | theme: 12 | logo: "../assets/logo.svg" 13 | 14 | extra: 15 | homepage: ../ 16 | 17 | extra_css: 18 | - "../assets/custom.css" 19 | 20 | extra_javascript: 21 | - "../assets/versions.js" 22 | -------------------------------------------------------------------------------- /.mkdocs/overrides/main.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block htmltitle %} 4 | {% if page.meta and page.meta.title %} 5 | <title>{{ 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 %} -------------------------------------------------------------------------------- /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 | links: 9 | - title: Slack Channel 10 | url: https://raintank-corp.slack.com/archives/C018SLDD5MW 11 | description: | 12 | Set of tools, types and libraries for building and manipulating Grafana objects. 13 | spec: 14 | type: library 15 | owner: group:default/platform-monitoring 16 | lifecycle: production 17 | -------------------------------------------------------------------------------- /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 | "require": {} 16 | } 17 | -------------------------------------------------------------------------------- /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/go/.gitignore: -------------------------------------------------------------------------------- 1 | */vendor 2 | -------------------------------------------------------------------------------- /examples/go/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | This folder contains a collection of Grafana dashboards written in Go. 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 | $ go mod vendor 37 | $ go run . 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 'go run .' .` 44 | -------------------------------------------------------------------------------- /examples/go/custom-panel/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/grafana/grafana-foundation-sdk/examples/go/grafana-agent-overview 2 | 3 | go 1.22.0 4 | 5 | require github.com/grafana/grafana-foundation-sdk/go v0.0.0-20250501220944-e22983a17bec 6 | -------------------------------------------------------------------------------- /examples/go/custom-panel/go.sum: -------------------------------------------------------------------------------- 1 | github.com/grafana/grafana-foundation-sdk/go v0.0.0-20250501220944-e22983a17bec h1:PB+nNSYq6olhYTsF12Nk2yMu9cVx2KnJ+7SZ3hwkFWA= 2 | github.com/grafana/grafana-foundation-sdk/go v0.0.0-20250501220944-e22983a17bec/go.mod h1:48EA8jF85SrReYflLa39Sk34b6NpxwJPBwjF3TJgRpE= 3 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /examples/go/custom-query/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/grafana/grafana-foundation-sdk/examples/go/grafana-agent-overview 2 | 3 | go 1.22.0 4 | 5 | require github.com/grafana/grafana-foundation-sdk/go v0.0.0-20250501220944-e22983a17bec 6 | -------------------------------------------------------------------------------- /examples/go/custom-query/go.sum: -------------------------------------------------------------------------------- 1 | github.com/grafana/grafana-foundation-sdk/go v0.0.0-20250501220944-e22983a17bec h1:PB+nNSYq6olhYTsF12Nk2yMu9cVx2KnJ+7SZ3hwkFWA= 2 | github.com/grafana/grafana-foundation-sdk/go v0.0.0-20250501220944-e22983a17bec/go.mod h1:48EA8jF85SrReYflLa39Sk34b6NpxwJPBwjF3TJgRpE= 3 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /examples/go/grafana-agent-overview/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/grafana/grafana-foundation-sdk/examples/go/grafana-agent-overview 2 | 3 | go 1.22.0 4 | 5 | require github.com/grafana/grafana-foundation-sdk/go v0.0.0-20250501220944-e22983a17bec 6 | -------------------------------------------------------------------------------- /examples/go/grafana-agent-overview/go.sum: -------------------------------------------------------------------------------- 1 | github.com/grafana/grafana-foundation-sdk/go v0.0.0-20250501220944-e22983a17bec h1:PB+nNSYq6olhYTsF12Nk2yMu9cVx2KnJ+7SZ3hwkFWA= 2 | github.com/grafana/grafana-foundation-sdk/go v0.0.0-20250501220944-e22983a17bec/go.mod h1:48EA8jF85SrReYflLa39Sk34b6NpxwJPBwjF3TJgRpE= 3 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/linux-node-overview/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/grafana/grafana-foundation-sdk/examples/go/linux-node-overview 2 | 3 | go 1.22.0 4 | 5 | require github.com/grafana/grafana-foundation-sdk/go v0.0.0-20250501220944-e22983a17bec 6 | -------------------------------------------------------------------------------- /examples/go/linux-node-overview/go.sum: -------------------------------------------------------------------------------- 1 | github.com/grafana/grafana-foundation-sdk/go v0.0.0-20250501220944-e22983a17bec h1:PB+nNSYq6olhYTsF12Nk2yMu9cVx2KnJ+7SZ3hwkFWA= 2 | github.com/grafana/grafana-foundation-sdk/go v0.0.0-20250501220944-e22983a17bec/go.mod h1:48EA8jF85SrReYflLa39Sk34b6NpxwJPBwjF3TJgRpE= 3 | -------------------------------------------------------------------------------- /examples/go/linux-node-overview/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | 7 | "github.com/grafana/grafana-foundation-sdk/examples/go/linux-node-overview/builder" 8 | ) 9 | 10 | func main() { 11 | sampleDashboard, err := builder.Build() 12 | if err != nil { 13 | panic(err) 14 | } 15 | dashboardJson, err := json.MarshalIndent(sampleDashboard, "", " ") 16 | if err != nil { 17 | panic(err) 18 | } 19 | 20 | fmt.Println(string(dashboardJson)) 21 | } 22 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /examples/go/red-method/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/grafana/grafana-foundation-sdk/examples/go/grafana-agent-overview 2 | 3 | go 1.22.0 4 | 5 | require github.com/grafana/grafana-foundation-sdk/go v0.0.0-20250501220944-e22983a17bec 6 | -------------------------------------------------------------------------------- /examples/go/red-method/go.sum: -------------------------------------------------------------------------------- 1 | github.com/grafana/grafana-foundation-sdk/go v0.0.0-20250501220944-e22983a17bec h1:PB+nNSYq6olhYTsF12Nk2yMu9cVx2KnJ+7SZ3hwkFWA= 2 | github.com/grafana/grafana-foundation-sdk/go v0.0.0-20250501220944-e22983a17bec/go.mod h1:48EA8jF85SrReYflLa39Sk34b6NpxwJPBwjF3TJgRpE= 3 | -------------------------------------------------------------------------------- /examples/go/red-method/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | redDashboard, err := red(redConfig{ 10 | DashboardTitle: "RED method", 11 | ServiceIDs: []string{"sample-service", "payments", "front-gateway"}, 12 | }).Build() 13 | if err != nil { 14 | panic(err) 15 | } 16 | dashboardJson, err := json.MarshalIndent(redDashboard, "", " ") 17 | if err != nil { 18 | panic(err) 19 | } 20 | 21 | fmt.Println(string(dashboardJson)) 22 | } 23 | -------------------------------------------------------------------------------- /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 | * [`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 | $ gradle run 37 | ``` 38 | -------------------------------------------------------------------------------- /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-panel/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafana/grafana-foundation-sdk/3d39499441e319a743025eb102707ae888f3bd41/examples/java/custom-panel/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /examples/java/custom-panel/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /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/custom-panel/src/main/java/custompanel/CustomPanelOptions.java: -------------------------------------------------------------------------------- 1 | package custompanel; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | public class CustomPanelOptions { 6 | @JsonProperty("makeItBeautiful") 7 | private Boolean makeItBeautiful; 8 | 9 | public void setMakeItBeautiful(Boolean makeItBeautiful) { 10 | this.makeItBeautiful = makeItBeautiful; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /examples/java/custom-query/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafana/grafana-foundation-sdk/3d39499441e319a743025eb102707ae888f3bd41/examples/java/custom-query/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /examples/java/custom-query/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /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/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/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/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/grafana-agent-overview/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafana/grafana-foundation-sdk/3d39499441e319a743025eb102707ae888f3bd41/examples/java/grafana-agent-overview/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /examples/java/grafana-agent-overview/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/java/linux-node-overview/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafana/grafana-foundation-sdk/3d39499441e319a743025eb102707ae888f3bd41/examples/java/linux-node-overview/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /examples/java/linux-node-overview/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /examples/java/linux-node-overview/src/main/java/linuxnode/Main.java: -------------------------------------------------------------------------------- 1 | package linuxnode; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import linuxnode.linux.NodeExporter; 5 | 6 | public class Main { 7 | public static void main(String[] args) { 8 | try { 9 | System.out.println(NodeExporter.Build().toJSON()); 10 | } catch (JsonProcessingException e) { 11 | throw new RuntimeException(e); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/java/linux-node-overview/src/main/java/linuxnode/linux/Logs.java: -------------------------------------------------------------------------------- 1 | package linuxnode.linux; 2 | 3 | import com.grafana.foundation.logs.PanelBuilder; 4 | 5 | public class Logs { 6 | public static PanelBuilder errorsInSystemLogs() { 7 | return Common.defaultLogs(). 8 | title("Errors in system logs"). 9 | withTarget(Common.basicLokiQuery("{level=~\"err|crit|alert|emerg\", job=\"integrations/raspberrypi-node\", instance=\"$instance\"}")). 10 | withTarget(Common.basicLokiQuery("{filename=~\"/var/log/syslog*|/var/log/messages*\", job=\"integrations/raspberrypi-node\", instance=\"$instance\"} |~\".+(?i)error(?-i).+\"")); 11 | } 12 | public static PanelBuilder authLogs() { 13 | return Common.defaultLogs(). 14 | title("Auth logs"). 15 | withTarget(Common.basicLokiQuery("{unit=\"ssh.service\", job=\"integrations/raspberrypi-node\", instance=\"$instance\"}")). 16 | withTarget(Common.basicLokiQuery("{filename=~\"/var/log/auth.log|/var/log/secure\", job=\"integrations/raspberrypi-node\", instance=\"$instance\"}")); 17 | } 18 | public static PanelBuilder kernelLogs() { 19 | return Common.defaultLogs(). 20 | title("Kernel logs"). 21 | withTarget(Common.basicLokiQuery("{transport=\"kernel\", job=\"integrations/raspberrypi-node\", instance=\"$instance\"}")). 22 | withTarget(Common.basicLokiQuery("{filename=\"/var/log/kern.log\", job=\"integrations/raspberrypi-node\", instance=\"$instance\"}")); 23 | } 24 | public static PanelBuilder allSystemLogs() { 25 | return Common.defaultLogs(). 26 | title("All system logs"). 27 | withTarget(Common.basicLokiQuery("{transport!=\"\", job=\"integrations/raspberrypi-node\", instance=\"$instance\"}")). 28 | withTarget(Common.basicLokiQuery("{filename!=\"\", job=\"integrations/raspberrypi-node\", instance=\"$instance\"}")); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /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/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/red-method/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafana/grafana-foundation-sdk/3d39499441e319a743025eb102707ae888f3bd41/examples/java/red-method/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /examples/java/red-method/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/php/.gitignore: -------------------------------------------------------------------------------- 1 | */vendor -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /examples/php/custom-panel/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "grafana/foundation-sdk-example", 3 | "type": "project", 4 | "autoload": { 5 | "psr-4": { 6 | "App\\": "./src" 7 | } 8 | }, 9 | "require": { 10 | "grafana/foundation-sdk": "dev-v11.6.x+cog-v0.0.x" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /examples/php/custom-query/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "grafana/foundation-sdk-example", 3 | "type": "project", 4 | "autoload": { 5 | "psr-4": { 6 | "App\\": "./src" 7 | } 8 | }, 9 | "require": { 10 | "grafana/foundation-sdk": "dev-v11.6.x+cog-v0.0.x" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /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()); -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /examples/php/grafana-agent-overview/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "grafana/foundation-sdk-example", 3 | "type": "project", 4 | "autoload": { 5 | "psr-4": { 6 | "App\\": "./src" 7 | } 8 | }, 9 | "require": { 10 | "grafana/foundation-sdk": "dev-v11.6.x+cog-v0.0.x" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/php/grafana-agent-overview/index.php: -------------------------------------------------------------------------------- 1 | =3.0.0,<4.0.0 2 | pulumiverse_grafana==0.5.0 3 | grafana_foundation_sdk==1713437340!10.4.0 4 | -------------------------------------------------------------------------------- /examples/pulumi/typescript/.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | /node_modules/ 3 | -------------------------------------------------------------------------------- /examples/pulumi/typescript/Pulumi.dev.yaml: -------------------------------------------------------------------------------- 1 | encryptionsalt: v1:ndbNyyxE2kA=:v1:R0etjMYFwiaC7/me:ouuaAW0UsZ6GpU68p6NvHWdBsCQOzQ== 2 | -------------------------------------------------------------------------------- /examples/pulumi/typescript/Pulumi.yaml: -------------------------------------------------------------------------------- 1 | name: foundation-sdk-typescript 2 | runtime: nodejs 3 | description: A show case of how to use the Typescript Foundation SDK in Pulumi 4 | config: 5 | pulumi:tags: 6 | value: 7 | pulumi:template: "" 8 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /examples/pulumi/typescript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foundation-sdk-typescript", 3 | "main": "index.ts", 4 | "devDependencies": { 5 | "@types/node": "^18", 6 | "typescript": "^5.0.0" 7 | }, 8 | "dependencies": { 9 | "@grafana/grafana-foundation-sdk": "~10.4.0-cogv0.0.x.1712659373", 10 | "@pulumi/pulumi": "^3.113.0", 11 | "@pulumiverse/grafana": "^0.5.0" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /examples/python/.gitignore: -------------------------------------------------------------------------------- 1 | */.venv 2 | __pycache__ 3 | *.pyc 4 | -------------------------------------------------------------------------------- /examples/python/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | This folder contains a collection of Grafana dashboards written in Python. 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 | Note, the Grafana Foundation SDK requires Python 3.11+. 34 | 35 | From an example's folder: 36 | 37 | ```console 38 | $ python -m venv .venv 39 | $ source .venv/bin/activate 40 | $ pip install -r requirements.txt 41 | $ python main.py 42 | ``` 43 | 44 | > [!NOTE] 45 | > [Grizzly](https://github.com/grafana/grizzly/) can be used to preview the examples locally: 46 | > `grr serve -w -S 'python main.py' .` 47 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /examples/python/custom-panel/requirements.txt: -------------------------------------------------------------------------------- 1 | grafana-foundation-sdk==1746136285!11.6.0 2 | -------------------------------------------------------------------------------- /examples/python/custom-panel/src/__init__.py: -------------------------------------------------------------------------------- 1 | # src 2 | -------------------------------------------------------------------------------- /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/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/python/custom-query/requirements.txt: -------------------------------------------------------------------------------- 1 | grafana-foundation-sdk==1746136285!11.6.0 2 | -------------------------------------------------------------------------------- /examples/python/custom-query/src/__init__.py: -------------------------------------------------------------------------------- 1 | # src 2 | -------------------------------------------------------------------------------- /examples/python/grafana-agent-overview/requirements.txt: -------------------------------------------------------------------------------- 1 | grafana-foundation-sdk==1746136285!11.6.0 2 | -------------------------------------------------------------------------------- /examples/python/grafana-agent-overview/src/__init__.py: -------------------------------------------------------------------------------- 1 | # src 2 | -------------------------------------------------------------------------------- /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/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/python/linux-node-overview/requirements.txt: -------------------------------------------------------------------------------- 1 | grafana-foundation-sdk==1746136285!11.6.0 2 | -------------------------------------------------------------------------------- /examples/python/linux-node-overview/src/__init__.py: -------------------------------------------------------------------------------- 1 | # src 2 | -------------------------------------------------------------------------------- /examples/python/red-method/main.py: -------------------------------------------------------------------------------- 1 | from grafana_foundation_sdk.cog.encoder import JSONEncoder 2 | 3 | from src.red import red 4 | 5 | 6 | red_dashboard = red( 7 | dashboard_title="RED method", 8 | service_ids=["sample-service", "payments", "front-gateway"], 9 | ) 10 | 11 | if __name__ == "__main__": 12 | print(JSONEncoder(sort_keys=True, indent=2).encode(red_dashboard.build())) 13 | -------------------------------------------------------------------------------- /examples/python/red-method/requirements.txt: -------------------------------------------------------------------------------- 1 | grafana-foundation-sdk==1746136285!11.6.0 2 | -------------------------------------------------------------------------------- /examples/python/red-method/src/__init__.py: -------------------------------------------------------------------------------- 1 | # src 2 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /examples/terraform/.gitignore: -------------------------------------------------------------------------------- 1 | .terraform 2 | .terraform.lock.hcl 3 | terraform.tfstate* 4 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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", < [!NOTE] 41 | > [Grizzly](https://github.com/grafana/grizzly/) can be used to preview the examples locally: 42 | > 43 | > `grr serve -w -S 'yarn dev' .` -------------------------------------------------------------------------------- /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-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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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/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/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 | -------------------------------------------------------------------------------- /examples/typescript/red-method/src/index.ts: -------------------------------------------------------------------------------- 1 | import { red } from "./red"; 2 | 3 | const redDashboard = red({ 4 | dashboardTitle: "RED method", 5 | serviceIds: ["sample-service", "payments", "front-gateway"], 6 | }); 7 | 8 | console.log(JSON.stringify(redDashboard.build(), null, 2)); 9 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.java.home= 2 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /scripts/validate/java.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}/java" 15 | 16 | gradle build -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /scripts/validate/python.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}/python" 15 | 16 | mypy . -------------------------------------------------------------------------------- /scripts/validate/typescript.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}/typescript" 15 | 16 | yarn install 17 | 18 | yarn build -------------------------------------------------------------------------------- /scripts/versions.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | COG_VERSION="v0.0.x" # hardcoded for now 4 | 5 | ALL_GRAFANA_VERSIONS="next;v11.6.x;v11.5.x;v11.4.x;v11.3.x;v11.2.x;v11.1.x;v11.0.x;v10.4.x;v10.3.x;v10.2.x;v10.1.x" 6 | --------------------------------------------------------------------------------