15. January 2020
5 min

Grafana Dashboards as Code with Grafonnet

Are you annoyed by maintaining your Grafana dashboards via UI or is the update process of your dashboard JSON files becoming a mess? Find out how Grafana dashboards can be managed as code using Grafonnet.
Grafana and Code Title

What is Grafonnet?

In case you already know what Grafonnet and Jsonnet are, feel free to skip this part and continue below. For those who don’t know: Grafonnet is a Jsonnet library – with Jsonnet being a JSON extension to create files using abstractions such as variables, functions, conditionals and more. Grafonnet consists of different functions we can use to create the JSON objects required to compose Grafana dashboards or panels. The resulting JSON files will then be imported into Grafana. You can find the library on GitHub and if you need a deeper insight into Jsonnet, they have a nice tutorial on their webpage.

Creating a Dashboard with Grafonnet

Back to Grafonnet: As mentioned before, the library exposes functions we can use to define our Grafana dashboards. First, we need to import Grafonnet. Grafana.libsonnet works as an entry point and exposes all required functions and interfaces from the library files. In my case, finding out how to use the functions resulted in looking at each source file manually since I didn’t find any documentation. It’s not too much to look at, so no need to worry.

The code above creates a new dashboard object requiring only a title. Other parameters are predefined and can be specified if necessary. After compiling $ jsonnet -o output.json input.jsonnet , the result can be imported into Grafana. There is not much to see yet though.

Adding Template Variables

Before adding panels I decided to start with adding template variables to my dashboard. Our dashboard object provides the functions addTemplate() and addTemplates(), which either take a template object or an array of them.

Adding Panels in Grafonnet

There is not much to see now either, so let’s add some panels. Panel objects are being added similar to template variables, by using addPanel() or addPanels(). In addition to creating the panel objects, we specify their position by adding a “gridPos” attribute. Below is the additional code to above for adding one text and graph panel.

My graph panel has no data points yet though. By using addTarget() which is exposed by the panel object we can add a target object. The following code shows how a Prometheus-target object can be added while the picture below shows how my dashboard looked like after adding two additional panels and their respective targets.

3 Grafana Panels in a line

Adding Rows in Grafonnet

Instead of displaying all services within one graph, we’re using a row to grant each service its own graphs. The panels can either be nested within the row object, in case of the row being collapsed or added after if the row shouldn’t be collapsed. The code below shows how my dashboard code looks like with a non-collapsed row and the three panels.

Custom Functions for Reusability

Well, the code above is not pretty nor easy. Having multiple dashboards and panels will probably exceed what one can grasp and making changes will get just as time-consuming as making changes in the UI is. However, this is where Jsonnet comes handy – why not create a small own library? Using reusable functions will make the code not just easier to read but easier to maintain as well.

It’s a balancing act. Using a custom function which gets a title and an array of panels to create dashboard and template object on its own will result in not being able to configure anything besides the title of the dashboard while calling dashboard.new() in each file manually might result in the need of changing each file separately.

As an example, I wrote a custom function returning the template object. Additionally, I stored the input for the 3 graph panels within an array and iterate over it to create the panel objects to have an easier overview of the panels. Downside here: the more different and customized panels I need, the more complex my iteration gets. Below is how the code for my dashboard file as well as a picture of how the dashboard itself looks like now. If you want to peek at everything else as well you can do this here.

Grafana Rows with Panels

Conclusion

If using Grafana UI to generate dashboards is too tiring or time extensive, Grafonnet might be worth considering when using lots of similar dashboards or panels as long as you find the right balance between customizing and reusing your custom templates. On the other hand, all changes will need to be done within the Jsonnet files since changes within the UI won’t change the corresponding file.

So, how do you create your Grafana dashboards?