Build a Panel Plugin

Introduction

Panels are the building blocks of Grafana. They allow you to visualize data in different ways. While Grafana has several types of panels already built-in, you can also build your own panel, to add support other visualizations.

For more information about panels, refer to the documentation on Panels.

What you’ll build

In this tutorial, you’ll build a simple, but complete panel that will visualize health of a service through the use of color.

What you’ll learn

  • How to create a plugin

What you’ll need

  • Grafana version 7.0+
  • NodeJS
  • yarn

Set up your environment

Before you can get started building plugins, you need to set up your environment for plugin development.

To discover plugins, Grafana scans a plugin directory, the location of which depends on your operating system.

1. Create a directory called grafana-plugins in your preferred workspace.

2. Find the plugins property in the Grafana configuration file and set the plugins property to the path of your grafana-plugins directory. Refer to the Grafana configuration documentation for more information.

[paths]
plugins = "/path/to/grafana-plugins"

Restart Grafana if it’s already running, to load the new configuration.

Alternative method: Docker

If you don’t want to install Grafana on your local machine, you can use Docker. To set up Grafana for plugin development using Docker, run the following command:

docker run -d -p 3000:3000 -v "$(pwd)"/grafana-plugins:/var/lib/grafana/plugins --name=grafana grafana/grafana

Since Grafana only loads plugins on start-up, you need to restart the container whenever you add or remove a plugin.

docker restart grafana

Create a new plugin

Tooling for modern web development can be tricky to wrap your head around. While you certainly can write you own webpack configuration, for this guide, you’ll be using grafana-toolkit.

grafana-toolkit is a CLI application that simplifies Grafana plugin development, so that you can focus on code. The toolkit takes care of building and testing for you.

1. In the plugin directory, create a panel plugin from template using the plugin:create command:

npx @grafana/toolkit plugin:create my-plugin

2. Change directory.

cd my-plugin

3. Download necessary dependencies:

yarn install

4. Build the plugin:

yarn dev

5. Restart the Grafana server for Grafana to discover your plugin.

6. Open Grafana and go to Configuration -> Plugins. Make sure that your plugin is there.

By default, Grafana logs whenever it discovers a plugin:

INFO[01-01|12:00:00] Registering plugin       logger=plugins name=my-plugin

Anatomy of a plugin

Plugins come in different shapes and sizes. Before we dive deeper, let’s look at some of the properties that are shared by all of them.

Every plugin you create will require at least two files: plugin.json and module.ts.

plugin.json

When Grafana starts, it scans the plugin directory for any subdirectory that contains a plugin.json file. The plugin.json file contains information about your plugin, and tells Grafana about what capabilities and dependencies your plugin needs.

While certain plugin types can have specific configuration options, let’s look at the mandatory ones:

  • type tells Grafana what type of plugin to expect. Grafana supports three types of plugins: panel, datasource, and app.
  • name is what users will see in the list of plugins. If you’re creating a data source, this is typically the name of the database it connects to, such as Prometheus, PostgreSQL, or Stackdriver.
  • id uniquely identifies your plugin, and should start with your GitHub username, to avoid clashing with other plugins.

To see all the available configuration settings for the plugin.json, refer to the plugin.json Schema.

module.ts

After discovering your plugin, Grafana loads the module.ts file, the entrypoint for your plugin. module.ts exposes the implementation of your plugin, which depends on the type of plugin you’re building.

Specifically, module.ts needs to expose an object that extends GrafanaPlugin, and can be any of the following:

Panel plugins

Since Grafana 6.x, panels are ReactJS components. The simplest panel consists of a single function, the render function, which returns the content of the panel.

Prior to Grafana 6.0, plugins were written in AngularJS. Even though we still support plugins written in AngularJS, we highly recommend that you write new plugins using ReactJS.

The render function

The render function in SimplePanel.tsx determines how Grafana displays the panel in a dashboard.

Panel properties

The PanelProps interface exposes runtime information about the panel, such as panel dimensions, and the current time range.

You can access the panel properties through this.props, as seen in your plugin.

SimplePanel.tsx

const { options, data, width, height } = this.props;

Development workflow

Next, you’ll learn the basic workflow of making a change to your panel, building it, and reloading Grafana to reflect the change you made.

First, you need to add your panel to a dashboard:

  1. Open Grafana in your browser.
  2. Create a new dashboard, and select Choose Visualization in the New Panel view.
  3. Select your panel from the list of visualizations.
  4. Save the dashboard.

Now that you can view your panel, make a change to the panel plugin:

  1. In the panel render function, change the fill color of the circle.
  2. Run yarn dev to build the plugin.
  3. In the browser, reload Grafana with the new changes.

Configure your panel

Sometimes you want to offer the users of your panel to configure the behavior of your plugin. By adding a panel editor to your plugin, your panel will be able to accept user input, or options.

A panel editor is a React component that extends PureComponent<PanelEditorProps<SimpleOptions>>. Here, SimpleOptions is a TypeScript interface that defines the available options.

export const defaults: SimpleOptions = {
  text: 'The default text!',
};

Just like the panel itself, the panel editor is a React component, which returns a form that lets users update the value of the options defined by SimpleOptions.

SimpleEditor.tsx

<FormField label="Text" labelWidth={5} inputWidth={20} type="text" onChange={this.onTextChanged} value={options.text || ''} />

The onChange attribute on the FormField lets you update the panel properties. Here, onTextChanged is a function that updates the panel properties whenever the value of the FormField changes.

You can update the value of an option, by calling this.props.onOptionsChange:

onTextChanged = ({ target }: any) => {
    this.props.onOptionsChange({ ...this.props.options, text: target.value });
  };

Access time series data

Most panels visualize dynamic data from a Grafana data source. You’ve already seen that the this.props object provides useful data to your panel. It also contains the results from a data source query, which you can access through the data property:

const { data } = this.props;

Data frames

Data sources in Grafana return the results of a query in a format called data frames. A data frame is a columnar data structure, which means values are organized by fields, rather than by records.

Columnar data is a common occurrence in analytics, as it can greatly reduce the amount data read.

Here’s an example of what a query result that contains a data frame can look like:

{
  series: [
    {
      name: "My data frame",
      fields: [
        {
          name: "Time",
          type: "time",
          values: [1576578517623, 1576578518236, 1576578519714]
        },
        {
          name: "Value",
          type: "number",
          values: [0.0, 1.0, 2.0]
        }
      ],
      length: 3,
    }
  ]
}

The current panel implementation only displays the number of series returned. Try changing it to display the current value, i.e. the last value in a series.

Congratulations

Congratulations, you made it to the end of this tutorial!