mirror of
https://github.com/grafana/grafana.git
synced 2025-07-28 19:02:29 +08:00
Docs: Plugin doc review for chunk 1-A (#67070)
* Plugin doc review for chunk 1-A Signed-off-by: Joe Perez <joseph.perez@grafana.com> * Group of fixes in response to review comments Signed-off-by: Joe Perez <joseph.perez@grafana.com> * Updates for review comments Signed-off-by: Joe Perez <joseph.perez@grafana.com> * Fixed extra space Signed-off-by: Joe Perez <joseph.perez@grafana.com> * Additional doc fixes Signed-off-by: Joe Perez <joseph.perez@grafana.com> * More doc fixes Signed-off-by: Joe Perez <joseph.perez@grafana.com> * Fixes from doc review Signed-off-by: Joe Perez <joseph.perez@grafana.com> * Doc review fixes Signed-off-by: Joe Perez <joseph.perez@grafana.com> * More changes from doc review Signed-off-by: Joe Perez <joseph.perez@grafana.com> * Fix links and relrefs using doc-validator advice Signed-off-by: Jack Baldry <jack.baldry@grafana.com> * Publishing criteria update Signed-off-by: Joe Perez <joseph.perez@grafana.com> * Markdown fix Signed-off-by: Joe Perez <joseph.perez@grafana.com> * Fixes Signed-off-by: Joe Perez <joseph.perez@grafana.com> * Testing Signed-off-by: Joe Perez <joseph.perez@grafana.com> * Testing Signed-off-by: Joe Perez <joseph.perez@grafana.com> * Testing Signed-off-by: Joe Perez <joseph.perez@grafana.com> * Link fix Signed-off-by: Joe Perez <joseph.perez@grafana.com> * Prettier Signed-off-by: Joe Perez <joseph.perez@grafana.com> * Fix to publishing criteria Signed-off-by: Joe Perez <joseph.perez@grafana.com> * Doc fix Signed-off-by: Joe Perez <joseph.perez@grafana.com> * Doc fix Signed-off-by: Joe Perez <joseph.perez@grafana.com> * Doc fix Signed-off-by: Joe Perez <joseph.perez@grafana.com> * Update docs/sources/developers/plugins/_index.md Co-authored-by: Kim Nylander <104772500+knylander-grafana@users.noreply.github.com> * Update docs/sources/developers/plugins/_index.md Co-authored-by: Kim Nylander <104772500+knylander-grafana@users.noreply.github.com> * Update docs/sources/developers/plugins/_index.md Co-authored-by: Kim Nylander <104772500+knylander-grafana@users.noreply.github.com> * Update docs/sources/developers/plugins/_index.md Co-authored-by: Kim Nylander <104772500+knylander-grafana@users.noreply.github.com> * Update docs/sources/developers/plugins/_index.md Co-authored-by: Kim Nylander <104772500+knylander-grafana@users.noreply.github.com> * Update docs/sources/developers/plugins/_index.md Co-authored-by: Kim Nylander <104772500+knylander-grafana@users.noreply.github.com> * Update docs/sources/developers/plugins/_index.md Co-authored-by: Kim Nylander <104772500+knylander-grafana@users.noreply.github.com> * Update docs/sources/developers/plugins/_index.md Co-authored-by: Kim Nylander <104772500+knylander-grafana@users.noreply.github.com> * Update docs/sources/developers/plugins/_index.md Co-authored-by: Kim Nylander <104772500+knylander-grafana@users.noreply.github.com> * Update docs/sources/developers/plugins/build-a-logs-data-source-plugin.md Co-authored-by: Kim Nylander <104772500+knylander-grafana@users.noreply.github.com> * Update docs/sources/developers/plugins/build-a-streaming-data-source-plugin.md Co-authored-by: Kim Nylander <104772500+knylander-grafana@users.noreply.github.com> * Update docs/sources/developers/plugins/build-a-streaming-data-source-plugin.md Co-authored-by: Kim Nylander <104772500+knylander-grafana@users.noreply.github.com> * Update docs/sources/developers/plugins/get-started-with-plugins/_index.md Co-authored-by: Kim Nylander <104772500+knylander-grafana@users.noreply.github.com> * Update docs/sources/developers/plugins/publish-a-plugin.md Co-authored-by: Kim Nylander <104772500+knylander-grafana@users.noreply.github.com> * Update docs/sources/developers/plugins/publish-a-plugin.md Co-authored-by: Kim Nylander <104772500+knylander-grafana@users.noreply.github.com> * Update docs/sources/developers/plugins/publish-a-plugin.md Co-authored-by: Kim Nylander <104772500+knylander-grafana@users.noreply.github.com> * Update docs/sources/developers/plugins/sign-a-plugin.md Co-authored-by: Kim Nylander <104772500+knylander-grafana@users.noreply.github.com> * Prettier Signed-off-by: Joe Perez <joseph.perez@grafana.com> --------- Signed-off-by: Joe Perez <joseph.perez@grafana.com> Signed-off-by: Jack Baldry <jack.baldry@grafana.com> Co-authored-by: Jack Baldry <jack.baldry@grafana.com> Co-authored-by: Kim Nylander <104772500+knylander-grafana@users.noreply.github.com>
This commit is contained in:
@ -4,100 +4,112 @@ title: Build a streaming data source plugin
|
||||
|
||||
# Build a streaming data source plugin
|
||||
|
||||
This guide explains how to build a streaming data source plugin.
|
||||
In Grafana, you can set your dashboards to automatically refresh at a certain interval, no matter what data source you use. Unfortunately, this means that your queries are requesting all the data to be sent again, regardless of whether the data has actually changed. Adding streaming to a plugin helps reduce queries so your dashboard is only updated when new data becomes available.
|
||||
|
||||
## Before you begin
|
||||
|
||||
This guide assumes that you're already familiar with how to [Build a data source plugin](/tutorials/build-a-data-source-plugin/).
|
||||
|
||||
When monitoring critical applications, you want your dashboard to refresh as soon as your data does. In Grafana, you can set your dashboards to automatically refresh at a certain interval, no matter what data source you use. Unfortunately, this means that your queries are requesting all the data to be sent again, regardless of whether the data has actually changed.
|
||||
Grafana uses [RxJS](https://rxjs.dev/) to continuously send data from a data source to a panel visualization.
|
||||
|
||||
By enabling _streaming_ for your data source plugin, you can update your dashboard as soon as new data becomes available.
|
||||
> **Note:** To learn more about RxJs, refer to the [RxJS documentation](https://rxjs.dev/guide/overview).
|
||||
|
||||
## Add streaming to your data source
|
||||
|
||||
Enable streaming for your data source plugin to update your dashboard when new data becomes available.
|
||||
|
||||
For example, a streaming data source plugin can connect to a websocket, or subscribe to a message bus, and update the visualization whenever a new message is available.
|
||||
|
||||
Let's see how you can add streaming to an existing data source!
|
||||
### Step 1: Edit the `plugin.json` file
|
||||
|
||||
Grafana uses [RxJS](https://rxjs.dev/) to continuously send data from a data source to a panel visualization. There's a lot more to RxJS than what's covered in this guide. If you want to learn more, check out the [RxJS documentation](https://rxjs.dev/guide/overview).
|
||||
Enable streaming for your data source in the `plugin.json` file.
|
||||
|
||||
1. Enable streaming for your data source in the `plugin.json` file.
|
||||
```json
|
||||
{
|
||||
"streaming": true
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"streaming": true
|
||||
}
|
||||
```
|
||||
### Step 2: Change the signature of the `query` method
|
||||
|
||||
1. Change the signature of the `query` method to return an `Observable` from the `rxjs` package. Make sure you remove the `async` keyword.
|
||||
Modify the signature of the `query` method to return an `Observable` from the `rxjs` package. Make sure you remove the `async` keyword.
|
||||
|
||||
```ts
|
||||
import { Observable } from 'rxjs';
|
||||
```
|
||||
```ts
|
||||
import { Observable } from 'rxjs';
|
||||
```
|
||||
|
||||
```ts
|
||||
query(options: DataQueryRequest<MyQuery>): Observable<DataQueryResponse> {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
```ts
|
||||
query(options: DataQueryRequest<MyQuery>): Observable<DataQueryResponse> {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
1. Create an `Observable` for each query, and then combine them all using the `merge` function from the `rxjs` package.
|
||||
### Step 3: Create an `Observable` instance for each query
|
||||
|
||||
```ts
|
||||
import { Observable, merge } from 'rxjs';
|
||||
```
|
||||
Create an `Observable` instance for each query, and then combine them all using the `merge` function from the `rxjs` package.
|
||||
|
||||
```ts
|
||||
const observables = options.targets.map((target) => {
|
||||
return new Observable<DataQueryResponse>((subscriber) => {
|
||||
// ...
|
||||
});
|
||||
});
|
||||
```ts
|
||||
import { Observable, merge } from 'rxjs';
|
||||
```
|
||||
|
||||
return merge(...observables);
|
||||
```
|
||||
```ts
|
||||
const observables = options.targets.map((target) => {
|
||||
return new Observable<DataQueryResponse>((subscriber) => {
|
||||
// ...
|
||||
});
|
||||
});
|
||||
|
||||
1. In the `subscribe` function, create a `CircularDataFrame`.
|
||||
return merge(...observables);
|
||||
```
|
||||
|
||||
```ts
|
||||
import { CircularDataFrame } from '@grafana/data';
|
||||
```
|
||||
### Step 4: Create a `CircularDataFrame` instance
|
||||
|
||||
```ts
|
||||
const frame = new CircularDataFrame({
|
||||
append: 'tail',
|
||||
capacity: 1000,
|
||||
});
|
||||
In the `subscribe` function, create a `CircularDataFrame` instance.
|
||||
|
||||
frame.refId = query.refId;
|
||||
frame.addField({ name: 'time', type: FieldType.time });
|
||||
frame.addField({ name: 'value', type: FieldType.number });
|
||||
```
|
||||
```ts
|
||||
import { CircularDataFrame } from '@grafana/data';
|
||||
```
|
||||
|
||||
Circular data frames have a limited capacity. When a circular data frame reaches its capacity, the oldest data point is removed.
|
||||
```ts
|
||||
const frame = new CircularDataFrame({
|
||||
append: 'tail',
|
||||
capacity: 1000,
|
||||
});
|
||||
|
||||
1. Use `subscriber.next()` to send the updated data frame whenever you receive new updates.
|
||||
frame.refId = query.refId;
|
||||
frame.addField({ name: 'time', type: FieldType.time });
|
||||
frame.addField({ name: 'value', type: FieldType.number });
|
||||
```
|
||||
|
||||
```ts
|
||||
import { LoadingState } from '@grafana/data';
|
||||
```
|
||||
Circular data frames have a limited capacity. When a circular data frame reaches its capacity, the oldest data point is removed.
|
||||
|
||||
```ts
|
||||
const intervalId = setInterval(() => {
|
||||
frame.add({ time: Date.now(), value: Math.random() });
|
||||
### Step 5: Send the updated data frame
|
||||
|
||||
subscriber.next({
|
||||
data: [frame],
|
||||
key: query.refId,
|
||||
state: LoadingState.Streaming,
|
||||
});
|
||||
}, 500);
|
||||
Use `subscriber.next()` to send the updated data frame whenever you receive new updates.
|
||||
|
||||
return () => {
|
||||
clearInterval(intervalId);
|
||||
};
|
||||
```
|
||||
```ts
|
||||
import { LoadingState } from '@grafana/data';
|
||||
```
|
||||
|
||||
> **Note:** In practice, you'd call `subscriber.next` as soon as you receive new data from a websocket or a message bus. The example above simulates data being received every 500 milliseconds.
|
||||
```ts
|
||||
const intervalId = setInterval(() => {
|
||||
frame.add({ time: Date.now(), value: Math.random() });
|
||||
|
||||
Here's the final `query` method.
|
||||
subscriber.next({
|
||||
data: [frame],
|
||||
key: query.refId,
|
||||
state: LoadingState.Streaming,
|
||||
});
|
||||
}, 500);
|
||||
|
||||
return () => {
|
||||
clearInterval(intervalId);
|
||||
};
|
||||
```
|
||||
|
||||
> **Note:** In practice, you'd call `subscriber.next` as soon as you receive new data from a websocket or a message bus. In the example above, data is being received every 500 milliseconds.
|
||||
|
||||
### Example code for final `query` method
|
||||
|
||||
```ts
|
||||
query(options: DataQueryRequest<MyQuery>): Observable<DataQueryResponse> {
|
||||
@ -134,4 +146,6 @@ query(options: DataQueryRequest<MyQuery>): Observable<DataQueryResponse> {
|
||||
}
|
||||
```
|
||||
|
||||
One limitation with this example is that the panel visualization is cleared every time you update the dashboard. If you have access to historical data, you can add, or _backfill_, it to the data frame before the first call to `subscriber.next()`.
|
||||
One limitation with this example is that the panel visualization is cleared every time you update the dashboard. If you have access to historical data, you can add it, or _backfill_ it, to the data frame before the first call to `subscriber.next()`.
|
||||
|
||||
For another example of a streaming plugin, refer to the [streaming websocket example](https://github.com/grafana/grafana-plugin-examples/tree/main/examples/datasource-streaming-websocket) on GitHub.
|
||||
|
Reference in New Issue
Block a user