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>
(cherry picked from commit 13be068919)
Co-authored-by: Joseph Perez <45749060+josmperez@users.noreply.github.com>
4.5 KiB
title
| title |
|---|
| Build a streaming data source plugin |
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.
Grafana uses RxJS to continuously send data from a data source to a panel visualization.
Note: To learn more about RxJs, refer to the RxJS documentation.
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.
Step 1: Edit the plugin.json file
Enable streaming for your data source in the plugin.json file.
{
"streaming": true
}
Step 2: Change the signature of the query method
Modify the signature of the query method to return an Observable from the rxjs package. Make sure you remove the async keyword.
import { Observable } from 'rxjs';
query(options: DataQueryRequest<MyQuery>): Observable<DataQueryResponse> {
// ...
}
Step 3: Create an Observable instance for each query
Create an Observable instance for each query, and then combine them all using the merge function from the rxjs package.
import { Observable, merge } from 'rxjs';
const observables = options.targets.map((target) => {
return new Observable<DataQueryResponse>((subscriber) => {
// ...
});
});
return merge(...observables);
Step 4: Create a CircularDataFrame instance
In the subscribe function, create a CircularDataFrame instance.
import { CircularDataFrame } from '@grafana/data';
const frame = new CircularDataFrame({
append: 'tail',
capacity: 1000,
});
frame.refId = query.refId;
frame.addField({ name: 'time', type: FieldType.time });
frame.addField({ name: 'value', type: FieldType.number });
Circular data frames have a limited capacity. When a circular data frame reaches its capacity, the oldest data point is removed.
Step 5: Send the updated data frame
Use subscriber.next() to send the updated data frame whenever you receive new updates.
import { LoadingState } from '@grafana/data';
const intervalId = setInterval(() => {
frame.add({ time: Date.now(), value: Math.random() });
subscriber.next({
data: [frame],
key: query.refId,
state: LoadingState.Streaming,
});
}, 500);
return () => {
clearInterval(intervalId);
};
Note: In practice, you'd call
subscriber.nextas 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
query(options: DataQueryRequest<MyQuery>): Observable<DataQueryResponse> {
const streams = options.targets.map(target => {
const query = defaults(target, defaultQuery);
return new Observable<DataQueryResponse>(subscriber => {
const frame = new CircularDataFrame({
append: 'tail',
capacity: 1000,
});
frame.refId = query.refId;
frame.addField({ name: 'time', type: FieldType.time });
frame.addField({ name: 'value', type: FieldType.number });
const intervalId = setInterval(() => {
frame.add({ time: Date.now(), value: Math.random() });
subscriber.next({
data: [frame],
key: query.refId,
state: LoadingState.Streaming,
});
}, 100);
return () => {
clearInterval(intervalId);
};
});
});
return merge(...streams);
}
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 on GitHub.