From 7cd8f7868a6dc3e46a282666f80cd879b4fa0928 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Gomez?= Date: Thu, 26 Mar 2020 11:54:44 +0100 Subject: [PATCH 1/8] Bootstrap some docs --- README.md | 6 ++++++ doc/index.md | 11 ++++++++++ doc/unmarshalling_yaml.md | 43 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 doc/index.md create mode 100644 doc/unmarshalling_yaml.md diff --git a/README.md b/README.md index 5e9acb55..04b80bf5 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,12 @@ if _, err := client.UpsertDashboard(ctx, folder, builder); err != nil { For a more complete example, see the [`example`](./cmd/example/) directory. +## Going further + +Check out [the documentation](doc/index.md) to discover what Grabana can do for +you. + + ## License This library is under the [MIT](LICENSE) license. diff --git a/doc/index.md b/doc/index.md new file mode 100644 index 00000000..0d4c51da --- /dev/null +++ b/doc/index.md @@ -0,0 +1,11 @@ +# Getting started with Grabana + +## Dashboards as code + +* [Example](../cmd/example/) +* [GoDoc](https://pkg.go.dev/github.com/K-Phoen/grabana?tab=doc) + +## Dashboards as YAML + +* [Example](../cmd/yaml/example.yaml) +* [Unmarshalling a YAML file](unmarshalling_yaml.md) diff --git a/doc/unmarshalling_yaml.md b/doc/unmarshalling_yaml.md new file mode 100644 index 00000000..1b4dc0bb --- /dev/null +++ b/doc/unmarshalling_yaml.md @@ -0,0 +1,43 @@ +# Unmarshalling a YAML file + +Grabana provides a way to unmarshal YAML. This can be done by giving a file or anything that +satisfies the `io.Reader` interface to the `decoder.UnmarshalYAML` function. + +The result is a `dashboard.Builder` that can then be used by Grabana's client to upsert the dashboard. + +```go +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "net/http" + "os" + + "github.com/K-Phoen/grabana/decoder" +) + +func main() { + filePath := "some/awesome/dashboard.yaml" + + content, err := ioutil.ReadFile(filePath) + if err != nil { + fmt.Fprintf(os.Stderr, "Could not read file: %s\n", err) + os.Exit(1) + } + + dashboard, err := decoder.UnmarshalYAML(bytes.NewBuffer(content)) + if err != nil { + fmt.Fprintf(os.Stderr, "Could not parse file: %s\n", err) + os.Exit(1) + } + + // do something with `dashboard` +} +``` + + +## That was it! + +[Return to the index to explore the other possibilities of the module](index.md) From 7ce4868c377e34d25c6875d8ea8854052a675934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Gomez?= Date: Thu, 26 Mar 2020 13:25:56 +0100 Subject: [PATCH 2/8] More doc --- README.md | 85 ++++++++++++++++++++++++++++------- doc/annotations_yaml.md | 19 ++++++++ doc/dashboard_options_yaml.md | 15 +++++++ doc/index.md | 5 ++- doc/variables_yaml.md | 44 ++++++++++++++++++ 5 files changed, 151 insertions(+), 17 deletions(-) create mode 100644 doc/annotations_yaml.md create mode 100644 doc/dashboard_options_yaml.md create mode 100644 doc/variables_yaml.md diff --git a/README.md b/README.md index 04b80bf5..b0849f8c 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,9 @@ Grabana provides a developer-friendly way of creating Grafana dashboards. -If you are looking for a way to version your dashboards configuration or -automate tedious and error-prone creation of dashboards, this library is meant -for you. +Whether you prefer writing **code or YAML**, if you are looking for a way to +version your dashboards configuration or automate tedious and error-prone +creation of dashboards, this library is meant for you. ## Design goals @@ -14,7 +14,7 @@ for you. * expose a developer-friendly API * allow IDE assistance and auto-completion -## Example +## Dashboard as code Dashboard configuration: @@ -48,20 +48,11 @@ ctx := context.Background() client := grabana.NewClient(&http.Client{}, grafanaHost, grafanaAPIToken) // create the folder holding the dashboard for the service -folder, err := client.GetFolderByTitle(ctx, "Test Folder") -if err != nil && err != grabana.ErrFolderNotFound { - fmt.Printf("Could not create folder: %s\n", err) +folder, err := client.FindOrCreateFolder(ctx, "Test Folder") +if err != nil { + fmt.Printf("Could not find or create folder: %s\n", err) os.Exit(1) } -if folder == nil { - folder, err = client.CreateFolder(ctx, "Test Folder") - if err != nil { - fmt.Printf("Could not create folder: %s\n", err) - os.Exit(1) - } - - fmt.Printf("Folder created (id: %d, uid: %s)\n", folder.ID, folder.UID) -} if _, err := client.UpsertDashboard(ctx, folder, builder); err != nil { fmt.Printf("Could not create dashboard: %s\n", err) @@ -71,6 +62,68 @@ if _, err := client.UpsertDashboard(ctx, folder, builder); err != nil { For a more complete example, see the [`example`](./cmd/example/) directory. +## Dashboard as YAML + +Dashboard configuration: + +```yaml +# dashboard.yaml +title: Awesome dashboard + +editable: true +tags: [generated] +auto_refresh: 5s + +variables: + - interval: + name: interval + label: Interval + values: ["30s", "1m", "5m", "10m", "30m", "1h", "6h", "12h"] + +rows: + - name: Prometheus + panels: + - graph: + title: HTTP Rate + height: 400px + datasource: prometheus-default + targets: + - prometheus: + query: "rate(promhttp_metric_handler_requests_total[$interval])" + legend: "{{handler}} - {{ code }}" +``` + +Dashboard creation: + +```go +content, err := ioutil.ReadFile("dashboard.yaml") +if err != nil { + fmt.Fprintf(os.Stderr, "Could not read file: %s\n", err) + os.Exit(1) +} + +dashboard, err := decoder.UnmarshalYAML(bytes.NewBuffer(content)) +if err != nil { + fmt.Fprintf(os.Stderr, "Could not parse file: %s\n", err) + os.Exit(1) +} + +ctx := context.Background() +client := grabana.NewClient(&http.Client{}, grafanaHost, grafanaAPIToken) + +// create the folder holding the dashboard for the service +folder, err := client.FindOrCreateFolder(ctx, "Test Folder") +if err != nil { + fmt.Printf("Could not find or create folder: %s\n", err) + os.Exit(1) +} + +if _, err := client.UpsertDashboard(ctx, folder, builder); err != nil { + fmt.Printf("Could not create dashboard: %s\n", err) + os.Exit(1) +} +``` + ## Going further Check out [the documentation](doc/index.md) to discover what Grabana can do for diff --git a/doc/annotations_yaml.md b/doc/annotations_yaml.md new file mode 100644 index 00000000..397f5aa6 --- /dev/null +++ b/doc/annotations_yaml.md @@ -0,0 +1,19 @@ +# Annotations + +> Annotations provide a way to mark points on the graph with rich events. When +> you hover over an annotation you can get event description and event tags. +> The text field can include links to other systems with more detail. +> +> — https://grafana.com/docs/grafana/latest/reference/annotations/ + +```yaml +tags_annotations: + - name: Deployments + datasource: "-- Grafana --" + color: "#5794F2" + tags: ["deploy", "production"] +``` + +## That was it! + +[Return to the index to explore the other possibilities of the module](index.md) diff --git a/doc/dashboard_options_yaml.md b/doc/dashboard_options_yaml.md new file mode 100644 index 00000000..ac55c1d9 --- /dev/null +++ b/doc/dashboard_options_yaml.md @@ -0,0 +1,15 @@ +# Dashboard options + +Generic options describing the dashboard's behavior. + +```yaml +title: Awesome dashboard +editable: true +shared_crosshair: true +tags: [generated, yaml] +auto_refresh: 10s +``` + +## That was it! + +[Return to the index to explore the other possibilities of the module](index.md) diff --git a/doc/index.md b/doc/index.md index 0d4c51da..02660538 100644 --- a/doc/index.md +++ b/doc/index.md @@ -7,5 +7,8 @@ ## Dashboards as YAML -* [Example](../cmd/yaml/example.yaml) * [Unmarshalling a YAML file](unmarshalling_yaml.md) +* [Realistic example](../cmd/yaml/example.yaml) +* [Dashboard options](dashboard_options_yaml.md) +* [Variables](variables_yaml.md) +* [Annotations](annotations_yaml.md) diff --git a/doc/variables_yaml.md b/doc/variables_yaml.md new file mode 100644 index 00000000..77ffb9c7 --- /dev/null +++ b/doc/variables_yaml.md @@ -0,0 +1,44 @@ +# Variables + +> Variables allows for more interactive and dynamic dashboards. Instead of +> hard-coding things like server, application and sensor name in your metric +> queries you can use variables in their place. Variables are shown as +> dropdown select boxes at the top of the dashboard. These dropdowns +> make it easy to change the data being displayed in your dashboard. +> +> — https://grafana.com/docs/grafana/latest/reference/templating/ + +```yaml +variables: + - interval: + name: interval + label: Interval + values: ["30s", "1m", "5m", "10m", "30m", "1h", "6h", "12h"] + - query: + name: status + label: HTTP status + datasource: prometheus-default + request: "label_values(prometheus_http_requests_total, code)" + - const: + name: percentile + label: Percentile + default: 80 + values_map: + 50th: "50" + 75th: "75" + 80th: "80" + 85th: "85" + 90th: "90" + 95th: "95" + 99th: "99" + - custom: + name: vX + default: v2 + values_map: + v1: v1 + v2: v2 +``` + +## That was it! + +[Return to the index to explore the other possibilities of the module](index.md) From 16d7f5c0b0f6929673a9c50290ae3a53d4e222ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Gomez?= Date: Thu, 26 Mar 2020 13:28:07 +0100 Subject: [PATCH 3/8] Add CI for the documentation --- .github/workflows/ci.yaml | 22 ++++++++++++++++++++++ .markdownlint.json | 8 ++++++++ 2 files changed, 30 insertions(+) create mode 100644 .markdownlint.json diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index a0974809..5cbeef7c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -17,6 +17,28 @@ jobs: golangci_lint_flags: "--config=.golangci.yaml" reporter: github-pr-review + doc: + name: Documentation + runs-on: ubuntu-18.04 + + steps: + - uses: actions/checkout@v2 + with: + depth: 1 + + - uses: nosborn/github-action-markdown-cli@master + with: + files: ./content/ + + - uses: K-Phoen/action-misspell@master + with: + github_token: ${{ github.token }} + reporter: github-pr-review + locale: "US" + + - name: alexjs + uses: theashraf/alex-action@master + tests: name: Tests runs-on: ubuntu-18.04 diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 00000000..64daad1c --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,8 @@ +{ + "default": true, + "no-inline-html": false, + "no-hard-tabs": false, + "no-trailing-punctuation": false, + "no-bare-urls": false, + "line-length": false +} From d51c0a8190daf1391ea1bfbb78fdea669db54f31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Gomez?= Date: Thu, 26 Mar 2020 13:33:46 +0100 Subject: [PATCH 4/8] Text panels --- doc/index.md | 1 + doc/text_panels_yaml.md | 28 ++++++++++++++++++++++++++++ doc/variables_yaml.md | 2 +- 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 doc/text_panels_yaml.md diff --git a/doc/index.md b/doc/index.md index 02660538..1a8f2ff7 100644 --- a/doc/index.md +++ b/doc/index.md @@ -12,3 +12,4 @@ * [Dashboard options](dashboard_options_yaml.md) * [Variables](variables_yaml.md) * [Annotations](annotations_yaml.md) +* [Text panels](text_panels_yaml.md) diff --git a/doc/text_panels_yaml.md b/doc/text_panels_yaml.md new file mode 100644 index 00000000..3870e530 --- /dev/null +++ b/doc/text_panels_yaml.md @@ -0,0 +1,28 @@ +# Text panels + +> The text panel lets you make information and description panels etc. for your +> dashboards. +> +> — https://grafana.com/docs/grafana/latest/features/panels/text/ + +```yaml + +rows: + - name: "Text panels row" + panels: + - text: + title: Some awesome text? + span: 6 + height: 400px + markdown: "Markdown syntax help: [commonmark.org/help](https://commonmark.org/help/)\n${percentile}" + + - text: + title: Some awesome html? + span: 3 + height: 200px + html: "Some awesome html?" +``` + +## That was it! + +[Return to the index to explore the other possibilities of the module](index.md) diff --git a/doc/variables_yaml.md b/doc/variables_yaml.md index 77ffb9c7..2997a40d 100644 --- a/doc/variables_yaml.md +++ b/doc/variables_yaml.md @@ -4,7 +4,7 @@ > hard-coding things like server, application and sensor name in your metric > queries you can use variables in their place. Variables are shown as > dropdown select boxes at the top of the dashboard. These dropdowns -> make it easy to change the data being displayed in your dashboard. +> allow changing the data being displayed in your dashboard. > > — https://grafana.com/docs/grafana/latest/reference/templating/ From f341a9a438345fae6c3fcbc52e30885fac548e32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Gomez?= Date: Thu, 26 Mar 2020 14:12:59 +0100 Subject: [PATCH 5/8] Table panels --- doc/index.md | 1 + doc/table_panels_yaml.md | 33 +++++++++++++++++++++++++++++++++ doc/text_panels_yaml.md | 1 - 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 doc/table_panels_yaml.md diff --git a/doc/index.md b/doc/index.md index 1a8f2ff7..09223b01 100644 --- a/doc/index.md +++ b/doc/index.md @@ -13,3 +13,4 @@ * [Variables](variables_yaml.md) * [Annotations](annotations_yaml.md) * [Text panels](text_panels_yaml.md) +* [Table panels](table_panels_yaml.md) diff --git a/doc/table_panels_yaml.md b/doc/table_panels_yaml.md new file mode 100644 index 00000000..da9a0649 --- /dev/null +++ b/doc/table_panels_yaml.md @@ -0,0 +1,33 @@ +# Table panels + +> The table panel is very flexible, supporting both multiple modes for time +> series as well as for table, annotation and raw JSON data. It also provides +> date formatting and value formatting and coloring options. +> +> — https://grafana.com/docs/grafana/latest/features/panels/table_panel/ + +```yaml +rows: + - name: "Table panels row" + panels: + - table: + title: Threads + span: 12 + height: 400px + datasource: prometheus-default + targets: + - prometheus: + query: "go_threads" + # hides the column having a label matching the given pattern. + hidden_columns: ["Time"] + time_series_aggregations: + - label: AVG + # valid types are: avg, count, current, min, max + type: avg + - label: Current + type: current +``` + +## That was it! + +[Return to the index to explore the other possibilities of the module](index.md) diff --git a/doc/text_panels_yaml.md b/doc/text_panels_yaml.md index 3870e530..ef06a057 100644 --- a/doc/text_panels_yaml.md +++ b/doc/text_panels_yaml.md @@ -6,7 +6,6 @@ > — https://grafana.com/docs/grafana/latest/features/panels/text/ ```yaml - rows: - name: "Text panels row" panels: From 18b80437ba1b5e0d22784372ae1ac520e2324d7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Gomez?= Date: Thu, 26 Mar 2020 14:17:41 +0100 Subject: [PATCH 6/8] Graph panels --- doc/graph_panels_yaml.md | 55 ++++++++++++++++++++++++++++++++++++++++ doc/index.md | 1 + 2 files changed, 56 insertions(+) create mode 100644 doc/graph_panels_yaml.md diff --git a/doc/graph_panels_yaml.md b/doc/graph_panels_yaml.md new file mode 100644 index 00000000..9941b661 --- /dev/null +++ b/doc/graph_panels_yaml.md @@ -0,0 +1,55 @@ +# Graph panels + +> The main panel in Grafana is simply named Graph. It provides a very rich set +> of graphing options. +> +> — https://grafana.com/docs/grafana/latest/features/panels/graph/ + +```yaml +rows: + - name: "Graph panels row" + panels: + - graph: + title: HTTP Rate + height: 400px + span: 16 + datasource: prometheus-default + targets: + - prometheus: + query: "rate(promhttp_metric_handler_requests_total[$interval])" + legend: "{{handler}} - {{ code }}" + axes: + left: { unit: short, min: 0, label: Requests } + right: { hidden: true } + + - graph: + title: Heap allocations + height: 400px + span: 16 + datasource: prometheus-default + targets: + - prometheus: + query: "go_memstats_heap_alloc_bytes" + legend: "{{job}}" + ref: A + alert: + title: Too many heap allocations + evaluate_every: 1m + for: 1m + # ID of the notification channel + notify: 1 + message: "Wow, a we're allocating a lot." + # Valid values are: no_data, alerting, keep_state, ok + on_no_data: alerting + # Valid values are: alerting, keep_state + on_execution_error: alerting + if: + - operand: and + # valid `func` values are: avg, sum, count, last, min, max, median, diff, percent_diff + value: {func: avg, ref: A, from: 1m, to: now} + threshold: {above: 23000000} +``` + +## That was it! + +[Return to the index to explore the other possibilities of the module](index.md) diff --git a/doc/index.md b/doc/index.md index 09223b01..4e0d5d63 100644 --- a/doc/index.md +++ b/doc/index.md @@ -14,3 +14,4 @@ * [Annotations](annotations_yaml.md) * [Text panels](text_panels_yaml.md) * [Table panels](table_panels_yaml.md) +* [Graph panels](graph_panels_yaml.md) From edab640b746bc58b50a7c135000266ddb10355d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Gomez?= Date: Thu, 26 Mar 2020 14:23:57 +0100 Subject: [PATCH 7/8] Singlestat panels --- decoder/graph.go | 6 +++--- doc/graph_panels_yaml.md | 8 ++++++-- doc/index.md | 1 + doc/singlestat_panels_yaml.md | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 doc/singlestat_panels_yaml.md diff --git a/decoder/graph.go b/decoder/graph.go index c5e3ddec..194799b8 100644 --- a/decoder/graph.go +++ b/decoder/graph.go @@ -175,11 +175,11 @@ func (a graphAlert) toOptions() ([]alert.Option, error) { } type alertThreshold struct { - HasNoValue bool + HasNoValue bool `yaml:"has_no_value"` Above *float64 Below *float64 - OutsideRange [2]float64 - WithinRange [2]float64 + OutsideRange [2]float64 `yaml:"outside_range"` + WithinRange [2]float64 `yaml:"within_range"` } func (threshold alertThreshold) toOption() (alert.ConditionOption, error) { diff --git a/doc/graph_panels_yaml.md b/doc/graph_panels_yaml.md index 9941b661..e3d173e9 100644 --- a/doc/graph_panels_yaml.md +++ b/doc/graph_panels_yaml.md @@ -1,7 +1,7 @@ # Graph panels -> The main panel in Grafana is simply named Graph. It provides a very rich set -> of graphing options. +> The main panel in Grafana is named Graph. It provides a very rich set of +> graphing options. > > — https://grafana.com/docs/grafana/latest/features/panels/graph/ @@ -48,6 +48,10 @@ rows: # valid `func` values are: avg, sum, count, last, min, max, median, diff, percent_diff value: {func: avg, ref: A, from: 1m, to: now} threshold: {above: 23000000} + # threshold: {has_no_value: true} + # threshold: {below: 23000000} + # threshold: {outside_range: [23000000, 26000000]} + # threshold: {within_range: [23000000, 26000000]} ``` ## That was it! diff --git a/doc/index.md b/doc/index.md index 4e0d5d63..1c0910c7 100644 --- a/doc/index.md +++ b/doc/index.md @@ -15,3 +15,4 @@ * [Text panels](text_panels_yaml.md) * [Table panels](table_panels_yaml.md) * [Graph panels](graph_panels_yaml.md) +* [Singlestat panels](singlestat_panels_yaml.md) diff --git a/doc/singlestat_panels_yaml.md b/doc/singlestat_panels_yaml.md new file mode 100644 index 00000000..cf6e4c13 --- /dev/null +++ b/doc/singlestat_panels_yaml.md @@ -0,0 +1,33 @@ +# Singlestat panels + +> The Singlestat Panel allows you to show the one main summary stat of a SINGLE +> series. It reduces the series into a single number (by looking at the max, +> min, average, or sum of values in the series). Singlestat also provides +> thresholds to color the stat or the Panel background. It can also translate +> the single number into a text value, and show a sparkline summary of the series. +> +> — https://grafana.com/docs/grafana/latest/features/panels/singlestat/ + +```yaml +rows: + - name: "Graph panels row" + panels: + - single_stat: + title: Heap Allocations + span: 12 + height: 400px + datasource: prometheus-default + targets: + - prometheus: + query: 'go_memstats_heap_alloc_bytes{job="prometheus"}' + unit: bytes + thresholds: ["26000000", "28000000"] + # valie values are: value, background + color: ["value"] + # valid values are: bottom, full + sparkline: bottom +``` + +## That was it! + +[Return to the index to explore the other possibilities of the module](index.md) From 5d98ac25b3626b6ea20a2a21c3bf8b234f136f22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Gomez?= Date: Thu, 26 Mar 2020 14:27:59 +0100 Subject: [PATCH 8/8] Add alexjs config --- .alexrc | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .alexrc diff --git a/.alexrc b/.alexrc new file mode 100644 index 00000000..605c1912 --- /dev/null +++ b/.alexrc @@ -0,0 +1,3 @@ +{ + "allow": ["color"] +}