Revert "Add Grafana tutorials originally from tutorials repository" (#62283)

Revert "Add Grafana tutorials originally from tutorials repository (#62124)"

This reverts commit f98ad926ac.
pull/62238/head^2
Jack Baldry 2 years ago committed by GitHub
parent 5ff94e528b
commit a54d18c1f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 40
      docs/sources/shared/tutorials/create-plugin.md
  2. 29
      docs/sources/shared/tutorials/plugin-anatomy.md
  3. 77
      docs/sources/shared/tutorials/publish-your-plugin.md
  4. 34
      docs/sources/shared/tutorials/set-up-environment.md
  5. 9
      docs/sources/tutorials/_index.md
  6. 180
      docs/sources/tutorials/build-a-data-source-backend-plugin/index.md
  7. 372
      docs/sources/tutorials/build-a-data-source-plugin/index.md
  8. 235
      docs/sources/tutorials/build-a-panel-plugin-with-d3/index.md
  9. 259
      docs/sources/tutorials/build-a-panel-plugin/index.md
  10. 164
      docs/sources/tutorials/build-a-streaming-data-source-plugin/index.md
  11. 208
      docs/sources/tutorials/build-an-app-plugin/index.md
  12. 331
      docs/sources/tutorials/create-alerts-from-flux-queries/index.md
  13. 236
      docs/sources/tutorials/create-users-and-teams/index.md
  14. 354
      docs/sources/tutorials/grafana-fundamentals/index.md
  15. 146
      docs/sources/tutorials/iis/index.md
  16. 147
      docs/sources/tutorials/install-grafana-on-raspberry-pi/index.md
  17. 118
      docs/sources/tutorials/integrate-hubot/index.md
  18. 260
      docs/sources/tutorials/provision-dashboards-and-data-sources/index.md
  19. 222
      docs/sources/tutorials/run-grafana-behind-a-proxy/index.md
  20. 101
      docs/sources/tutorials/stream-metrics-from-telegraf-to-grafana/index.md

@ -1,40 +0,0 @@
---
title: Create Plugin
---
Tooling for modern web development can be tricky to wrap your head around. While you certainly can write your own webpack configuration, for this guide, you'll be using grafana create-plugin tool
Grafana [create-plugin tool](https://www.npmjs.com/package/@grafana/create-plugin) is a CLI application that simplifies Grafana plugin development, so that you can focus on code. The tool scaffolds a starter plugin and all the required configuration for you.
1. In the plugin directory, create a plugin from template using create-plugin:
```
npx @grafana/create-plugin
```
1. Change directory to your newly created plugin:
```
cd my-plugin
```
1. Install the dependencies:
```
yarn install
```
1. Build the plugin:
```
yarn dev
```
1. Restart the Grafana server for Grafana to discover your plugin.
1. 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
```

@ -1,29 +0,0 @@
---
title: Plugin Anatomy
---
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 Grafana username, to avoid clashing with other plugins. [Sign up for a Grafana account](/signup/) to claim your username.
To see all the available configuration settings for the `plugin.json`, refer to the [plugin.json Schema](/docs/grafana/latest/plugins/developing/plugin.json/).
### 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](https://github.com/grafana/grafana/blob/08bf2a54523526a7f59f7c6a8dafaace79ab87db/packages/grafana-data/src/types/plugin.ts#L124), and can be any of the following:
- [PanelPlugin](https://github.com/grafana/grafana/blob/08bf2a54523526a7f59f7c6a8dafaace79ab87db/packages/grafana-data/src/types/panel.ts#L73)
- [DataSourcePlugin](https://github.com/grafana/grafana/blob/08bf2a54523526a7f59f7c6a8dafaace79ab87db/packages/grafana-data/src/types/datasource.ts#L33)
- [AppPlugin](https://github.com/grafana/grafana/blob/45b7de1910819ad0faa7a8aeac2481e675870ad9/packages/grafana-data/src/types/app.ts#L27)

@ -1,77 +0,0 @@
---
title: Package your plugin
---
Once you're happy with your plugin, it's time to package it, and submit to the plugin repository.
For users to be able to use the plugin without building it themselves, you need to make a production build of the plugin, and commit to a release branch in your repository.
To submit a plugin to the plugin repository, you need to create a release of your plugin. While we recommend following the branching strategy outlined below, you're free to use one that makes more sense to you.
#### Create a plugin release
Let's create version 0.1.0 of our plugin.
1. Create a branch called `release-0.1.x`.
```
git checkout -b release-0.1.x
```
1. Do a production build.
```
yarn build
```
1. Add the `dist` directory.
```
git add -f dist
```
1. Create the release commit.
```
git commit -m "Release v0.1.0"
```
1. Create a release tag.
```
git tag -a v0.1.0 -m "Create release tag v0.1.0"
```
1. Push to GitHub. `follow-tags` tells Git to push the release tag along with our release branch.
```
git push --set-upstream origin release-0.1.x --follow-tags
```
#### Submit the plugin
For a plugin to be published on [Grafana Plugins](/grafana/plugins/), it needs to be added to the [grafana-plugin-repository](https://github.com/grafana/grafana-plugin-repository).
1. Fork the [grafana-plugin-repository](https://github.com/grafana/grafana-plugin-repository)
1. Add your plugin to the `repo.json` file in the project root directory:
```json
{
"id": "<plugin id>",
"type": "<plugin type>",
"url": "https://github.com/<username>/my-plugin",
"versions": [
{
"version": "<version>",
"commit": "<git sha>",
"url": "https://github.com/<username>/my-plugin"
}
]
}
```
1. [Create a pull request](https://github.com/grafana/grafana-plugin-repository/pull/new/master).
Once your plugin has been accepted, it'll be published on [Grafana Plugin](/grafana/plugins/), available for anyone to [install](/docs/grafana/latest/plugins/installation/)!
> We're auditing every plugin that's added to make sure it's ready to be published. This means that it might take some time before your plugin is accepted. We're working on adding more automated tests to improve this process.

@ -1,34 +0,0 @@
---
title: Set up 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.
1. 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](/docs/grafana/latest/installation/configuration/#plugins) for more information.
```ini
[paths]
plugins = "/path/to/grafana-plugins"
```
1. 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](https://www.docker.com).
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:7.0.0
```
Since Grafana only loads plugins on start-up, you need to restart the container whenever you add or remove a plugin.
```
docker restart grafana
```

@ -1,9 +0,0 @@
---
title: 'Tutorials'
menuTitle: 'Tutorials'
description: 'Grafana tutorials'
---
# Tutorials
{{< section >}}

@ -1,180 +0,0 @@
---
title: Build a data source backend plugin
summary: Create a backend for your data source plugin.
description: Create a backend for your data source plugin.
id: build-a-data-source-backend-plugin
categories: ['plugins']
tags: ['beginner']
status: Published
authors: ['grafana_labs']
Feedback Link: https://github.com/grafana/tutorials/issues/new
weight: 75
---
## Introduction
Grafana supports a wide range of data sources, including Prometheus, MySQL, and even Datadog. There's a good chance you can already visualize metrics from the systems you have set up. In some cases, though, you already have an in-house metrics solution that you’d like to add to your Grafana dashboards. This tutorial teaches you to build a support for your data source.
For more information about backend plugins, refer to the documentation on [Backend plugins](/docs/grafana/latest/developers/plugins/backend/).
In this tutorial, you'll:
- Build a backend for your data source
- Implement a health check for your data source
- Enable Grafana Alerting for your data source
{{% class "prerequisite-section" %}}
#### Prerequisites
- Knowledge about how data sources are implemented in the frontend.
- Grafana 7.0
- Go ([Version](https://github.com/grafana/plugin-tools/blob/main/packages/create-plugin/templates/backend/go.mod#L3))
- [Mage](https://magefile.org/)
- NodeJS ([Version](https://github.com/grafana/plugin-tools/blob/main/packages/create-plugin/templates/common/package.json#L66))
- yarn
{{% /class %}}
## Set up your environment
{{< docs/shared lookup="tutorials/set-up-environment.md" source="grafana" >}}
## Create a new plugin
To build a backend for your data source plugin, Grafana requires a binary that it can execute when it loads the plugin during start-up. In this guide, we will build a binary using the [Grafana plugin SDK for Go](/docs/grafana/latest/developers/plugins/backend/grafana-plugin-sdk-for-go/).
The easiest way to get started is to use the Grafana [create-plugin tool](https://www.npmjs.com/package/@grafana/create-plugin). Navigate to the plugin folder that you configured in step 1 and type:
```
npx @grafana/create-plugin
```
Follow the steps and select **datasource** as your plugin type and answer **yes** when prompted to create a backend for your plugin.
```bash
cd my-plugin
```
Install frontend dependencies and build frontend parts of the plugin to _dist_ directory:
```bash
yarn install
yarn build
```
Run the following to update [Grafana plugin SDK for Go](/docs/grafana/latest/developers/plugins/backend/grafana-plugin-sdk-for-go/) dependency to the latest minor version:
```bash
go get -u github.com/grafana/grafana-plugin-sdk-go
go mod tidy
```
Build backend plugin binaries for Linux, Windows and Darwin to _dist_ directory:
```bash
mage -v
```
Now, let's verify that the plugin you've built so far can be used in Grafana when creating a new data source:
1. Restart your Grafana instance.
1. Open Grafana in your web browser.
1. Navigate via the side-menu to **Configuration** -> **Data Sources**.
1. Click **Add data source**.
1. Find your newly created plugin and select it.
1. Enter a name and then click **Save & Test** (ignore any errors reported for now).
You now have a new data source instance of your plugin that is ready to use in a dashboard:
1. Navigate via the side-menu to **Create** -> **Dashboard**.
1. Click **Add new panel**.
1. In the query tab, select the data source you just created.
1. A line graph is rendered with one series consisting of two data points.
1. Save the dashboard.
### Troubleshooting
#### Grafana doesn't load my plugin
By default, Grafana requires backend plugins to be signed. To load unsigned backend plugins, you need to
configure Grafana to [allow unsigned plugins](/docs/grafana/latest/plugins/plugin-signature-verification/#allow-unsigned-plugins).
For more information, refer to [Plugin signature verification](/docs/grafana/latest/plugins/plugin-signature-verification/#backend-plugins).
## Anatomy of a backend plugin
The folders and files used to build the backend for the data source are:
| file/folder | description |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Magefile.go` | It’s not a requirement to use mage build files, but we strongly recommend using it so that you can use the build targets provided by the plugin SDK. |
| `/go.mod ` | Go modules dependencies, [reference](https://golang.org/cmd/go/#hdr-The_go_mod_file) |
| `/src/plugin.json` | A JSON file describing the backend plugin |
| `/pkg/main.go` | Starting point of the plugin binary. |
#### plugin.json
The [plugin.json](/docs/grafana/latest/developers/plugins/metadata/) file is required for all plugins. When building a backend plugin these properties are important:
| property | description |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| backend | Should be set to `true` for backend plugins. This tells Grafana that it should start a binary when loading the plugin. |
| executable | This is the name of the executable that Grafana expects to start, see [plugin.json reference](/docs/grafana/latest/developers/plugins/metadata/) for details. |
| alerting | Should be set to `true` if your backend datasource supports alerting. |
In the next step we will look at the query endpoint!
## Implement data queries
We begin by opening the file `/pkg/plugin/plugin.go`. In this file you will see the `SampleDatasource` struct which implements the [backend.QueryDataHandler](https://pkg.go.dev/github.com/grafana/grafana-plugin-sdk-go/backend?tab=doc#QueryDataHandler) interface. The `QueryData` method on this struct is where the data fetching happens for a data source plugin.
Each request contains multiple queries to reduce traffic between Grafana and plugins. So you need to loop over the slice of queries, process each query, and then return the results of all queries.
In the tutorial we have extracted a method named `query` to take care of each query model. Since each plugin has their own unique query model, Grafana sends it to the backend plugin as JSON. Therefore the plugin needs to `Unmarshal` the query model into something easier to work with.
As you can see the sample only returns static numbers. Try to extend the plugin to return other types of data.
You can read more about how to [build data frames in our docs](/docs/grafana/latest/developers/plugins/data-frames/).
## Add support for health checks
Implementing the health check handler allows Grafana to verify that a data source has been configured correctly.
When editing a data source in Grafana's UI, you can **Save & Test** to verify that it works as expected.
In this sample data source, there is a 50% chance that the health check will be successful. Make sure to return appropriate error messages to the users, informing them about what is misconfigured in the data source.
Open `/pkg/plugin/plugin.go`. In this file you'll see that the `SampleDatasource` struct also implements the [backend.CheckHealthHandler](https://pkg.go.dev/github.com/grafana/grafana-plugin-sdk-go/backend?tab=doc#CheckHealthHandler) interface. Navigate to the `CheckHealth` method to see how the health check for this sample plugin is implemented.
## Enable Grafana Alerting
1. Open _src/plugin.json_.
1. Add the top level `backend` property with a value of `true` to specify that your plugin supports Grafana Alerting, e.g.
```json
{
...
"backend": true,
"executable": "gpx_simple_datasource_backend",
"alerting": true,
"info": {
...
}
```
1. Rebuild frontend parts of the plugin to _dist_ directory:
```bash
yarn build
```
1. Restart your Grafana instance.
1. Open Grafana in your web browser.
1. Open the dashboard you created earlier in the _Create a new plugin_ step.
1. Edit the existing panel.
1. Click on the _Alert_ tab.
1. Click on _Create Alert_ button.
1. Edit condition and specify _IS ABOVE 10_. Change _Evaluate every_ to _10s_ and clear the _For_ field to make the alert rule evaluate quickly.
1. Save the dashboard.
1. After some time the alert rule evaluates and transitions into _Alerting_ state.
## Summary
In this tutorial you created a backend for your data source plugin.

@ -1,372 +0,0 @@
---
title: Build a data source plugin
summary: Create a plugin to add support for your own data sources.
description: Create a plugin to add support for your own data sources.
id: build-a-data-source-plugin
categories: ['plugins']
tags: ['beginner']
status: Published
authors: ['grafana_labs']
Feedback Link: https://github.com/grafana/tutorials/issues/new
weight: 70
---
## Introduction
Grafana supports a wide range of data sources, including Prometheus, MySQL, and even Datadog. There's a good chance you can already visualize metrics from the systems you have set up. In some cases, though, you already have an in-house metrics solution that you’d like to add to your Grafana dashboards. This tutorial teaches you to build a support for your data source.
In this tutorial, you'll:
- Build a data source to visualize a sine wave
- Construct queries using the query editor
- Configure your data source using the config editor
{{% class "prerequisite-section" %}}
### Prerequisites
- Grafana >=7.0
- NodeJS >=14
- yarn
{{% /class %}}
## Set up your environment
{{< docs/shared lookup="tutorials/set-up-environment.md" source="grafana" >}}
## Create a new plugin
{{< docs/shared lookup="tutorials/create-plugin.md" source="grafana" >}}
## Anatomy of a plugin
{{< docs/shared lookup="tutorials/plugin-anatomy.md" source="grafana" >}}
## Data source plugins
A data source in Grafana must extend the `DataSourceApi` interface, which requires you to defines two methods: `query` and `testDatasource`.
### The `query` method
The `query` method is the heart of any data source plugin. It accepts a query from the user, retrieves the data from an external database, and returns the data in a format that Grafana recognizes.
```
async query(options: DataQueryRequest<MyQuery>): Promise<DataQueryResponse>
```
The `options` object contains the queries, or _targets_, that the user made, along with context information, like the current time interval. Use this information to query an external database.
> The term _target_ originates from Graphite, and the earlier days of Grafana when Graphite was the only supported data source. As Grafana gained support for more data sources, the term "target" became synonymous with any type of query.
### Test your data source
`testDatasource` implements a health check for your data source. For example, Grafana calls this method whenever the user clicks the **Save & Test** button, after changing the connection settings.
```
async testDatasource()
```
## Data frames
Nowadays there are countless of different databases, each with their own ways of querying data. To be able to support all the different data formats, Grafana consolidates the data into a unified data structure called _data frames_.
Let's see how to create and return a data frame from the `query` method. In this step, you'll change the code in the starter plugin to return a [sine wave](https://en.wikipedia.org/wiki/Sine_wave).
1. In the current `query` method, remove the code inside the `map` function.
The `query` method now look like this:
```ts
async query(options: DataQueryRequest<MyQuery>): Promise<DataQueryResponse> {
const { range } = options;
const from = range!.from.valueOf();
const to = range!.to.valueOf();
const data = options.targets.map(target => {
// Your code goes here.
});
return { data };
}
```
1. In the `map` function, use the `lodash/defaults` package to set default values for query properties that haven't been set:
```ts
const query = defaults(target, defaultQuery);
```
1. Create a data frame with a time field and a number field:
```ts
const frame = new MutableDataFrame({
refId: query.refId,
fields: [
{ name: 'time', type: FieldType.time },
{ name: 'value', type: FieldType.number },
],
});
```
`refId` needs to be set to tell Grafana which query that generated this date frame.
Next, we'll add the actual values to the data frame. Don't worry about the math used to calculate the values.
1. Create a couple of helper variables:
```ts
// duration of the time range, in milliseconds.
const duration = to - from;
// step determines how close in time (ms) the points will be to each other.
const step = duration / 1000;
```
1. Add the values to the data frame:
```ts
for (let t = 0; t < duration; t += step) {
frame.add({ time: from + t, value: Math.sin((2 * Math.PI * t) / duration) });
}
```
The `frame.add()` accepts an object where the keys corresponds to the name of each field in the data frame.
1. Return the data frame:
```ts
return frame;
```
1. Rebuild the plugin and try it out.
Your data source is now sending data frames that Grafana can visualize. Next, we'll look at how you can control the frequency of the sine wave by defining a _query_.
> In this example, we're generating timestamps from the current time range. This means that you'll get the same graph no matter what time range you're using. In practice, you'd instead use the timestamps returned by your database.
## Define a query
Most data sources offer a way to query specific data. MySQL and PostgreSQL use SQL, while Prometheus has its own query language, called _PromQL_. No matter what query language your databases are using, Grafana lets you build support for it.
Add support for custom queries to your data source, by implementing your own _query editor_, a React component that enables users to build their own queries, through a user-friendly graphical interface.
A query editor can be as simple as a text field where the user edits the raw query text, or it can provide a more user-friendly form with drop-down menus and switches, that later gets converted into the raw query text before it gets sent off to the database.
### Define the query model
The first step in designing your query editor is to define its _query model_. The query model defines the user input to your data source.
We want to be able to control the frequency of the sine wave, so let's add another property.
1. Add a new number property called `frequency` to the query model:
**src/types.ts**
```ts
export interface MyQuery extends DataQuery {
queryText?: string;
constant: number;
frequency: number;
}
```
1. Set a default value to the new `frequency` property:
```ts
export const defaultQuery: Partial<MyQuery> = {
constant: 6.5,
frequency: 1.0,
};
```
### Bind the model to a form
Now that you've defined the query model you wish to support, the next step is to bind the model to a form. The `FormField` is a text field component from `grafana/ui` that lets you register a listener which will be invoked whenever the form field value changes.
1. Add a new form field to the query editor to control the new frequency property.
**QueryEditor.tsx**
```ts
const { queryText, constant, frequency } = query;
```
```ts
<FormField width={4} value={frequency} onChange={this.onFrequencyChange} label="Frequency" type="number" />
```
1. Add a event listener for the new property.
```ts
onFrequencyChange = (event: ChangeEvent<HTMLInputElement>) => {
const { onChange, query, onRunQuery } = this.props;
onChange({ ...query, frequency: parseFloat(event.target.value) });
// executes the query
onRunQuery();
};
```
The registered listener, `onFrequencyChange`, calls `onChange` to update the current query with the value from the form field.
`onRunQuery();` tells Grafana to run the query after each change. For fast queries, this is recommended to provide a more responsive experience.
### Use the property
The new query model is now ready to use in our `query` method.
1. In the `query` method, use the `frequency` property to adjust our equation.
```ts
frame.add({ time: from + t, value: Math.sin((2 * Math.PI * query.frequency * t) / duration) });
```
## Configure your data source
To access a specific data source, you often need to configure things like hostname, credentials, or authentication method. A _config editor_ lets your users configure your data source plugin to fit their needs.
The config editor looks similar to the query editor, in that it defines a model and binds it to a form.
Since we're not actually connecting to an external database in our sine wave example, we don't really need many options. To show you how you can add an option however, we're going to add the _wave resolution_ as an option.
The resolution controls how close in time the data points are to each other. A higher resolution means more points closer together, at the cost of more data being processed.
### Define the options model
1. Add a new number property called `resolution` to the options model.
**types.ts**
```ts
export interface MyDataSourceOptions extends DataSourceJsonData {
path?: string;
resolution?: number;
}
```
### Bind the model to a form
Just like query editor, the form field in the config editor calls the registered listener whenever the value changes.
1. Add a new form field to the query editor to control the new resolution option.
**ConfigEditor.tsx**
```ts
<div className="gf-form">
<FormField
label="Resolution"
onChange={this.onResolutionChange}
value={jsonData.resolution || ''}
placeholder="Enter a number"
/>
</div>
```
1. Add a event listener for the new option.
```ts
onResolutionChange = (event: ChangeEvent<HTMLInputElement>) => {
const { onOptionsChange, options } = this.props;
const jsonData = {
...options.jsonData,
resolution: parseFloat(event.target.value),
};
onOptionsChange({ ...options, jsonData });
};
```
The `onResolutionChange` listener calls `onOptionsChange` to update the current options with the value from the form field.
### Use the option
1. Create a property called `resolution` to the `DataSource` class.
```ts
export class DataSource extends DataSourceApi<MyQuery, MyDataSourceOptions> {
resolution: number;
constructor(instanceSettings: DataSourceInstanceSettings<MyDataSourceOptions>) {
super(instanceSettings);
this.resolution = instanceSettings.jsonData.resolution || 1000.0;
}
// ...
```
1. In the `query` method, use the `resolution` property to calculate the step size.
**src/DataSource.ts**
```ts
const step = duration / this.resolution;
```
## Get data from an external API
So far, you've generated the data returned by the data source. A more realistic use case would be to fetch data from an external API.
While you can use something like [axios](https://github.com/axios/axios) or the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) to make requests, we recommend using the [`getBackendSrv`](/docs/grafana/latest/packages_api/runtime/getbackendsrv/) function from the [grafana/runtime](/docs/grafana/latest/packages_api/runtime/) package.
The main advantage of `getBackendSrv` is that it proxies requests through the Grafana server rather making the request from the browser. This is strongly recommended when making authenticated requests to an external API. For more information on authenticating external requests, refer to [Add authentication for data source plugins](/docs/grafana/latest/developers/plugins/add-authentication-for-data-source-plugins/).
1. Import `getBackendSrv`.
**src/DataSource.ts**
```ts
import { getBackendSrv } from '@grafana/runtime';
```
1. Create a helper method `doRequest` and use the `datasourceRequest` method to make a request to your API. Replace `https://api.example.com/metrics` to point to your own API endpoint.
```ts
async doRequest(query: MyQuery) {
const result = await getBackendSrv().datasourceRequest({
method: "GET",
url: "https://api.example.com/metrics",
params: query,
})
return result;
}
```
1. Make a request for each query. `Promises.all` waits for all requests to finish before returning the data.
```ts
async query(options: DataQueryRequest<MyQuery>): Promise<DataQueryResponse> {
const promises = options.targets.map((query) =>
this.doRequest(query).then((response) => {
const frame = new MutableDataFrame({
refId: query.refId,
fields: [
{ name: "Time", type: FieldType.time },
{ name: "Value", type: FieldType.number },
],
});
response.data.forEach((point: any) => {
frame.appendRow([point.time, point.value]);
});
return frame;
})
);
return Promise.all(promises).then((data) => ({ data }));
}
```
## Summary
In this tutorial you built a complete data source plugin for Grafana that uses a query editor to control what data to visualize. You've added a data source option, commonly used to set connection options and more.
### Learn more
Learn how you can improve your plugin even further, by reading our advanced guides:
- [Add support for variables](/docs/grafana/latest/developers/plugins/add-support-for-variables/)
- [Add support for annotations](/docs/grafana/latest/developers/plugins/add-support-for-annotations/)
- [Add support for Explore queries](/docs/grafana/latest/developers/plugins/add-support-for-explore-queries/)
- [Build a logs data source](/docs/grafana/latest/developers/plugins/build-a-logs-data-source-plugin/)

@ -1,235 +0,0 @@
---
title: Build a panel plugin with D3.js
summary: Learn how to use D3.js in your panel plugins.
description: how to use D3.js in your panel plugins.
id: build-a-panel-plugin-with-d3
categories: ['plugins']
tags: ['beginner']
status: Published
authors: ['grafana_labs']
Feedback Link: https://github.com/grafana/tutorials/issues/new
weight: 60
---
## Introduction
Panels are the building blocks of Grafana, and allow you to visualize data in different ways. This tutorial gives you a hands-on walkthrough of creating your own panel using [D3.js](https://d3js.org/).
For more information about panels, refer to the documentation on [Panels](/docs/grafana/latest/features/panels/panels/).
In this tutorial, you'll:
- Build a simple panel plugin to visualize a bar chart.
- Learn how to use D3.js to build a panel using data-driven transformations.
{{% class "prerequisite-section" %}}
### Prerequisites
- Grafana 7.0
- NodeJS 12.x
- yarn
{{% /class %}}
## Set up your environment
{{< docs/shared lookup="tutorials/set-up-environment.md" source="grafana" >}}
## Create a new plugin
{{< docs/shared lookup="tutorials/create-plugin.md" source="grafana" >}}
## Data-driven documents
[D3.js](https://d3js.org/) is a JavaScript library for manipulating documents based on data. It lets you transform arbitrary data into HTML, and is commonly used for creating visualizations.
Wait a minute. Manipulating documents based on data? That's sounds an awful lot like React. In fact, much of what you can accomplish with D3 you can already do with React. So before we start looking at D3, let's see how you can create an SVG from data, using only React.
In **SimplePanel.tsx**, change `SimplePanel` to return an `svg` with a `rect` element.
```ts
export const SimplePanel: React.FC<Props> = ({ options, data, width, height }) => {
const theme = useTheme();
return (
<svg width={width} height={height}>
<rect x={0} y={0} width={10} height={10} fill={theme.palette.greenBase} />
</svg>
);
};
```
One single rectangle might not be very exciting, so let's see how you can create rectangles from data.
1. Create some data that we can visualize.
```ts
const values = [4, 8, 15, 16, 23, 42];
```
1. Calculate the height of each bar based on the height of the panel.
```ts
const barHeight = height / values.length;
```
1. Inside a SVG group, `g`, create a `rect` element for every value in the dataset. Each rectangle uses the value as its width.
```ts
return (
<svg width={width} height={height}>
<g>
{values.map((value, i) => (
<rect x={0} y={i * barHeight} width={value} height={barHeight - 1} fill={theme.palette.greenBase} />
))}
</g>
</svg>
);
```
1. Rebuild the plugin and reload your browser to see the changes you've made.
As you can see, React is perfectly capable of dynamically creating HTML elements. In fact, creating elements using React is often faster than creating them using D3.
So why would you use even use D3? In the next step, we'll see how you can take advantage of D3's data transformations.
## Transform data using D3.js
In this step, you'll see how you can transform data using D3 before rendering it using React.
D3 is already bundled with Grafana, and you can access it by importing the `d3` package. However, we're going to need the type definitions while developing.
1. Install the D3 type definitions:
```bash
yarn add --dev @types/d3
```
1. Import `d3` in **SimplePanel.tsx**.
```ts
import * as d3 from 'd3';
```
In the previous step, we had to define the width of each bar in pixels. Instead, let's use _scales_ from the D3 library to make the width of each bar depend on the width of the panel.
Scales are functions that map a range of values to another range of values. In this case, we want to map the values in our datasets to a position within our panel.
1. Create a scale to map a value between 0 and the maximum value in the dataset, to a value between 0 and the width of the panel. We'll be using this to calculate the width of the bar.
```ts
const scale = d3
.scaleLinear()
.domain([0, d3.max(values) || 0.0])
.range([0, width]);
```
1. Pass the value to the scale function to calculate the width of the bar in pixels.
```ts
return (
<svg width={width} height={height}>
<g>
{values.map((value, i) => (
<rect x={0} y={i * barHeight} width={scale(value)} height={barHeight - 1} fill={theme.palette.greenBase} />
))}
</g>
</svg>
);
```
As you can see, even if we're using React to render the actual elements, the D3 library contains useful tools that you can use to transform your data before rendering it.
## Add an axis
Another useful tool in the D3 toolbox is the ability to generate _axes_. Adding axes to our chart makes it easier for the user to understand the differences between each bar.
Let's see how you can use D3 to add a horizontal axis to your bar chart.
1. Create a D3 axis. Notice that by using the same scale as before, we make sure that the bar width aligns with the ticks on the axis.
```ts
const axis = d3.axisBottom(scale);
```
1. Generate the axis. While D3 needs to generate the elements for the axis, we can encapsulate it by generating them within an anonymous function which we pass as a `ref` to a group element `g`.
```ts
<g
ref={(node) => {
d3.select(node).call(axis as any);
}}
/>
```
By default, the axis renders at the top of the SVG element. We'd like to move it to the bottom, but to do that, we first need to make room for it by decreasing the height of each bar.
1. Calculate the new bar height based on the padded height.
```ts
const padding = 20;
const chartHeight = height - padding;
const barHeight = chartHeight / values.length;
```
1. Translate the axis by adding a transform to the `g` element.
```ts
<g
transform={`translate(0, ${chartHeight})`}
ref={(node) => {
d3.select(node).call(axis as any);
}}
/>
```
Congrats! You've created a simple and responsive bar chart.
## Complete example
```ts
import React from 'react';
import { PanelProps } from '@grafana/data';
import { SimpleOptions } from 'types';
import { useTheme } from '@grafana/ui';
import * as d3 from 'd3';
interface Props extends PanelProps<SimpleOptions> {}
export const SimplePanel: React.FC<Props> = ({ options, data, width, height }) => {
const theme = useTheme();
const values = [4, 8, 15, 16, 23, 42];
const scale = d3
.scaleLinear()
.domain([0, d3.max(values) || 0.0])
.range([0, width]);
const axis = d3.axisBottom(scale);
const padding = 20;
const chartHeight = height - padding;
const barHeight = chartHeight / values.length;
return (
<svg width={width} height={height}>
<g>
{values.map((value, i) => (
<rect x={0} y={i * barHeight} width={scale(value)} height={barHeight - 1} fill={theme.palette.greenBase} />
))}
</g>
<g
transform={`translate(0, ${chartHeight})`}
ref={(node) => {
d3.select(node).call(axis as any);
}}
/>
</svg>
);
};
```
## Summary
In this tutorial you built a panel plugin with D3.js.

@ -1,259 +0,0 @@
---
title: Build a panel plugin
summary: Learn how to create a custom visualization for your dashboards.
description: Learn how to create a custom visualization for your dashboards.
id: build-a-panel-plugin
categories: ['plugins']
tags: ['beginner']
status: Published
authors: ['grafana_labs']
Feedback Link: https://github.com/grafana/tutorials/issues/new
weight: 50
---
## 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 for other visualizations.
For more information about panels, refer to the documentation on [Panels](/docs/grafana/latest/panels/).
{{% class "prerequisite-section" %}}
### Prerequisites
- Grafana >=7.0
- NodeJS >=14
- yarn
{{% /class %}}
## Set up your environment
{{< docs/shared lookup="tutorials/set-up-environment.md" source="grafana" >}}
## Create a new plugin
{{< docs/shared lookup="tutorials/create-plugin.md" source="grafana" >}}
## Anatomy of a plugin
{{< docs/shared lookup="tutorials/plugin-anatomy.md" source="grafana" >}}
## Panel plugins
Since Grafana 6.x, panels are [ReactJS components](https://reactjs.org/docs/components-and-props.html).
Prior to Grafana 6.0, plugins were written in [AngularJS](https://angular.io/). Even though we still support plugins written in AngularJS, we highly recommend that you write new plugins using ReactJS.
### Panel properties
The [PanelProps](https://github.com/grafana/grafana/blob/747b546c260f9a448e2cb56319f796d0301f4bb9/packages/grafana-data/src/types/panel.ts#L27-L40) interface exposes runtime information about the panel, such as panel dimensions, and the current time range.
You can access the panel properties through `props`, as seen in your plugin.
**src/SimplePanel.tsx**
```js
const { options, data, width, height } = 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 changes you made.
First, you need to add your panel to a dashboard:
1. Open Grafana in your browser.
1. Create a new dashboard, and add a new panel.
1. Select your panel from the list of visualization types.
1. Save the dashboard.
Now that you can view your panel, try making a change to the panel plugin:
1. In `SimplePanel.tsx`, change the fill color of the circle.
1. Run `yarn dev` to build the plugin.
1. In the browser, reload Grafana with the new changes.
## Add panel options
Sometimes you want to offer the users of your panel an option to configure the behavior of your plugin. By configuring _panel options_ for your plugin, your panel will be able to accept user input.
In the previous step, you changed the fill color of the circle in the code. Let's change the code so that the plugin user can configure the color from the panel editor.
#### Add an option
Panel options are defined in a _panel options object_. `SimpleOptions` is an interface that describes the options object.
1. In `types.ts`, add a `CircleColor` type to hold the colors the users can choose from:
```
type CircleColor = 'red' | 'green' | 'blue';
```
1. In the `SimpleOptions` interface, add a new option called `color`:
```
color: CircleColor;
```
Here's the updated options definition:
**src/types.ts**
```ts
type SeriesSize = 'sm' | 'md' | 'lg';
type CircleColor = 'red' | 'green' | 'blue';
// interface defining panel options type
export interface SimpleOptions {
text: string;
showSeriesCount: boolean;
seriesCountSize: SeriesSize;
color: CircleColor;
}
```
#### Add an option control
To change the option from the panel editor, you need to bind the `color` option to an _option control_.
Grafana supports a range of option controls, such as text inputs, switches, and radio groups.
Let's create a radio control and bind it to the `color` option.
1. In `src/module.ts`, add the control at the end of the builder:
```ts
.addRadio({
path: 'color',
name: 'Circle color',
defaultValue: 'red',
settings: {
options: [
{
value: 'red',
label: 'Red',
},
{
value: 'green',
label: 'Green',
},
{
value: 'blue',
label: 'Blue',
},
],
}
});
```
The `path` is used to bind the control to an option. You can bind a control to nested option by specifying the full path within a options object, for example `colors.background`.
Grafana builds an options editor for you and displays it in the panel editor sidebar in the **Display** section.
#### Use the new option
You're almost done. You've added a new option and a corresponding control to change the value. But the plugin isn't using the option yet. Let's change that.
1. To convert option value to the colors used by the current theme, add a `switch` statement right before the `return` statement in `SimplePanel.tsx`.
**src/SimplePanel.tsx**
```ts
let color: string;
switch (options.color) {
case 'red':
color = theme.palette.redBase;
break;
case 'green':
color = theme.palette.greenBase;
break;
case 'blue':
color = theme.palette.blue95;
break;
}
```
1. Configure the circle to use the color.
```ts
<g>
<circle style={{ fill: color }} r={100} />
</g>
```
Now, when you change the color in the panel editor, the fill color of the circle changes as well.
## Create dynamic panels using data frames
Most panels visualize dynamic data from a Grafana data source. In this step, you'll create one circle per series, each with a radius equal to the last value in the series.
> To use data from queries in your panel, you need to set up a data source. If you don't have one available, you can use the [TestData DB](/docs/grafana/latest/features/datasources/testdata) data source while developing.
The results from a data source query within your panel are available in the `data` property inside your panel component.
```ts
const { data } = props;
```
`data.series` contains the series returned from a data source query. Each series is represented as a data structure called _data frame_. A data frame resembles a table, where data is stored by columns, or _fields_, instead of rows. Every value in a field share the same data type, such as string, number, or time.
Here's an example of a data frame with a time field, `Time`, and a number field, `Value`:
| Time | Value |
| ------------- | ----- |
| 1589189388597 | 32.4 |
| 1589189406480 | 27.2 |
| 1589189513721 | 15.0 |
Let's see how you can retrieve data from a data frame and use it in your visualization.
1. Get the last value of each field of type `number`, by adding the following to `SimplePanel.tsx`, before the `return` statement:
```ts
const radii = data.series
.map((series) => series.fields.find((field) => field.type === 'number'))
.map((field) => field?.values.get(field.values.length - 1));
```
`radii` will contain the last values in each of the series that are returned from a data source query. You'll use these to set the radius for each circle.
1. Change the `svg` element to the following:
```ts
<svg
className={styles.svg}
width={width}
height={height}
xmlns="http://www.w3.org/2000/svg"
xmlnsXlink="http://www.w3.org/1999/xlink"
viewBox={`0 -${height / 2} ${width} ${height}`}
>
<g fill={color}>
{radii.map((radius, index) => {
const step = width / radii.length;
return <circle r={radius} transform={`translate(${index * step + step / 2}, 0)`} />;
})}
</g>
</svg>
```
Note how we're creating a `<circle>` element for each value in `radii`:
```ts
{
radii.map((radius, index) => {
const step = width / radii.length;
return <circle r={radius} transform={`translate(${index * step + step / 2}, 0)`} />;
});
}
```
We use the `transform` here to distribute the circle horizontally within the panel.
1. Rebuild your plugin and try it out by adding multiple queries to the panel. Refresh the dashboard.
If you want to know more about data frames, check out our introduction to [Data frames](/docs/grafana/latest/developers/plugins/data-frames/).
## Summary
In this tutorial you learned how to create a custom visualization for your dashboards.

@ -1,164 +0,0 @@
---
title: Build a streaming data source backend plugin
summary: Create a backend for your data source plugin with streaming capabilities.
description: Create a backend for your data source plugin with streaming capabilities.
id: build-a-streaming-data-source-backend-plugin
categories: ['plugins']
tags: ['beginner']
status: Published
authors: ['grafana_labs']
Feedback Link: https://github.com/grafana/tutorials/issues/new
weight: 75
---
## Introduction
Grafana supports a wide range of data sources, including Prometheus, MySQL, and even Datadog. In previous tutorials we have shown how to extend Grafana capabilities to query custom data sources by [building a backend datasource plugin](/tutorials/build-a-data-source-backend-plugin/). In this tutorial we take a step further and add streaming capabilities to the backend datasource plugin. Streaming allows plugins to push data to Grafana panels as soon as data appears (without periodic polling from UI side).
For more information about backend plugins, refer to the documentation on [Backend plugins](/docs/grafana/latest/developers/plugins/backend/).
In this tutorial, you'll:
- Extend a backend plugin with streaming capabilities
{{% class "prerequisite-section" %}}
#### Prerequisites
- Knowledge about how data sources are implemented in the frontend.
- Knowledge about [backend datasource anatomy](/tutorials/build-a-data-source-backend-plugin/)
- Grafana 8.0+
- Go ([Version](https://github.com/grafana/plugin-tools/blob/main/packages/create-plugin/templates/backend/go.mod#L3))
- [Mage](https://magefile.org/)
- NodeJS ([Version](https://github.com/grafana/plugin-tools/blob/main/packages/create-plugin/templates/common/package.json#L66))
- yarn
{{% /class %}}
## Set up your environment
{{< docs/shared lookup="tutorials/set-up-environment.md" source="grafana" >}}
## Create a new plugin
To build a backend for your data source plugin, Grafana requires a binary that it can execute when it loads the plugin during start-up. In this guide, we will build a binary using the [Grafana plugin SDK for Go](/docs/grafana/latest/developers/plugins/backend/grafana-plugin-sdk-for-go/).
The easiest way to get started is to use the Grafana [create-plugin tool](https://www.npmjs.com/package/@grafana/create-plugin). Navigate to the plugin folder that you configured in step 1 and type:
```
npx @grafana/create-plugin
```
Follow the steps and select **datasource** as your plugin type and answer **yes** when prompted to create a backend for your plugin.
```bash
cd my-plugin
```
Install frontend dependencies and build frontend parts of the plugin to _dist_ directory:
```bash
yarn install
yarn build
```
Run the following to update [Grafana plugin SDK for Go](/docs/grafana/latest/developers/plugins/backend/grafana-plugin-sdk-for-go/) dependency to the latest minor version:
```bash
go get -u github.com/grafana/grafana-plugin-sdk-go
go mod tidy
```
Build backend plugin binaries for Linux, Windows and Darwin to _dist_ directory:
```bash
mage -v
```
Now, let's verify that the plugin you've built can be used in Grafana when creating a new data source:
1. Restart your Grafana instance.
1. Open Grafana in your web browser.
1. Navigate via the side-menu to **Configuration** -> **Data Sources**.
1. Click **Add data source**.
1. Find your newly created plugin and select it.
1. Enter a name and then click **Save & Test** (ignore any errors reported for now).
You now have a new data source instance of your plugin that is ready to use in a dashboard. To confirm, follow these steps:
1. Navigate via the side-menu to **Create** -> **Dashboard**.
1. Click **Add new panel**.
1. In the query tab, select the data source you just created.
1. A line graph is rendered with one series consisting of two data points.
1. Save the dashboard.
### Troubleshooting
#### Grafana doesn't load my plugin
By default, Grafana requires backend plugins to be signed. To load unsigned backend plugins, you need to
configure Grafana to [allow unsigned plugins](/docs/grafana/latest/plugins/plugin-signature-verification/#allow-unsigned-plugins).
For more information, refer to [Plugin signature verification](/docs/grafana/latest/plugins/plugin-signature-verification/#backend-plugins).
## Anatomy of a backend plugin
As you may notice till this moment we did the same steps described in [build a backend datasource plugin tutorial](/tutorials/build-a-data-source-backend-plugin/). At this point, you should be familiar with backend plugin structure and a way how data querying and health check capabilities could be implemented. Let's take the next step and discuss how datasource plugin can handle data streaming.
## Add streaming capabilities
What we want to achieve here is to issue a query to load initial data from a datasource plugin and then switching to data streaming mode where the plugin will push data frames to Grafana time-series panel.
In short – implementing a streaming plugin means implementing a `backend.StreamHandler` interface which contains `SubscribeStream`, `RunStream`, and `PublishStream` methods.
`SubscribeStream` is a method where the plugin has a chance to authorize user subscription requests to a channel. Users on the frontend side subscribe to different channels to consume real-time data.
When returning a `data.Frame` with initial data we can return a special field `Channel` to let the frontend know that we are going to stream data frames after initial data load. When the frontend receives a frame with a `Channel` set it automatically issues a subscription request to that channel.
Channel is a string identifier of topic to which clients can subscribe in Grafana Live. See a documentation of Grafana Live for [details about channel structure](/docs/grafana/latest/live/live-channel/).
As said in docs in Grafana Live channel consists of 3 parts delimited by `/`:
- Scope
- Namespace
- Path
For datasource plugin channels Grafana uses `ds` scope. Namespace in the case of datasource channels is a datasource unique ID (UID) which is issued by Grafana at the moment of datasource creation. The path is a custom string that plugin authors free to choose themselves (just make sure it consists of allowed symbols). I.e. datasource channel looks like `ds/<DATASOURCE_UID>/<CUSTOM_PATH>`.
So to let the frontend know that we are going to stream data we set a `Channel` field into frame metadata inside `QueryData` implementation. In our tutorial it's a `ds/<DATASOURCE_UID>/stream`. The frontend will issue a subscription request to this channel.
Inside `SubscribeStream` implementation we check whether a user allowed to subscribe on a channel path. If yes – we return an OK status code to tell Grafana user can join a channel:
```go
status := backend.SubscribeStreamStatusPermissionDenied
if req.Path == "stream" {
// Allow subscribing only on expected path.
status = backend.SubscribeStreamStatusOK
}
return &backend.SubscribeStreamResponse{
Status: status,
}, nil
```
As soon as the first subscriber joins a channel Grafana opens a unidirectional stream to consume streaming frames from a plugin. To handle this and to push data towards clients we implement a `RunStream` method which provides a way to push JSON data into a channel. So we can push data frame like this (error handling skipped):
```go
// Send frame to stream including both frame schema and data frame parts.
_ = sender.SendFrame(frame, data.IncludeAll)
```
Open example datasource query editor and make sure `With Streaming` toggle is on. After doing this you should see data displayed and then periodically updated by streaming frames coming periodically from `RunStream` method.
The important thing to note is that Grafana opens a unidirectional stream only once per channel upon the first subscriber joined. Every other subscription request will be still authorized by `SubscribeStream` method but the new `RunStream` won't be issued. I.e. you can have many active subscribers but only one running stream. At this moment this guarantee works for a single Grafana instance, we are planning to support this for highly-available Grafana setup (many Grafana instances behind load-balancer) in future releases.
The stream will be automatically closed as soon as all subscriber users left.
For the tutorial use case, we only need to properly implement `SubscribeStream` and `RunStream` - we don't need to handle publications to a channel from users. But we still need to write `PublishStream` method to fully implement `backend.StreamHandler` interface. Inside `PublishStream` we just do not allow any publications from users since we are pushing data from a backend:
```go
return &backend.PublishStreamResponse{
Status: backend.PublishStreamStatusPermissionDenied,
}, nil
```
## Summary
In this tutorial you created a backend for your data source plugin with streaming capabilities.

@ -1,208 +0,0 @@
---
title: Build an app plugin
summary: Learn at how to create an app for Grafana.
description: Learn at how to create an app for Grafana.
id: build-an-app-plugin
categories: ['plugins']
tags: ['beginner']
status: Published
authors: ['grafana_labs']
Feedback Link: https://github.com/grafana/tutorials/issues/new
weight: 50
draft: true
---
## Introduction
App plugins are Grafana plugins that can bundle data source and panel plugins within one package. They also let you create _custom pages_ within Grafana. Custom pages enable the plugin author to include things like documentation, sign-up forms, or to control other services over HTTP.
Data source and panel plugins will show up like normal plugins. The app pages will be available in the main menu.
{{% class "prerequisite-section" %}}
### Prerequisites
- Grafana 7.0
- NodeJS 12.x
- yarn
{{% /class %}}
## Set up your environment
{{< docs/shared lookup="tutorials/set-up-environment.md" source="grafana" >}}
## Create a new plugin
{{< docs/shared lookup="tutorials/create-plugin.md" source="grafana" >}}
## Anatomy of a plugin
{{< docs/shared lookup="tutorials/plugin-anatomy.md" source="grafana" >}}
## App plugins
App plugins let you bundle resources such as dashboards, panels, and data sources into a single plugin.
Any resource you want to include needs to be added to the `includes` property in the `plugin.json` file. To add a resource to your app plugin, you need to include it to the `plugin.json`.
Plugins that are included in an app plugin are available like any other plugin.
Dashboards and pages can be added to the app menu by setting `addToNav` to `true`.
By setting `"defaultNav": true`, users can navigate to the dashboard by clicking the app icon in the side menu.
## Add a custom page
App plugins let you extend the Grafana user interface through the use of _custom pages_.
Any requests sent to `/a/<plugin-id>`, e.g. `/a/myorgid-simple-app/`, are routed to the _root page_ of the app plugin. The root page is a React component that returns the content for a given route.
While you're free to implement your own routing, in this tutorial you'll use a tab-based navigation page that you can use by calling `onNavChange`.
Let's add a tab for managing server instances.
1. In the `src/pages` directory, add a new file called `Instances.tsx`. This component contains the content for the new tab.
```ts
import { AppRootProps } from '@grafana/data';
import React, { FC } from 'react';
export const Instances: FC<AppRootProps> = ({ query, path, meta }) => {
return <p>Hello</p>;
};
```
1. Register the page by adding it to the `pages` array in `src/pages/index.ts`.
**index.ts**
```ts
import { Instances } from './Instances';
```
```ts
{
component: Instances,
icon: 'file-alt',
id: 'instances',
text: 'Instances',
}
```
1. Add the page to the app menu, by including it in `plugin.json`. This will be the main view of the app, so we'll set `defaultNav` to let users quickly get to it by clicking the app icon in the side menu.
**plugin.json**
```json
"includes": [
{
"type": "page",
"name": "Instances",
"path": "/a/myorgid-simple-app?tab=instances",
"role": "Viewer",
"addToNav": true,
"defaultNav": true
}
]
```
> **Note:** While `page` includes typically reference pages created by the app, you can set `path` to any URL, internal or external. Try setting `path` to `https://grafana.com`.
## Configure the app
Let's add a new configuration page where users are able to configure default zone and regions for any instances they create.
1. In `module.ts`, add new configuration page using the `addConfigPage` method. `body` is the React component that renders the page content.
**module.ts**
```ts
.addConfigPage({
title: 'Defaults',
icon: 'fa fa-info',
body: DefaultsConfigPage,
id: 'defaults',
})
```
## Add a dashboard
#### Include a dashboard in your app
1. In `src/`, create a new directory called `dashboards`.
1. Create a file called `overview.json` in the `dashboards` directory.
1. Copy the JSON definition for the dashboard you want to include and paste it into `overview.json`. If you don't have one available, you can find a sample dashboard at the end of this step.
1. In `plugin.json`, add the following object to the `includes` property.
- The `name` of the dashboard needs to be the same as the `title` in the dashboard JSON model.
- `path` points out the file that contains the dashboard definition, relative to the `plugin.json` file.
```json
"includes": [
{
"type": "dashboard",
"name": "System overview",
"path": "dashboards/overview.json",
"addToNav": true
}
]
```
1. Save and restart Grafana to load the new changes.
## Bundle a plugin
An app plugin can contain panel and data source plugins that get installed along with the app plugin.
In this step, you'll add a data source to your app plugin. You can add panel plugins the same way by changing `datasource` to `panel`.
1. In `src/`, create a new directory called `datasources`.
1. Create a new data source using Grafana create-plugin tool in a temporary directory.
```bash
mkdir tmp
cd tmp
npx @grafana/create-plugin
```
1. Move the `src` directory in the data source plugin to `src/datasources`, and rename it to `my-datasource`.
```bash
mv ./my-datasource/src ../src/datasources/my-datasource
```
Any bundled plugins are built along with the app plugin. Grafana looks for any subdirectory containing a `plugin.json` file and attempts to load a plugin in that directory.
To let users know that your plugin bundles other plugins, you can optionally display it on the plugin configuration page. This is not done automatically, so you need to add it to the `plugin.json`.
1. Include the data source in the `plugin.json`. The `name` property is only used for displaying in the Grafana UI.
```json
"includes": [
{
"type": "datasource",
"name": "My data source"
}
]
```
#### Include external plugins
If you want to let users know that your app requires an existing plugin, you can add it as a dependency in `plugin.json`. Note that they'll still need to install it themselves.
```json
"dependencies": {
"plugins": [
{
"type": "panel",
"name": "Worldmap Panel",
"id": "grafana-worldmap-panel",
"version": "^0.3.2"
}
]
}
```
## Summary
In this tutorial you learned how to create an app plugin.

@ -1,331 +0,0 @@
---
title: How to create Grafana alerts with InfluxDB and the Flux query language
summary: Create complex alerts from Flux queries in the new Grafana Alerting
description: Create complex alerts from Flux queries in the new Grafana Alerting
id: grafana-alerts-flux-queries
categories: ['alerting']
tags: ['advanced']
status: published
authors: ['grant_pinkos']
Feedback Link: https://github.com/grafana/tutorials/issues/new
weight: 70
---
# How to create Grafana alerts with InfluxDB and the Flux query language
[Grafana Alerting](/docs/grafana/latest/alerting/) represents a powerful new approach to systems observability and incident response management. While the alerting platform is perhaps best known for its strong integrations with Prometheus, the system works with numerous popular data sources including InfluxDB. In this tutorial we will learn how to create Grafana alerts using InfluxDB and the newer Flux query language. We will cover five common scenarios from the most basic to the most complex. Together, these five scenarios will provide an excellent guide for almost any type of alerting query that you wish to create using Grafana and Flux.
Before we dive into our alerting scenarios, it is worth considering the development of InfluxDB's two popular query languages: InfluxQL and Flux. Originally, InfluxDB used [InfluxQL](https://docs.influxdata.com/influxdb/v2.5/reference/syntax/influxql/spec/) as their query language, which uses a SQL-like syntax. But beginning with InfluxDB v1.8, the company introduced [Flux](https://docs.influxdata.com/flux/v0.x/), "an open source functional data scripting language designed for querying, analyzing, and acting on data." "Flux," its official documentation goes on to state, "unifies code for querying, processing, writing, and acting on data into a single syntax. The language is designed to be usable, readable, flexible, composable, testable, contributable, and shareable."
In the following five examples we will see just how powerful and flexible the new Flux query language can be. We will also see just how well Flux pairs with Grafana Alerting.
## Example 1: Create an alert when a value is above or below a set threshold
Our first example uses a common real-world scenario for InfluxDB and Grafana Alerting. Popular with IoT and edge applications, InfluxDB excels at on-site, real-time observability. In this example, and in fact for many of the following examples, we will consider the hypothetical scenario where we are monitoring a number of fluid tanks in a manufacturing plant. This scenario, [based on an actual application of InfluxDB and Alerting](/go/grafanaconline/2021/plant-efficiency-grafana-cloud/), will allow us to work through Grafana's various alerting setups, progressing from the simplest to the most complex.
For Example 1, let's consider the following scenario: we are monitoring one tank, `A5`, for which we are storing real-time temperature data. We need to make sure that the temperature in this tank is always greater than 30 °C and less than 60 °C.
We want to write a Grafana alert that will trigger whenever the temperature in tank `A5` crosses the lower threshold of 30 °C or the upper threshold of 60 °C.
To do this, we'll: 1. create a Grafana alert rule. 1. add a Flux query. 1. add expressions to the alert rule.
### Create a Grafana Alert rule
1. Open the Grafana alerting menu and select **Alert rules**.
1. Click **New alert rule**.
1. Give your alert rule a name and then select **Grafana managed alert**.
For InfluxDB, you will always create a [Grafana managed rule](/docs/grafana/latest/alerting/alerting-rules/create-grafana-managed-rule/#add-grafana-managed-rule).
### Add an initial Flux query to the alert rule
Still in the **Step 2** section of the Alert rule page, you will see three boxes: a query editor (`A`), and then two sections labelled `B` and `C`. You will use these three sections to construct your rule. Let's move through them one by one.
First, we want to query the data in our imaginary InfluxDB instance to obtain a time series graph of the temperature of tank A5. For this you would choose your InfluxDB data source from the dropdown and then write a query like this:
```
from(bucket: "RetroEncabulator")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_measurement"] == "TemperatureData")
|> filter(fn: (r) => r["Tank"] == "A5")
|> filter(fn: (r) => r["_field"] == "Temperature")
|> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)
|> yield(name: "mean")
```
This is a fairly typical Flux query. Let's go through it function by function. We begin using [the `from()` function](https://docs.influxdata.com/flux/v0.x/stdlib/influxdata/influxdb/from/) to choose the correct bucket where our tank data resides. Then we use [a `range()` function](https://docs.influxdata.com/flux/v0.x/stdlib/universe/range/) to filter our rows based on time constraints. Then we pass our data through three [`filter()` functions](https://docs.influxdata.com/flux/v0.x/stdlib/universe/filter/) to narrow our results. We choose a specific [`measurement` (a special keyword in InfluxDB)](https://docs.influxdata.com/influxdb/v1.8/concepts/glossary/#measurement), then our tank in question (`A5`), and then a specific [`field` (another special keyword in InfluxDB)](https://docs.influxdata.com/influxdb/v1.8/concepts/glossary/#field). After this we pass the data into [an `aggregateWindow()` function](https://docs.influxdata.com/flux/v0.x/stdlib/universe/aggregatewindow/), which downsamples our data into specific periods of time, and then finally [a `yield()` function](https://docs.influxdata.com/flux/v0.x/stdlib/universe/yield/), which specifies which final result we want: `mean`.
This Flux query will yield a time-series graph like this:
![grafana alerts from flux queries](/media/tutorials/screenshot-flux-timeseries-graph.png)
### Add expressions to your Grafana Alert rule
With data now appearing in our rule setup, our next step is to create an [expression](/docs/grafana/v9.0/panels/query-a-data-source/use-expressions-to-manipulate-data/about-expressions/#using-expressions). Move to section `B`. For this scenario, we want to create a Reduce expression that will reduce the above to a single value. In this image, you can see that we have chosen to reduce our time-series data the `Last` value from input `A`. In this case, it returns a value 53 degrees celsius for Tank A5:
![grafana alerts from flux queries](/media/tutorials/screenshot-flux-reduce-expression.png)
Finally, we need to create a math expression that Grafana will alert on. In our case we will write an expression with two conditions separated by the OR `||` operator. We want to trigger an alert any time our result in section `B` is less than 30 or more than 60. This looks like `$B < 30 || $B > 60`:
![grafana alerts from flux queries](/media/tutorials/screenshot-flux-math-expression.png)
Set the alert condition to `C - expression`. We can now preview our alert. Here is a preview of this alert when the state is `Normal`:
![grafana alerts from flux queries](/media/tutorials/screenshot-flux-alert-preview-state-normal.png)
And here is a preview of this alert when the state is `Alerting`:
![grafana alerts from flux queries](/media/tutorials/screenshot-flux-alert-alert-preview-state-alerting.png)
Note that the Reduce expression above is needed. Without it, when previewing the results, Grafana would display `invalid format of evaluation results for the alert definition B: looks like time series data, only reduced data can be alerted on`.
💡Tip: In case your locale is still stubbornly using Fahrenheit, we can modify the above Flux query by adding (before the aggregateWindow statement) a map() function to to convert (or map) the values from °C to °F. Note that we are not creating a new field. We are simply remapping the existing value.
```flux
|> map(fn: (r) => ({r with _value: r._value * 1.8 + 32.0}))
```
### Conclusion
Using these three steps you can create a Flux-based Grafana Alert that will trigger on either of two thresholds from a single data source. But what if you need to trigger an alert based on **multiple conditions and from multiple time-series**? In example two we will cover this very scenario.
## Example 2: how to create a Grafana alert from two queries and two conditions
Let's mix things up a bit for example two and leave our imaginary manufacturing plant. Imagine you're an assistant to the great Dr. Emmett Brown from Back to the Future, and Doc has tasked you with the following challenge: "I want an alert sent to me every time both conditions for time travel are met: when the velocity of a vehicle reaches 88 miles per hour and an object generates 1.21 jigowatts of electricity."
Let's assume we are tracking this data in InfluxDB and Grafana. Let's also assume that each of the above data sources comes from different buckets. How do we alert on this? How do we use Grafana and Flux to alert on two distinct conditions originating from two distinct data sources?
### Add two Flux queries to your Grafana Alert rule
Like we did in example 1, let's first mock up our queries. Our query for our vehicle data is very similar to our last query. We use a `from()`, `range()`, and a sequence of `filter()` functions. We then use `AggregateWindow()` and `yield()` to narrow our data even more. In this case, the result is a time series tracking the velocity of our 1983 DeLorean:
```flux
from(bucket: "vehicles")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_measurement"] == "VehicleData")
|> filter(fn: (r) => r["VehicleType"] == "DeLorean")
|> filter(fn: (r) => r["VehicleYear"] == "1983")
|> filter(fn: (r) => r["_field"] == "velocity")
|> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)
|> yield(name: "mean")
```
Our second query will trigger an alert whenever our electricity resource (the lightning strike on the Hill Valley clocktower) reaches the needed 1.21 jigowatts. A query like this would look very similar to our vehicle velocity query:
```flux
from(bucket: "HillValley")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_measurement"] == "ElectricityData")
|> filter(fn: (r) => r["Location"] == "clocktower")
|> filter(fn: (r) => r["Source"] == "lightning")
|> filter(fn: (r) => r["_field"] == "power")
|> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)
|> yield(name: "mean")
```
We are now ready to modify this data using expressions.
### Add expressions to your Grafana Alert rule
1. Let's now use the same steps to reduce each query to the last (most recent) value. Reducing Query `A` to a single value might look like this:
![grafana alerts from flux queries](/media/tutorials/screenshot-flux-additional-queries-reduce-expression-A.png)
1. And here we are reducing query `B`:
![grafana alerts from flux queries](/media/tutorials/screenshot-flux-additional-queries-reduce-expression-B.png)
1. Now, in section `C` we need to create a math expression to be alerted on. In this case we will use the AND `&&` operator to specify that two conditions must be met: the value of `C` (the reduced value from query `A`) must be greater than 88.0 while the value of `D` (the reduced value from query `B`) must be greater than 1.21. We write this as `$C > 88.0 && $D > 1.21`
![grafana alerts from flux queries](/media/tutorials/screenshot-flux-additional-queries-math-expression.png)
And here is a preview of our alerts:
![grafana alerts from flux queries](https://raw.githubusercontent.com/grafana/tutorials/master/content/tutorials/assets/flux-additional-queries-alert-preview.png)
💡Tip: If your data in InfluxDB happens to have an unnecessarily large number of digits to the right of the decimal (such as 1.2104705741732575 shown above), and you want your Grafana alerts to be more legible, try using {{ printf "%.2f" $values.D.Value }}. For example, in the annotation Summary, we could write the following:
```
{{ $values.D.Labels.Source }} at the {{ $values.D.Labels.Location }} has generated {{ printf "%.2f" $values.D.Value }} jigowatts.`
```
This will display as follows:
![grafana alerts from flux queries](/media/tutorials/screenshot-flux-tip-significant-figures.png))
You can reference our documentation on [alert message templating](/docs/grafana/latest/alerting/contact-points/message-templating/) to learn more about this powerful feature.
### Conclusion
In this example we showed how to create a Flux-based alert that uses two distinct conditions from two distinct queries that use data from two distinct data sources. For example three we will switch gears and tackle another popular alerting scenario: how to create an alert based on an aggregated (per day) value.
## Example 3: how to create a Grafana Alert based on an aggregated (per-day) value
One of the most common requests in [Grafana's community forum](https://community.grafana.com) involves graphing daily electrical consumption and production. This sort of data is very often stored in InfluxDB. In this example we will see how to aggregate time series data into a per-day value and then alert on it.
Let’s assume our electricity meter sends a reading to InfluxDB once per hour and contains the total kWh used for that hour. We want to write a query that will aggregate these per-hour values into a per-day value, then create an alert that triggers when the power consumption (kWh) exceeds 5,000 kWh per day.
### Add an initial Flux query to your Grafana Alert rule
1. Let's begin by examining a typical query and the resulting time graph for our hourly data across a 7-day period. A query like this is shown below:
```flux
from(bucket: "RetroEncabulator")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_measurement"] == "ElectricityData")
|> filter(fn: (r) => r["Location"] == "PlantD5")
|> filter(fn: (r) => r["_field"] == "power_consumed")
|> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)
|> yield(name: "power")
```
We can see the same pattern of Flux functions here that we say in examples 1 and 2. A query like this would produce a graph similar to the following:
![grafana alerts from flux queries](/media/tutorials/screenshot-flux-aggregatewindow-timeseries-graph.png)
1. Now let's adjust our query to calculate daily usage. With many datasources, this can be a rather complex operation. But with Flux, by simply changing the aggregateWindow function parameters we can calculate the daily usage over the same 7-day period:
```flux
from(bucket: "RetroEncabulator")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_measurement"] == "ElectricityData")
|> filter(fn: (r) => r["Location"] == "PlantD5")
|> filter(fn: (r) => r["_field"] == "power_consumed")
|> aggregateWindow(every: 1d, fn: sum)
|> yield(name: "power")
```
Note how we've adjusted our `aggregateWindow()` function to `aggregateWindow(every: 1d, fn: sum)`. This results in a graph like so:
![grafana alerts from flux queries](/media/tutorials/screenshot-flux-aggregatewindow-aggregated.png)
1. Add expressions to your Grafana Alert rule.
Now that we have our per-day query correct, we can continue using the same pattern as before, adding expressions to reduce and perform math on our results.
As before, let's reduce our query to a single value:
![grafana alerts from flux queries](/media/tutorials/screenshot-flux-aggregatewindow-reduce-expression.png)
Now create a math expression to be alerted on and set the evaluation behavior. In this case we want to write `$B > 5000`:
![grafana alerts from flux queries](/media/tutorials/screenshot-flux-aggregatewindow-math-expression.png)
And now we are alerting on our daily electricity consumption whenever we exceed 5000 kWh. Here is preview of our alert:
![grafana alerts from flux queries](/media/tutorials/screenshot-flux-aggregatewindow-alert-preview.png)
### Conclusion
Plotting and aggregating electrical consumption is a common use case for combining InfluxDB and Grafana. Using Flux, we saw just how easy it can be to group our data by day and then alert on that daily value. In our next two examples we will examine the more complex form of Grafana Alert: multidimensional alerts.
## Example 4: create a dynamic (multidimensional) Grafana Alert using Flux
Let’s return to our fluid tanks from example 1, but this time let’s assume we have 5 tanks (A5, B4, C3, D2, and E1). We are now tracking the temperature in five tanks: A5, B4, C3, D2, and E1.
We want to create one multidimensional alert that will notify us whenever the temperature in any tank is less than 30 °C or greater than 60 °C.
### Add an initial Flux query to your Grafana Alert rule
We begin, as always, by writing our initial query. This is very similar to our query in example 1, but note how our third `filter()` function captures the data from all five tanks and not just `A5`:
```flux
from(bucket: "HyperEncabulator")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_measurement"] == "TemperatureData")
|> filter(fn: (r) => r["MeasType"] == "actual")
|> filter(fn: (r) => r["Tank"] == "A5" or r["Tank"] == "B4" or r["Tank"] == "C3" or r["Tank"] == "D2" or r["Tank"] == "E1")
|> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)
|> yield(name: "mean")
```
💡Tip: If the tanks were shut down every night from 23:00 to 07:00, they would possibly fall below the 30 °C threshold. If one did not want to receive alerts during those hours, one can use the Flux function hourSelection() which filters rows by time values in a specified hour range.
```flux
|> hourSelection(start: 7, stop: 23)`
```
A query like the one above will produce a time series graph like this:
![grafana alerts from flux queries](/media/tutorials/screenshot-flux-multidimensional-timeseries-graph.png)
### Add expressions to your Grafana Alert rule
1. We create a Reduce expression that will reduce the time series for each tank to a single value. This gives us five distinct temperatures:
![grafana alerts from flux queries](/media/tutorials/screenshot-flux-multidimensional-reduce-expression.png))
1. Create a math expression to be alerted on. This is the exact same expression from example 1, `$B < 30 || $B > 60`:
![grafana alerts from flux queries](/media/tutorials/screenshot-flux-multidimensional-math-expression.png)
As we can see three tanks are within the acceptable thresholds while two tanks have crossed the upper boundary. This would trigger an alert for tanks `D2` and `E1`.
### Conclusion
With multidimensional alerts we can avoid repeating ourselves. But what if the scenario were even more complex? In the next and final example, we will examine how to use multidimensional alerts to create the most dynamic alerts possible.
## Example 5: how to create a dynamic (multidimensional) Grafana Alert using multiple queries and multiple thresholds with Flux
For this final example let's continue with our five fluid tanks and their five datasets.Let’s assume again that each tank has a temperature controller with a setpoint value that is stored in InfluxDB. Let’s mix things up and assume that each tank has a _different_ setpoint, where we always need to be within 3 degrees of the setpoint.
We want to create one multidimensional alert that will cover each unique scenario for each tank, triggering an alert whenever any tank's temperature moves beyond its unique allowable range.
To better visualize this challenge, here is a table representing our five tanks, their temperature setpoints, and their allowable range:
| Tank | Setpoint | Allowable Range (±3) |
| ---- | -------- | -------------------- |
| A5 | 45 | 42 to 48 |
| B4 | 55 | 52 to 58 |
| C3 | 60 | 57 to 63 |
| D2 | 72 | 69 to 75 |
| E1 | 80 | 77 to 83 |
With Grafana Alerting, we can create a single multidimensional rule to cover all 5 tanks, and we can use Flux to compare the setpoint and actual value for each tank. In other words, one multidimensional alert can monitor 5 separate tanks, each with different setpoints and actual values, but all with one common "allowable threshold" (i.e. a temperature difference of ±3 degrees).
### Add an initial Flux query to your Grafana Alert rule
Let's begin with our data query. It is similar to our past queries, only now more complex. We must add extra functions to get our data into the proper format, including a `pivot()`, `map()`, `rename()`, `keep()`, and `drop()` function:
```flux
from(bucket: "HyperEncabulator")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_measurement"] == "TemperatureData")
|> filter(fn: (r) => r["MeasType"] == "actual" or r["MeasType"] == "setpoint")
|> filter(fn: (r) => r["Tank"] == "A5" or r["Tank"] == "B4" or r["Tank"] == "C3" or r["Tank"] == "D2" or r["Tank"] == "E1")
|> filter(fn: (r) => r["_field"] == "Temperature")
|> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)
|> pivot(rowKey:["_time"], columnKey: ["MeasType"], valueColumn: "_value")
|> map(fn: (r) => ({ r with _value: (r.setpoint - r.actual)}))
|> rename(columns: {_value: "difference"})
|> keep(columns: ["_time", "difference", "Tank"])
|> drop(columns: ["actual", "setpoint"])
|> yield(name: "mean")
```
Note in the above that we are calculating the difference between the actual and the setpoint. The way Grafana parses the result from InfluxDB is that if a \_value column is found, it is assumed to be a time-series. The quick workaround is to add the following `rename()` function:
```flux
|> rename(columns: {_value: "something"})
```
The above query results in this time series:
![grafana alerts from flux queries](/media/tutorials/screenshot-flux-complex-query-timeseries-graph.png)
### Add expressions to your Grafana Alert rule
1. Again, we create a Reduce expression for the above query to reduce each of the above to a single value. This value represents the temperature differential between each tank's setpoint and its actual real-time temperature:
![grafana alerts from flux queries](/media/tutorials/screenshot-flux-complex-query-reduce-expression.png)
1. Now we create a math expression to be alerted on. This time we will create a condition that checks if the absolute value of our reduce calculation is greater than 3, `abs($(B))>3.0`:
![grafana alerts from flux queries](/media/tutorials/screenshot-flux-complex-query-math-expression.png)
We can now see that two tanks, `D2` and `E1`, are evaluating to true. When we preview the alert we can see that those two tanks will trigger a notification and change their state from `Normal` to `Alerting`:
![grafana alerts from flux queries](/media/tutorials/screenshot-flux-complex-query-alert-preview-state-normal.png)
![grafana alerts from flux queries](/media/tutorials/screenshot-flux-complex-query-alert-preview-state-alerting.png)
### Conclusion
Flux queries and Grafana Unified Alerting are a powerful combination to identify practically any alertable conditions in your dataset, or across your entire system. For more information on Grafana Alerting, [visit the documentation here](/docs/grafana/latest/alerting/). For more information on the Flux query language, [you can visit that documentation as well](https://docs.influxdata.com/flux/v0.x/).

@ -1,236 +0,0 @@
---
title: Create users and teams
summary: Learn how to set up teams and users.
description: Learn how to set up teams and users.
id: create-users-and-teams
categories: ['administration']
tags: ['beginner']
status: Published
authors: ['grafana_labs']
Feedback Link: https://github.com/grafana/tutorials/issues/new
weight: 20
---
## Introduction
This tutorial is for admins or anyone that wants to learn how to manage
users in Grafana. You'll add multiple local users, organize them into teams,
and make sure they're only able to access the resources they need.
### Scenario
_Graphona_, a fictional telemarketing company, has asked you to configure Grafana
for their teams.
In this scenario, you'll:
- Create users and organize them into teams.
- Manage resource access for each user and team through roles and folders.
{{% class "prerequisite-section" %}}
### Prerequisites
- Grafana 7.0 or newer, this tutorial was tested with Grafana 8.5.
- A user with the Admin or Server Admin role.
{{% /class %}}
## Add users
In Grafana, all users are granted an _organization role_ that determines what
resources they can access.
There are three types of organization roles in Grafana. The **Grafana Admin** is
a global role, the default `admin` user has this role.
- **Grafana Admin -** Manage organizations, users, and view server-wide settings.
- **Organization Administrator -** Manage data sources, teams, and users within an organization.
- **Editor -** Create and edit dashboards.
- **Viewer -** View dashboards.
> **Note**: You can also configure Grafana to allow [anonymous access](/docs/grafana/latest/auth/overview/#anonymous-authentication), to make dashboards available even to those who don't have a Grafana user account. That's how Grafana Labs made https://play.grafana.org publicly available.
### Exercise
Graphona has asked you to add a group of early adopters that work in the Marketing and Engineering teams. They'll need to be able to edit their own team's dashboards, but want to have view access to dashboards that belong to the other team.
| Name | Email | Username |
| ----------------- | ----------------------------- | ----------------- |
| Almaz Russom | almaz.russom@example.com | almaz.russom |
| Brenda Tilman | brenda.tilman@example.com | brenda.tilman |
| Mada Rawdha Tahan | mada.rawdha.tahan@example.com | mada.rawdha.tahan |
| Yuan Yang | yuan.yang@example.com | yuan.yang |
#### Add users
Repeat the following steps for each of the employees in the table above to create the new user accounts:
1. Log in as a user that has the **Server Admin** role.
1. On the sidebar, click the **Server Admin** (shield) icon.
1. Choose **Users** from the menu drop-down, then click **New User**.
1. Enter the **Name**, **Email**, **Username**, and **Password** from the table above.
1. Click the **Create User** button to create the account.
When you create a user they are granted the Viewer role by default, which means that they won't be able to make any changes to any of the resources in Grafana. That's ok for now, you'll grant more user permissions by adding users to _teams_ in the next step.
## Assign users to teams
Teams let you grant permissions to a group of users, instead of granting permissions to individual users one at a time.
Teams are useful when onboarding new colleagues. When you add a user to a team, they get access to all resources assigned to that team.
### Exercise
In this step, you'll create two teams and assign users to them.
| Username | Team |
| ----------------- | ----------- |
| brenda.tilman | Marketing |
| mada.rawdha.tahan | Marketing |
| almaz.russom | Engineering |
| yuan.yang | Engineering |
#### Create a team
Create the _Marketing_ and _Engineering_ teams.
1. In the sidebar, hover your mouse over the **Configuration** (gear) icon and
then click **Teams**.
1. Click **New team**.
1. In **Name**, enter the name of the team: either _Marketing_ or _Engineering_.
You do not need to enter an email.
1. Click **Create**.
1. Click on the **Teams** link at the top of the page to return to teams page and create the second team.
#### Add a user to a team
Repeat these steps for each user to assign them to their team. Refer to the table above for team assignments.
1. Click the team name _Marketing_ or _Engineering_ to add members to that team.
1. Click **Add member**.
1. In the **Add team member** box, click the drop-down arrow to choose the user you want to add to the team .
1. Click **Add to team**.
When you're done, you'll have two teams with two users assigned to each.
## Manage resource access with folders
It's a good practice to use folders to organize collections of related dashboards. You can assign permissions at the folder level to individual users or teams.
### Exercise
The Marketing team is going to use Grafana for analytics, while the Engineering team wants to monitor the application they're building.
You'll create two folders, _Analytics_ and _Application_, where each team can add their own dashboards. The teams still want to be able to view each other's dashboards.
| Folder | Team | Permissions |
| ----------- | ----------- | ----------- |
| Analytics | Marketing | Edit |
| | Engineering | View |
| Application | Marketing | View |
| | Engineering | Edit |
Repeat the following steps for each folder. You'll move through all three steps for each folder before moving on to the next one.
#### Add a folder for each team
1. In the sidebar, hover your cursor over the **Dashboards** (four squares) icon and then click **Browse**.
1. To create a folder, click **New Folder**.
1. In **Name**, enter the folder name.
1. Click **Create**.
1. Stay in the folder view and move on to the next sections to edit permissions for this folder.
#### Remove the viewer role from folder permissions
By default, when you create a folder, all users with the Viewer role are granted permission to view the folder.
In this example, Graphona wants to explicitly grant teams access to folders. To support this, you need to remove the Viewer role from the list of permissions:
1. Go to the **Permissions** tab.
1. Remove the Viewer role from the list, by clicking the red button on the right.
1. Stay in the permissions tab and move on to the next section to grant folder permissions for each team.
#### Grant folder permissions to a team:
1. Click **Add Permission**.
1. In the **Add Permission For** dialog, make sure "Team" is selected in the first box.
1. In the second box, select the team to grant access to.
1. In the third box, select the access you want to grant.
1. Click **Save**.
1. Repeat for the other team.
1. Click the **Dashboards** link at the top of the page to return to the dashboard list.
When you're finished, you'll have two empty folders, the contents of which can only be viewed by members of the Marketing or Engineering teams. Only Marketing team members can edit the contents of the Analytics folder, only Engineering team members can edit the contents of the Application folder.
## Define granular permissions
By using folders and teams, you avoid having to manage permissions for individual users.
However, there are times when you need to configure permissions on a more granular level. For these cases, Grafana allows you to override permissions for specific dashboards.
### Exercise
Graphona has hired a consultant to assist the Marketing team. The consultant should only be able to access the SEO dashboard in the Analytics folder.
| Name | Email | Username |
| ---------- | -------------------------------- | ---------- |
| Luc Masson | luc.masson@exampleconsulting.com | luc.masson |
#### Add a new user
1. In the sidebar, click the **Server Admin** (shield) icon.
1. In the Users tab, click **New user**.
1. In **Name**, enter the name of the user.
1. In **E-mail**, enter the email of the user.
1. In **Username**, enter the username that the user will use to log in.
1. In **Password**, enter a password. The user can change their password once they log in.
1. Click **Create user** to create the user account.
#### Create a dashboard
1. In the sidebar, click the **Create** (plus) icon to create a new dashboard.
1. In the top right corner, click the cog icon to go to **Dashboard settings**.
1. In **Name**, enter **SEO**.
1. Click **Save Dashboard**.
1. In the **Save dashboard as...** pop-up, choose the **Analytics** folder from the drop-down and click **Save**.
#### Grant a user permission to view dashboard
1. In the top right corner of your dashboard, click the cog icon to go to **Dashboard settings**.
1. Go to the **Permissions** tab, and click **Add Permission**.
1. In the **Add Permission For** dialog, select **User** in the first box.
1. In the second box, select the user to grant access to: Luc Masson.
1. In the third box, select **View**.
1. Click **Save**.
1. Click **Save dashboard**.
1. Add a note about giving Luc Masson Viewer permission for the dashboard and then click **Save**.
You've created a new user and given them unique permissions to view a single dashboard within a folder.
#### Check your work
You can repeat these steps to log in as the other users you've created see the differences in the viewer and editor roles.
For this example, you can log in as the user `luc.masson` to see that they can only access the SEO dashboard.
1. Click the profile (avatar) button in the bottom left corner, choose **Sign out**.
1. Enter `luc.masson` as the username.
1. Enter the password you created for Luc.
1. Click **Log in**.
1. In the sidebar, hover your cursor over the **Dashboards** (four squares) icon and then click **Browse**.
1. You'll notice that you won't see the **Analytics** folder in the folder view because we did not give Luc folder permission.
1. Click on the list icon (3 lines) to see the dashboard list.
1. Click on the **SEO dashboard**, there shouldn't be any editing permissions since we assigned Luc the viewer role.
## Summary
In this tutorial, you've configured Grafana for an organization:
- You added users to your organization.
- You created teams to manage permissions for groups of users.
- You configured permissions for folders and dashboard.
### Learn more
- [Organization Roles](/docs/grafana/next/administration/manage-users-and-permissions/about-users-and-permissions/#organization-roles)
- [Permissions Overview](/docs/grafana/latest/administration/manage-users-and-permissions/about-users-and-permissions/#about-users-and-permissions)

@ -1,354 +0,0 @@
---
title: Grafana fundamentals
summary: Get familiar with Grafana
description: Get familiar with Grafana
id: grafana-fundamentals
categories: ['fundamentals']
tags: ['beginner']
status: Published
authors: ['grafana_labs']
Feedback Link: https://github.com/grafana/tutorials/issues/new
weight: 10
---
## Introduction
In this tutorial, you'll learn how to use Grafana to set up a monitoring solution for your application.
In this tutorial, you'll:
- Explore metrics and logs
- Build dashboards
- Annotate dashboards
- Set up alerts
{{% class "prerequisite-section" %}}
### Prerequisites
- [Docker](https://docs.docker.com/install/)
- [Docker Compose](https://docs.docker.com/compose/) (included in Docker for Desktop for macOS and Windows)
- [Git](https://git-scm.com/)
{{% /class %}}
## Set up the sample application
This tutorial uses a sample application to demonstrate some of the features in Grafana. To complete the exercises in this tutorial, you need to download the files to your local machine.
In this step, you'll set up the sample application, as well as supporting services, such as [Prometheus](https://prometheus.io/) and [Loki](/oss/loki/).
1. Clone the [github.com/grafana/tutorial-environment](https://github.com/grafana/tutorial-environment) repository.
```
git clone https://github.com/grafana/tutorial-environment.git
```
1. Change to the directory where you cloned this repository:
```
cd tutorial-environment
```
1. Make sure Docker is running:
```
docker ps
```
No errors means it is running. If you get an error, then start Docker and then run the command again.
1. Start the sample application:
```
docker-compose up -d
```
The first time you run `docker-compose up -d`, Docker downloads all the necessary resources for the tutorial. This might take a few minutes, depending on your internet connection.
> **Note:** If you already have Grafana, Loki, or Prometheus running on your system, then you might see errors because the Docker image is trying to use ports that your local installations are already using. Stop the services, then run the command again.
1. Ensure all services are up-and-running:
```
docker-compose ps
```
In the **State** column, it should say `Up` for all services.
1. Browse to the sample application on [localhost:8081](http://localhost:8081).
### Grafana News
The sample application, Grafana News, lets you post links and vote for the ones you like.
To add a link:
1. In **Title**, enter **Example**.
1. In **URL**, enter **https://example.com**.
1. Click **Submit** to add the link.
The link appears in the list under the Grafana News heading.
To vote for a link, click the triangle icon next to the name of the link.
## Log in to Grafana
Grafana is an open-source platform for monitoring and observability that lets you visualize and explore the state of your systems.
1. Open a new tab.
1. Browse to [localhost:3000](http://localhost:3000).
1. In **email or username**, enter **admin**.
1. In **password**, enter **admin**.
1. Click **Log In**.
The first time you log in, you're asked to change your password:
1. In **New password**, enter your new password.
1. In **Confirm new password**, enter the same password.
1. Click **Save**.
The first thing you see is the Home dashboard, which helps you get started.
To the far left you can see the _sidebar_, a set of quick access icons for navigating Grafana.
## Add a metrics data source
The sample application exposes metrics which are stored in [Prometheus](https://prometheus.io/), a popular time series database (TSDB).
To be able to visualize the metrics from Prometheus, you first need to add it as a data source in Grafana.
1. In the sidebar, hover your cursor over the **Configuration** (gear) icon, and then click **Data sources**.
1. Click **Add data source**.
1. In the list of data sources, click **Prometheus**.
1. In the URL box, enter **http\://prometheus:9090**.
1. Click **Save & test**.
Prometheus is now available as a data source in Grafana.
## Explore your metrics
Grafana Explore is a workflow for troubleshooting and data exploration. In this step, you'll be using Explore to create ad-hoc queries to understand the metrics exposed by the sample application.
> Ad-hoc queries are queries that are made interactively, with the purpose of exploring data. An ad-hoc query is commonly followed by another, more specific query.
1. In the sidebar, click the **Explore** (compass) icon.
1. In the **Query editor**, where it says _Enter a PromQL query…_, enter `tns_request_duration_seconds_count` and then press Shift + Enter.
A graph appears.
1. In the top right corner, click the dropdown arrow on the **Run Query** button, and then select **5s**. Grafana runs your query and updates the graph every 5 seconds.
You just made your first _PromQL_ query! [PromQL](https://prometheus.io/docs/prometheus/latest/querying/basics/) is a powerful query language that lets you select and aggregate time series data stored in Prometheus.
`tns_request_duration_seconds_count` is a _counter_, a type of metric whose value only ever increases. Rather than visualizing the actual value, you can use counters to calculate the _rate of change_, i.e. how fast the value increases.
1. Add the [`rate`](https://prometheus.io/docs/prometheus/latest/querying/functions/#rate) function to your query to visualize the rate of requests per second. Enter the following in the **Query editor** and then press Shift + Enter.
```
rate(tns_request_duration_seconds_count[5m])
```
Immediately below the graph there's an area where each time series is listed with a colored icon next to it. This area is called the _legend_.
PromQL lets you group the time series by their labels, using the [`sum`](https://prometheus.io/docs/prometheus/latest/querying/operators/#aggregation-operators) aggregation operator.
1. Add the `sum` aggregation operator to your query to group time series by route:
```
sum(rate(tns_request_duration_seconds_count[5m])) by(route)
```
1. Go back to the [sample application](http://localhost:8081) and generate some traffic by adding new links, voting, or just refresh the browser.
1. In the upper-right corner, click the _time picker_, and select **Last 5 minutes**. By zooming in on the last few minutes, it's easier to see when you receive new data.
Depending on your use case, you might want to group on other labels. Try grouping by other labels, such as `status_code`, by changing the `by(route)` part of the query.
## Add a logging data source
Grafana supports log data sources, like [Loki](/oss/loki/). Just like for metrics, you first need to add your data source to Grafana.
1. In the sidebar, hover your cursor over the **Configuration** (gear) icon, and then click **Data Sources**.
1. Click **Add data source**.
1. In the list of data sources, click **Loki**.
1. In the URL box, enter [http://loki:3100](http://loki:3100).
1. Click **Save & Test** to save your changes.
Loki is now available as a data source in Grafana.
## Explore your logs
Grafana Explore not only lets you make ad-hoc queries for metrics, but lets you explore your logs as well.
1. In the sidebar, click the **Explore** (compass) icon.
1. In the data source list at the top, select the **Loki** data source.
1. In the **Query editor**, enter:
```
{filename="/var/log/tns-app.log"}
```
1. Grafana displays all logs within the log file of the sample application. The height of each bar in the graph encodes the number of logs that were generated at that time.
1. Click and drag across the bars in the graph to filter logs based on time.
Not only does Loki let you filter logs based on labels, but on specific occurrences.
Let's generate an error, and analyze it with Explore.
1. In the [sample application](http://localhost:8081), post a new link without a URL to generate an error in your browser that says `empty url`.
1. Go back to Grafana and enter the following query to filter log lines based on a substring:
```
{filename="/var/log/tns-app.log"} |= "error"
```
1. Click on the log line that says `level=error msg="empty url"` to see more information about the error.
> **Note:** If you're in Live mode, clicking logs will not show more information about the error. Instead, stop and exit the live stream, then click the log line there.
Logs are helpful for understanding what went wrong. Later in this tutorial, you'll see how you can correlate logs with metrics from Prometheus to better understand the context of the error.
## Build a dashboard
A _dashboard_ gives you an at-a-glance view of your data and lets you track metrics through different visualizations.
Dashboards consist of _panels_, each representing a part of the story you want your dashboard to tell.
Every panel consists of a _query_ and a _visualization_. The query defines _what_ data you want to display, whereas the visualization defines _how_ the data is displayed.
1. In the sidebar, hover your cursor over the **Create** (plus sign) icon and then click **Dashboard**.
1. Click **Add a new panel**.
1. In the **Query editor** below the graph, enter the query from earlier and then press Shift + Enter:
```
sum(rate(tns_request_duration_seconds_count[5m])) by(route)
```
1. In the **Legend** field, enter **{{route}}** to rename the time series in the legend. The graph legend updates when you click outside the field.
1. In the Panel editor on the right, under **Settings**, change the panel title to "Traffic".
1. Click **Apply** in the top-right corner to save the panel and go back to the dashboard view.
1. Click the **Save dashboard** (disk) icon at the top of the dashboard to save your dashboard.
1. Enter a name in the **Dashboard name** field and then click **Save**.
## Annotate events
When things go bad, it often helps if you understand the context in which the failure occurred. Time of last deploy, system changes, or database migration can offer insight into what might have caused an outage. Annotations allow you to represent such events directly on your graphs.
In the next part of the tutorial, we will simulate some common use cases that someone would add annotations for.
1. To manually add an annotation, click anywhere in your graph, then click **Add annotation**.
1. In **Description**, enter **Migrated user database**.
1. Click **Save**.
Grafana adds your annotation to the graph. Hover your mouse over the base of the annotation to read the text.
Grafana also lets you annotate a time interval, with _region annotations_.
Add a region annotation:
1. Press Ctrl (or Cmd on macOS), then click and drag across the graph to select an area.
1. In **Description**, enter **Performed load tests**.
1. In **Tags**, enter **testing**.
Manually annotating your dashboard is fine for those single events. For regularly occurring events, such as deploying a new release, Grafana supports querying annotations from one of your data sources. Let's create an annotation using the Loki data source we added earlier.
1. At the top of the dashboard, click the **Dashboard settings** (gear) icon.
1. Go to **Annotations** and click **Add annotation query**.
1. In **Name**, enter **Errors**.
1. In **Data source**, select **Loki**.
1. In **Query**, enter the following query:
```
{filename="/var/log/tns-app.log"} |= "error"
```
<!--this add button is gone rn. look into this -->
1. Click **Add**. Grafana displays the Annotations list, with your new annotation.
1. Click the **Go back** arrow to return to your dashboard.
1. At the top of your dashboard, there is now a toggle to display the results of the newly created annotation query. Press it so that it's enabled.
The log lines returned by your query are now displayed as annotations in the graph.
Being able to combine data from multiple data sources in one graph allows you to correlate information from both Prometheus and Loki.
Annotations also work very well alongside alerts. In the next and final section, we will set up an alert for our app `grafana.news` and then we will trigger it. This will provide a quick intro to our new Alerting platform.
## Create a Grafana Managed Alert
Alerts allow you to identify problems in your system moments after they occur. By quickly identifying unintended changes in your system, you can minimize disruptions to your services.
Grafana's new alerting platform debuted with Grafana 8. A year later, with Grafana 9, it became the default alerting method. In this step we will create a Grafana Managed Alert. Then we will trigger our new alert and send a test message to a dummy endpoint.
The most basic alert consists of two parts:
1. A _Contact Point_ - A Contact point defines how Grafana delivers an alert. When the conditions of an _alert rule_ are met, Grafana notifies the contact points, or channels, configured for that alert. Some popular channels include email, webhooks, Slack notifications, and PagerDuty notifications.
1. An _Alert rule_ - An Alert rule defines one or more _conditions_ that Grafana regularly evaluates. When these evaluations meet the rule's criteria, the alert is triggered.
To begin, let's set up a webhook Contact Point. Once we have a usable endpoint, we'll write an alert rule and trigger a notification.
### Create a Contact Point for Grafana Managed Alerts
In this step, we'll set up a new Contact Point. This contact point will use the _webhooks_ channel. In order to make this work, we also need an endpoint for our webhook channel to receive the alert. We will use [requestbin.com](https://requestbin.com) to quickly set up that test endpoint. This way we can make sure that our alert is actually sending a notification somewhere.
1. Browse to [requestbin.com](https://requestbin.com).
1. Under the **Create Request Bin** button, click the **public bin** link.
Your request bin is now waiting for the first request.
1. Copy the endpoint URL.
Next, let's configure a Contact Point in Grafana's Alerting UI to send notifications to our Request Bin.
1. Return to Grafana. In Grafana's sidebar, hover your cursor over the **Alerting** (bell) icon and then click **Contact points**.
1. Click **+ New contact point**.
1. In **Name**, write **RequestBin**.
1. In **Contact point type**, choose **Webhook**.
1. In **Url**, paste the endpoint to your request bin.
1. Click **Test** to send a test alert to your request bin.
1. Navigate back to the request bin you created earlier. On the left side, there's now a `POST /` entry. Click it to see what information Grafana sent.
1. Return to Grafana and click **Save contact point**.
We have now created a dummy webhook endpoint and created a new Alerting Contact Point in Grafana. Now we can create an alert rule and link it to this new channel.
### Add an Alert Rule to Grafana
Now that Grafana knows how to notify us, it's time to set up an alert rule:
1. In Grafana's sidebar, hover the cursor over the **Alerting** (bell) icon and then click **Alert rules**.
1. Click **+ New alert rule**.
1. For **Section 1**, name the rule `fundamentals-test`, and set **Rule type** to **Grafana Managed Alert**. For **Folder** type `fundamentals` and in the box that appears, press **Create: fundamentals**.
1. For **Section 2**, find the **query A** box. Choose your Prometheus datasource and enter the same query that we used in our earlier panel: `sum(rate(tns_request_duration_seconds_count[5m])) by(route)`. Press **Run queries**. You should see some data in the graph.
1. Now scroll down to the **query B** box. For **Operation** choose `Classic condition`. [You can read more about classic and multi-dimensional conditions here](/docs/grafana/latest/alerting/unified-alerting/alerting-rules/create-grafana-managed-rule/#single-and-multi-dimensional-rule). For conditions enter the following: `WHEN last() OF A IS ABOVE 0.2`
1. In **Section 3**, enter `30s` for the **Evaluate every** field. For the purposes of this tutorial, the evaluation interval is intentionally short. This makes it easier to test. In the **for** field, enter `0m`. This setting makes Grafana wait until an alert has fired for a given time before Grafana sends the notification.
1. In **Section 4**, you can add some sample text to your summary message. [Read more about message templating here](/docs/grafana/latest/alerting/unified-alerting/message-templating/).
1. Click **Save and exit** at the top of the page.
1. In Grafana's sidebar, hover the cursor over the **Alerting** (bell) icon and then click **Notification policies**.
1. Under **Root policy**, press **Edit** and change the **Default contact point** to **RequestBin**. As a system grows, admins can use the **Notification policies** setting to organize and match alert rules to specific contact points.
### Trigger a Grafana Managed Alert
We have now configured an alert rule and a contact point. Now let's see if we can trigger a Grafana Managed Alert by generating some traffic on our sample application.
1. Browse to [localhost:8081](http://localhost:8081).
1. Repeatedly click the vote button or refresh the page to generate a traffic spike.
Once the query `sum(rate(tns_request_duration_seconds_count[5m])) by(route)` returns a value greater than `0.2` Grafana will trigger our alert. Browse to the Request Bin we created earlier and find the sent Grafana alert notification with details and metadata.
## Summary
In this tutorial you learned about fundamental features of Grafana. To do so, we ran several Docker containers on your local machine. When you are ready to clean up this local tutorial environment, run the following command:
```
docker-compose down -v
```
### Learn more
Check out the links below to continue your learning journey with Grafana's LGTM stack.
- [Prometheus](/docs/grafana/latest/features/datasources/prometheus/)
- [Loki](/docs/grafana/latest/features/datasources/loki/)
- [Explore](/docs/grafana/latest/features/explore/)
- [Alerting Overview](/docs/grafana/latest/alerting/)
- [Alert rules](/docs/grafana/latest/alerting/create-alerts/)
- [Contact Points](/docs/grafana/latest/alerting/notifications/)

@ -1,146 +0,0 @@
---
title: Use IIS with URL Rewrite as a reverse proxy
summary: Learn how to set up Grafana behind IIS with URL Rewrite.
description: Learn how to set up Grafana behind IIS with URL Rewrite.
id: iis
categories: ['administration']
tags: ['advanced']
status: Published
authors: ['grafana_labs']
Feedback Link: https://github.com/grafana/tutorials/issues/new
aliases: ['/docs/grafana/latest/tutorials/iis/']
---
# Use IIS with URL Rewrite as a reverse proxy
If you want Grafana to be a subpath/subfolder under a website in IIS then the Application Request Routing (ARR) and URL Rewrite modules for ISS can be used to support this.
Example:
- Parent site: http://yourdomain.com:8080
- Grafana: http://localhost:3000
Grafana as a subpath: http://yourdomain.com:8080/grafana
Other Examples:
- If the application is only served on the local server, the parent site can also look like http://localhost:8080.
- If your domain is served using https on port 443, and thus the port is not normally entered in the address of your site, then the need to specify a port for the parent site in the configuration steps below can be eliminated.
## Setup
Install the URL Rewrite module for IIS.
- Download and install the URL Rewrite module for IIS: https://www.iis.net/downloads/microsoft/url-rewrite
You will also need the Application Request Routing (ARR) module for IIS for proxy forwarding
- Download and install ARR module for IIS: https://www.iis.net/downloads/microsoft/application-request-routing
## Grafana Config
The Grafana config can be set by creating a file named/editing the existing file named `custom.ini` in the `conf` subdirectory of your Grafana installation. See the [installation instructions](http://docs.grafana.org/installation/windows/#configure) for more details.
Using the example from above, if the subpath is `grafana` (you can set this to whatever is required) and the parent site is `yourdomain.com:8080`, then you would add this to the `custom.ini` config file:
```bash
[server]
domain = yourdomain.com:8080
root_url = %(protocol)s://%(domain)s/grafana/
```
Restart the Grafana server after changing the config file.
Configured address to serve Grafana: http://yourdomain.com:8080/grafana
---
If you already have a subpath on your domain, configure it as follows:
- Your Parent Site Address: http://yourdomain.com/existingsubpath
```bash
[server]
domain = yourdomain.com/existingsubpath
root_url = %(protocol)s://%(domain)s/grafana/
```
Restart the Grafana server after changing the config file.
Configured address to serve Grafana: http://yourdomain.com/existingsubpath/grafana
## IIS Config
### Step 1: Forward Proxy
1. Open the IIS Manager and click on the server
2. In the admin console for the server, double click on the Application Request Routing option:
3. Click the `Server Proxy Settings` action on the right-hand pane
4. Select the `Enable proxy` checkbox so that it is enabled
5. Click `Apply` and proceed with the URL Rewriting configuration
**Note:** If you don't enable the Forward Proxy, you will most likely get 404 Not Found if you only apply the URL Rewrite rule
### Step 2: URL Rewriting
1. In the IIS Manager, click on the website that grafana will run under. For example, select the website that is bound to the http://yourdomain.com domain.
2. In the admin console for this website, double click on the URL Rewrite option:
{{< figure src="/static/img/docs/tutorials/IIS_admin_console.png" max-width="800px" >}}
3. Click on the `Add Rule(s)...` action
4. Choose the Blank Rule template for an Inbound Rule
{{< figure src="/static/img/docs/tutorials/IIS_add_inbound_rule.png" max-width="800px" >}}
5. Create an Inbound Rule for the website with the following settings:
- pattern: `grafana(/)?(.*)` (if you have customised the subpath that will be used, use that instead of `grafana`)
- check the `Ignore case` checkbox
- rewrite URL set to `http://localhost:3000/{R:2}`
- check the `Append query string` checkbox
- check the `Stop processing of subsequent rules` checkbox
{{< figure src="/static/img/docs/tutorials/IIS_url_rewrite.png" max-width="800px" >}}
6. If your version of Grafana is greater than 8.3.5, you also need to configure the reverse proxy to preserve host headers.
- This can be achieved by configuring the IIS config file by running this in a cmd prompt
`%windir%\system32\inetsrv\appcmd.exe set config -section:system.webServer/proxy -preserveHostHeader:true /commit:apphost`
- More information here https://github.com/grafana/grafana/issues/45261
Finally, navigate to `http://yourdomain.com:8080/grafana` and you should come to the Grafana login page.
## Troubleshooting
### 404 error
When navigating to the Grafana URL (`http://yourdomain.com:8080/grafana`) and a `HTTP Error 404.0 - Not Found` error is returned, then either:
- The pattern for the Inbound Rule is incorrect. Edit the rule, click on the `Test pattern...` button, test the part of the URL after `http://yourdomain.com:8080/` and make sure it matches. For `grafana/login` the test should return 3 capture groups: {R:0}: `grafana` {R:1}: `/` and {R:2}: `login`.
- The `root_url` setting in the Grafana config file does not match the parent URL with subpath.
### Grafana Website only shows text with no images or css
{{< figure src="/static/img/docs/tutorials/IIS_proxy_error.png" max-width="800px" >}}
1. The `root_url` setting in the Grafana config file does not match the parent URL with subpath. This could happen if the root_url is commented out by mistake (`;` is used for commenting out a line in .ini files):
`; root_url = %(protocol)s://%(domain)s/grafana/`
2. or if the subpath in the `root_url` setting does not match the subpath used in the pattern in the Inbound Rule in IIS:
`root_url = %(protocol)s://%(domain)s/grafana/`
pattern in Inbound Rule: `wrongsubpath(/)?(.*)`
3. or if the Rewrite URL in the Inbound Rule is incorrect.
The Rewrite URL should not include the subpath.
The Rewrite URL should contain the capture group from the pattern matching that returns the part of the URL after the subpath. The pattern used above returns three capture groups and the third one {R:2} returns the part of the URL after `http://yourdomain.com:8080/grafana/`.
### You see an 'Error updating options: origin not allowed' error
- Ensure you have undertaken step 6 above, to configure IIS to preserve host headers by edit IIS config by running this in cmd prompt:
`%windir%\system32\inetsrv\appcmd.exe set config -section:system.webServer/proxy -preserveHostHeader:true /commit:apphost`

@ -1,147 +0,0 @@
---
title: Install Grafana on Raspberry Pi
summary: Get Grafana set up on your Raspberry Pi.
description: Get Grafana set up on your Raspberry Pi.
id: install-grafana-on-raspberry-pi
categories: ['administration']
tags: ['beginner']
authors: ['grafana_labs']
Feedback Link: https://github.com/grafana/tutorials/issues/new
---
## Introduction
The Raspberry Pi is a tiny, affordable, yet capable computer that can run a range of different applications. Even Grafana!
Many people are running Grafana on Raspberry Pi as a way to monitor their home, for things like indoor temperature, humidity, or energy usage.
In this tutorial, you'll:
- Set up a Raspberry Pi using a version of Raspberry Pi OS (previously called "Raspbian") that does not require you to connect a keyboard or monitor (this is often called "headless").
- Install Grafana on your Raspberry Pi.
{{% class "prerequisite-section" %}}
### Prerequisites
- Raspberry Pi
- SD card
{{% /class %}}
## Set up your Raspberry Pi
Before we can install Grafana, you first need to set up your Raspberry Pi.
For this tutorial, you'll configure your Raspberry Pi to be _headless_. This means you don't need to connect a monitor, keyboard, or mouse to your Raspberry Pi. All configuration is done from your regular computer.
#### Download and install Raspberry Pi Imager
Before we get started, you need to download and install the [Raspberry Pi Imager](https://www.raspberrypi.org/software/).
We'll use the Raspberry Pi Imager to flash the operating system image to the SD card. You download the imager directly from the official Raspberry Pi website and it's available for Ubuntu Linux, macOS, and Windows.
Follow the directions on the website to download and install the imager.
#### Install Raspberry Pi OS
Now it is time to install Raspberry Pi OS.
1. Insert the SD card into your regular computer from which you plan to install Raspberry Pi OS.
1. Run the Raspberry Pi Imager that you downloaded and installed.
1. To select an operating system, click **Choose OS** in the imager. You will be shown a list of available options.
1. From the list, select **Raspberry Pi OS (other)** and then select **Raspberry Pi OS Lite**, which is a Debian-based operating system for the Raspberry Pi. Since you're going to run a headless Raspberry Pi, you won't need the desktop dependencies.
1. To select where you want to put the operating system image, click **Choose Storage** in the imager and then select the SD card you already inserted into your computer.
1. The final step in the imager to click **Write**. When you do, the imager will write the Raspberry Pi OS Lite image to the SD card and verify that it has been written correctly.
1. Eject the SD card from your computer, and insert it again.
While you _could_ fire up the Raspberry Pi now, we don't yet have any way of accessing it.
1. Create an empty file called `ssh` in the boot directory. This enables SSH so that you can log in remotely.
The next step is only required if you want the Raspberry Pi to connect to your wireless network. Otherwise, connect the it to your network by using a network cable.
1. **(Optional)** Create a file called `wpa_supplicant.conf` in the boot directory:
```
ctrl_interface=/var/run/wpa_supplicant
update_config=1
country=<Insert 2 letter ISO 3166-1 country code here>
network={
ssid="<Name of your WiFi>"
psk="<Password for your WiFi>"
}
```
All the necessary files are now on the SD card. Let's start up the Raspberry Pi.
1. Eject the SD card and insert it into the SD card slot on the Raspberry Pi.
1. Connect the power cable and make sure the LED lights are on.
1. Find the IP address of the Raspberry Pi. Usually you can find the address in the control panel for your WiFi router.
#### Connect remotely via SSH
1. Open up your terminal and enter the following command:
```
ssh pi@<ip address>
```
1. SSH warns you that the authenticity of the host can't be established. Type "yes" to continue connecting.
1. When asked for a password, enter the default password: `raspberry`.
1. Once you're logged in, change the default password:
```
passwd
```
Congratulations! You've now got a tiny Linux machine running that you can hide in a closet and access from your normal workstation.
## Install Grafana
Now that you've got the Raspberry Pi up and running, the next step is to install Grafana.
1. Add the APT key used to authenticate packages:
```
wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add -
```
1. Add the Grafana APT repository:
```
echo "deb https://packages.grafana.com/oss/deb stable main" | sudo tee -a /etc/apt/sources.list.d/grafana.list
```
1. Install Grafana:
```
sudo apt-get update
sudo apt-get install -y grafana
```
Grafana is now installed, but not yet running. To make sure Grafana starts up even if the Raspberry Pi is restarted, we need to enable and start the Grafana Systemctl service.
1. Enable the Grafana server:
```
sudo /bin/systemctl enable grafana-server
```
1. Start the Grafana server:
```
sudo /bin/systemctl start grafana-server
```
Grafana is now running on the machine and is accessible from any device on the local network.
1. Open a browser and go to `http://<ip address>:3000`, where the IP address is the address that you used to connect to the Raspberry Pi earlier. You're greeted with the Grafana login page.
1. Log in to Grafana with the default username `admin`, and the default password `admin`.
1. Change the password for the admin user when asked.
Congratulations! Grafana is now running on your Raspberry Pi. If the Raspberry Pi is ever restarted or turned off, Grafana will start up whenever the machine regains power.
## Summary
If you want to use Grafana without having to go through a full installation process, check out [Grafana Cloud](/products/cloud/), which is designed to get users up and running quickly and easily. Grafana Cloud offers a forever free plan that is genuinely useful for hobbyists, testing, and small teams.
### Learn more
- [Raspberry Pi Documentation](https://www.raspberrypi.org/documentation/)

@ -1,118 +0,0 @@
---
title: Integrate Hubot with Grafana
summary: Learn how to integrate Hubot with Grafana
description: Learn how to integrate Hubot with Grafana
id: integrate-hubot
categories: ['administration']
tags: ['advanced']
status: Published
authors: ['grafana_labs']
Feedback Link: https://github.com/grafana/tutorials/issues/new
aliases: ['/docs/grafana/latest/tutorials/hubot_howto/']
---
# Integrate Hubot with Grafana
Grafana 2.0 shipped with a great feature that enables it to render any graph or panel to a PNG image.
No matter what data source you are using, the PNG image of the Graph will look the same as it does in your browser.
This guide will show you how to install and configure the [Hubot-Grafana](https://github.com/stephenyeargin/hubot-grafana) plugin. This plugin allows you to tell hubot to render any dashboard or graph right from a channel in Slack, Hipchat or Basecamp. The bot will respond with an image of the graph and a link that will take you to the graph.
> _Amazon S3 Required_: The hubot-grafana script will upload the rendered graphs to Amazon S3. This
> is so Hipchat and Slack can show them reliably (they require the image to be publicly available).
{{< figure src="/static/img/docs/tutorials/hubot_grafana.png" max-width="800px" >}}
## What is Hubot?
[Hubot](https://hubot.github.com/) is an universal and extensible chat bot that can be used with many chat services and has a huge library of third party plugins that allow you to automate anything from your chat rooms.
## Install Hubot
Hubot is very easy to install and host. If you do not already have a bot up and running please read the official [Getting Started With Hubot](https://hubot.github.com/docs/) guide.
## Install Hubot-Grafana script
In your Hubot project repo install the Grafana plugin using `npm`:
```bash
npm install hubot-grafana --save
```
Edit the file external-scripts.json, and add hubot-grafana to the list of plugins.
```json
["hubot-pugme", "hubot-shipit", "hubot-grafana"]
```
## Configure
The `hubot-grafana` plugin requires a number of environment variables to be set in order to work properly.
```bash
export HUBOT_GRAFANA_HOST=https://play.grafana.org
export HUBOT_GRAFANA_API_KEY=abcd01234deadbeef01234
export HUBOT_GRAFANA_S3_BUCKET=mybucket
export HUBOT_GRAFANA_S3_ACCESS_KEY_ID=ABCDEF123456XYZ
export HUBOT_GRAFANA_S3_SECRET_ACCESS_KEY=aBcD01234dEaDbEef01234
export HUBOT_GRAFANA_S3_PREFIX=graphs
export HUBOT_GRAFANA_S3_REGION=us-standard
```
### Grafana server side rendering
The hubot plugin will take advantage of the Grafana server side rendering feature that can render any panel on the server using phantomjs. Grafana ships with a phantomjs binary (Linux only).
To verify that this feature works try the `Direct link to rendered image` link in the panel share dialog. If you do not get an image when opening this link verify that the required font packages are installed for phantomjs to work.
### Grafana API Key
{{< figure src="/static/img/docs/v2/orgdropdown_api_keys.png" max-width="150px" class="docs-image--right">}}
You need to set the environment variable `HUBOT_GRAFANA_API_KEY` to a Grafana API Key. You can add these from the API Keys page which you find in the Organization dropdown.
### Amazon S3
The `S3` options are optional but for the images to work properly in services like Slack and Hipchat they need to publicly available. By specifying the `S3` options the hubot-grafana script will publish the rendered panel to `S3` and it will use that URL when it posts to Slack or Hipchat.
## Hubot commands
- `hubot graf list`
- Lists the available dashboards
- `hubot graf db graphite-carbon-metrics`
- Graph all panels in the dashboard
- `hubot graf db graphite-carbon-metrics:3`
- Graph only panel with id 3 of a particular dashboard
- `hubot graf db graphite-carbon-metrics:cpu`
- Graph only the panels containing "cpu" (case insensitive) in the title
- `hubot graf db graphite-carbon-metrics now-12hr`
- Get a dashboard with a window of 12 hours ago to now
- `hubot graf db graphite-carbon-metrics now-24hr now-12hr`
- Get a dashboard with a window of 24 hours ago to 12 hours ago
- `hubot graf db graphite-carbon-metrics:3 now-8d now-1d`
- Get only the third panel of a particular dashboard with a window of 8 days ago to yesterday
- `hubot graf db graphite-carbon-metrics host=carbon-a`
- Get a templated dashboard with the `$host` parameter set to `carbon-a`
## Aliases
Some of the hubot commands above can lengthy and you might have to remember the dashboard slug (url id). If you have a few favorite graphs you want to be able check up on often (let's say from your mobile) you can create hubot command aliases with the hubot script `hubot-alias`.
Install it:
```bash
npm i --save hubot-alias
```
Now add `hubot-alias` to the list of plugins in `external-scripts.json` and restart hubot.
Now you can add an alias like this:
- `hubot alias graf-lb=graf db loadbalancers:2 now-20m`
{{< figure src="/static/img/docs/tutorials/hubot_grafana2.png" max-width="800px" >}}
## Summary
Grafana is going to ship with integrated Slack and Hipchat features some day but you do not have to wait for that. Grafana 2 shipped with a very clever server side rendering feature that can render any panel to a png using phantomjs. The hubot plugin for Grafana is something you can install and use today!

@ -1,260 +0,0 @@
---
title: Provision dashboards and data sources
summary: Treat your configuration as code.
description: Treat your configuration as code.
id: provision-dashboards-and-data-sources
categories: ['administration']
tags: ['intermediate']
authors: ['grafana_labs']
Feedback Link: https://github.com/grafana/tutorials/issues/new
weight: 40
---
## Introduction
Learn how you can reuse dashboards and data sources across multiple teams by provisioning Grafana from version-controlled configuration files.
In this tutorial, you'll:
- Provision dashboards.
- Provision data sources.
{{% class "prerequisite-section" %}}
### Prerequisites
- Grafana 7.0
- Administrator privileges on the system you are doing the tutorial on
{{% /class %}}
## Configuration as code
Configuration as code is the practice of storing the configuration of your system as a set of version controlled, human-readable configuration files, rather than in a database. These configuration files can be reused across environments to avoid duplicated resources.
As the number of dashboards and data sources grows within your organization, manually managing changes can become tedious and error-prone. Encouraging reuse becomes important to avoid multiple teams redesigning the same dashboards.
Grafana supports configuration as code through _provisioning_. The resources that currently supports provisioning are:
- [Dashboards](/docs/grafana/latest/administration/provisioning/#dashboards)
- [Data sources](/docs/grafana/latest/administration/provisioning/#datasources)
- [Alert notification channels](/docs/grafana/latest/administration/provisioning/#alert-notification-channels)
## Set the provisioning directory
Before you can start provisioning resources, Grafana needs to know where to find the _provisioning directory_. The provisioning directory contains configuration files that are applied whenever Grafana starts and continuously updated while running.
By default, Grafana looks for a provisioning directory in the configuration directory (grafana > conf) on the system where Grafana is installed. However, if you are a Grafana Administrator, then you might want to place the config files in a shared resource like a network folder, so you would need to change the path to the provisioning directory.
You can set a different path by setting the `paths.provisioning` property in the main config file:
```ini
[paths]
provisioning = <path to config files>
```
For more information about configuration files, refer to [Configuration](/docs/grafana/latest/installation/configuration/) in the [Grafana documentation](/docs/grafana/latest/).
The provisioning directory assumes the following structure:
```
provisioning/
datasources/
<yaml files>
dashboards/
<yaml files>
notifiers/
<yaml files>
```
Next, we'll look at how to provision a data source.
## Provision a data source
Each data source provisioning config file contains a _manifest_ that specifies the desired state of a set of provisioned data sources.
At startup, Grafana loads the configuration files and provisions the data sources listed in the manifests.
Let's configure a [TestData DB](/docs/grafana/latest/features/datasources/testdata/) data source that you can use for your dashboards.
#### Create a data source manifest
1. In the `provisioning/datasources/` directory, create a file called `default.yaml` with the following content:
```yaml
apiVersion: 1
datasources:
- name: TestData DB
type: testdata
```
1. Restart Grafana to load the new changes.
1. In the sidebar, hover the cursor over the **Configuration** (gear) icon and click **Data Sources**. The TestData DB appears in the list of data sources.
> The configuration options can vary between different types of data sources. For more information on how to configure a specific data source, refer to [Data sources](/docs/grafana/latest/administration/provisioning/#datasources).
## Provision a dashboard
Each dashboard config file contains a manifest that specifies the desired state of a set of _dashboard providers_.
A dashboard provider tells Grafana where to find the dashboard definitions and where to put them.
Grafana regularly checks for changes to the dashboard definitions (by default every 10 seconds).
Let's define a dashboard provider so that Grafana knows where to find the dashboards we want to provision.
#### Define a dashboard provider
In the `provisioning/dashboards/` directory, create a file called `default.yaml` with the following content:
```yaml
apiVersion: 1
providers:
- name: Default # A uniquely identifiable name for the provider
folder: Services # The folder where to place the dashboards
type: file
options:
path:
<path to dashboard definitions>
# Default path for Windows: C:/Program Files/GrafanaLabs/grafana/public/dashboards
# Default path for Linux is: /var/lib/grafana/dashboards
```
For more information on how to configure dashboard providers, refer to [Dashboards](/docs/grafana/latest/administration/provisioning/#dashboards).
#### Create a dashboard definition
1. In the dashboard definitions directory you specified in the dashboard provider, i.e. `options.path`, create a file called `cluster.json` with the following content:
```json
{
"__inputs": [],
"__requires": [],
"annotations": {
"list": []
},
"editable": false,
"gnetId": null,
"graphTooltip": 0,
"hideControls": false,
"id": null,
"links": [],
"panels": [
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "TestData DB",
"fill": 1,
"gridPos": {
"h": 8,
"w": 24,
"x": 0,
"y": 0
},
"id": 2,
"legend": {
"alignAsTable": false,
"avg": false,
"current": false,
"max": false,
"min": false,
"rightSide": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"repeat": null,
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "CPU Usage",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
}
],
"refresh": "",
"rows": [],
"schemaVersion": 16,
"style": "dark",
"tags": ["kubernetes"],
"templating": {
"list": []
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {
"refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"],
"time_options": ["5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d"]
},
"timezone": "browser",
"title": "Cluster",
"version": 0
}
```
1. Restart Grafana to provision the new dashboard or wait 10 seconds for Grafana to automatically create the dashboard.
1. In the sidebar, hover the cursor over **Dashboards** (squares) icon, and then click **Manage**. The dashboard appears in a **Services** folder.
> If you don't specify an `id` in the dashboard definition, then Grafana assigns one during provisioning. You can set the `id` yourself if you want to reference the dashboard from other dashboards. Be careful to not use the same `id` for multiple dashboards, as this will cause a conflict.
## Summary
In this tutorial you learned how you to reuse dashboards and data sources across multiple teams by provisioning Grafana from version-controlled configuration files.
Dashboard definitions can get unwieldy as more panels and configurations are added to them. There are a number of open source tools available to make it easier to manage dashboard definitions:
- [grafana-dash-gen](https://github.com/uber/grafana-dash-gen) (Javascript)
- [grafanalib](https://github.com/weaveworks/grafanalib) (Python)
- [grafonnet-lib](https://github.com/grafana/grafonnet-lib) (Jsonnet)
- [grafyaml](https://docs.openstack.org/infra/grafyaml/) (YAML)
### Learn more
- [Provisioning Grafana](/docs/grafana/latest/administration/provisioning/)

@ -1,222 +0,0 @@
---
title: Run Grafana behind a reverse proxy
summary: Learn how to run Grafana behind a reverse proxy
description: Learn how to run Grafana behind a reverse proxy
id: run-grafana-behind-a-proxy
categories: ['administration']
tags: ['advanced']
status: Published
authors: ['grafana_labs']
Feedback Link: https://github.com/grafana/tutorials/issues/new
aliases: ['/docs/grafana/latest/installation/behind_proxy/']
---
## Introduction
In this tutorial, you'll configure Grafana to run behind a reverse proxy.
When running Grafana behind a proxy, you need to configure the domain name to let Grafana know how to render links and redirects correctly.
- In the Grafana configuration file, change `server.domain` to the domain name you'll be using:
```bash
[server]
domain = example.com
```
- Restart Grafana for the new changes to take effect.
You can also serve Grafana behind a _sub path_, such as `http://example.com/grafana`.
To serve Grafana behind a sub path:
- Include the sub path at the end of the `root_url`.
- Set `serve_from_sub_path` to `true`.
```bash
[server]
domain = example.com
root_url = %(protocol)s://%(domain)s:%(http_port)s/grafana/
serve_from_sub_path = true
```
Next, you need to configure your reverse proxy.
## Configure NGINX
[NGINX](https://www.nginx.com) is a high performance load balancer, web server, and reverse proxy.
- In your NGINX configuration file inside `http` section, add the following:
```nginx
# this is required to proxy Grafana Live WebSocket connections.
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream grafana {
server localhost:3000;
}
server {
listen 80;
root /usr/share/nginx/html;
index index.html index.htm;
location / {
proxy_set_header Host $http_host;
proxy_pass http://grafana;
}
# Proxy Grafana Live WebSocket connections.
location /api/live/ {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $http_host;
proxy_pass http://grafana;
}
}
```
- Reload the NGINX configuration.
- Navigate to port 80 on the machine NGINX is running on. You're greeted by the Grafana login page.
For Grafana Live which uses WebSocket connections you may have to raise Nginx [worker_connections](https://nginx.org/en/docs/ngx_core_module.html#worker_connections) option which is 512 by default – which limits the number of possible concurrent connections with Grafana Live.
Also, be aware that the above configuration will work only when the `proxy_pass` value for `location /` is a literal string. If you are using a variable here, [read this GitHub issue](https://github.com/grafana/grafana/issues/18299). You will need to add [an appropriate NGINX rewrite rule](https://www.nginx.com/blog/creating-nginx-rewrite-rules/).
To configure NGINX to serve Grafana under a _sub path_, update the `location` block:
```nginx
# this is required to proxy Grafana Live WebSocket connections.
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream grafana {
server localhost:3000;
}
server {
listen 80;
root /usr/share/nginx/www;
index index.html index.htm;
location /grafana/ {
rewrite ^/grafana/(.*) /$1 break;
proxy_set_header Host $http_host;
proxy_pass http://grafana;
}
# Proxy Grafana Live WebSocket connections.
location /grafana/api/live/ {
rewrite ^/grafana/(.*) /$1 break;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $http_host;
proxy_pass http://grafana;
}
}
```
## Configure HAProxy
To configure HAProxy to serve Grafana under a _sub path_:
```bash
frontend http-in
bind *:80
use_backend grafana_backend if { path /grafana } or { path_beg /grafana/ }
backend grafana_backend
# Requires haproxy >= 1.6
http-request set-path %[path,regsub(^/grafana/?,/)]
# Works for haproxy < 1.6
# reqrep ^([^\ ]*\ /)grafana[/]?(.*) \1\2
server grafana localhost:3000
```
## Configure IIS
> IIS requires that the URL Rewrite module is installed.
To configure IIS to serve Grafana under a _sub path_, create an Inbound Rule for the parent website in IIS Manager with the following settings:
- pattern: `grafana(/)?(.*)`
- check the `Ignore case` checkbox
- rewrite URL set to `http://localhost:3000/{R:2}`
- check the `Append query string` checkbox
- check the `Stop processing of subsequent rules` checkbox
This is the rewrite rule that is generated in the `web.config`:
```xml
<rewrite>
<rules>
<rule name="Grafana" enabled="true" stopProcessing="true">
<match url="grafana(/)?(.*)" />
<action type="Rewrite" url="http://localhost:3000/{R:2}" logRewrittenUrl="false" />
</rule>
</rules>
</rewrite>
```
See the [tutorial on IIS URL Rewrites](/tutorials/iis/) for more in-depth instructions.
## Configure Traefik
[Traefik](https://traefik.io/traefik/) Cloud Native Reverse Proxy / Load Balancer / Edge Router
Using the docker provider the following labels will configure the router and service for a domain or subdomain routing.
```yaml
labels:
traefik.http.routers.grafana.rule: Host(`grafana.example.com`)
traefik.http.services.grafana.loadbalancer.server.port: 3000
```
To deploy on a _sub path_
```yaml
labels:
traefik.http.routers.grafana.rule: Host(`example.com`) && PathPrefix(`/grafana`)
traefik.http.services.grafana.loadbalancer.server.port: 3000
```
Examples using the file provider.
```yaml
http:
routers:
grafana:
rule: Host(`grafana.example.com`)
service: grafana
services:
grafana:
loadBalancer:
servers:
- url: http://192.168.30.10:3000
```
```yaml
http:
routers:
grafana:
rule: Host(`example.com`) && PathPrefix(`/grafana`)
service: grafana
services:
grafana:
loadBalancer:
servers:
- url: http://192.168.30.10:3000
```
## Summary
In this tutorial you learned how to run Grafana behind a reverse proxy.

@ -1,101 +0,0 @@
---
title: Stream metrics from Telegraf to Grafana
summary: Use Telegraf to stream live metrics to Grafana.
description: Use Telegraf to stream live metrics to Grafana.
id: stream-metrics-from-telegraf-to-grafana
categories: ['administration']
tags: ['beginner']
status: Published
authors: ['grafana_labs']
Feedback Link: https://github.com/grafana/tutorials/issues/new
weight: 75
---
## Introduction
Grafana v8 introduced streaming capabilities – a way to push data to UI panels in near real-time. In this tutorial we show how Grafana real-time streaming capabilities can be used together with Telegraf to instantly display system measurements.
In this tutorial, you'll:
- Setup Telegraf and output measurements directly to Grafana time-series panel in near real-time
{{% class "prerequisite-section" %}}
#### Prerequisites
- Grafana 8.0+
- Telegraf
{{% /class %}}
## Run Grafana and create admin token
1. Run Grafana following [installation instructions](/docs/grafana/latest/installation/) for your operating system
1. Log in and go to Configuration -> API Keys
1. Press "Add API key" button and create a new API token with **Admin** role
## Configure and run Telegraf
Telegraf is a plugin-driven server agent for collecting and sending metrics and events from databases, systems, and IoT sensors.
You can install it following [official installation instructions](https://docs.influxdata.com/telegraf/latest/introduction/installation/).
In this tutorial we will be using Telegraf HTTP output plugin to send metrics in Influx format to Grafana. We can use a configuration like this:
```
[agent]
interval = "1s"
flush_interval = "1s"
[[inputs.cpu]]
percpu = false
totalcpu = true
[[outputs.http]]
url = "http://localhost:3000/api/live/push/custom_stream_id"
data_format = "influx"
[outputs.http.headers]
Authorization = "Bearer <Your API Key>"
```
Make sure to replace `<Your API Key>` placeholder with your actual API key created in the previous step. Save this config into `telegraf.conf` file and run Telegraf pointing to this config file. Telegraf will periodically (once in a second) report the state of total CPU usage on a host to Grafana (which is supposed to be running on `http://localhost:3000`). Of course you can replace `custom_stream_id` to something more meaningful for your use case.
Inside Grafana Influx data is converted to Grafana data frames and then frames are published to Grafana Live channels. In this case, the channel where CPU data will be published is `stream/custom_stream_id/cpu`. The `stream` scope is constant, the `custom_stream_id` namespace is the last part of API URL set in Telegraf configuration (`http://localhost:3000/api/live/push/telegraf`) and the path is `cpu` - the name of a measurement.
The only thing left here is to create a dashboard with streaming data.
## Create dashboard with streaming data
1. Create new dashboard
1. Press Add empty panel
1. Select `-- Grafana --` datasource
1. Select `Live Measurements` query type
1. Find and select `stream/custom_stream_id/cpu` measurement for Channel field
1. Save dashboard changes
After making these steps Grafana UI should subscribe to the channel `stream/custom_stream_id/cpu` and you should see CPU data updates coming from Telegraf in near real-time.
## Stream using WebSocket endpoint
If you aim for a high-frequency update sending then you may want to use the WebSocket output plugin of Telegraf (introduced in Telegraf v1.19.0) instead of the HTTP output plugin we used above. Configure WebSocket output plugin like this:
```
[agent]
interval = "500ms"
flush_interval = "500ms"
[[inputs.cpu]]
percpu = false
totalcpu = true
[[outputs.websocket]]
url = "ws://localhost:3000/api/live/push/custom_stream_id"
data_format = "influx"
[outputs.websocket.headers]
Authorization = "Bearer <Your API Key>"
```
WebSocket avoids running all Grafana HTTP middleware on each request from Telegraf thus reducing Grafana backend CPU usage significantly.
## Summary
In this tutorial you learned how to use Telegraf to stream live metrics to Grafana.
Loading…
Cancel
Save