Module grafana_plugin_sdk::backend
source · Expand description
Functionality for use by backend plugins.
Backend plugins are executables that expose a gRPC server, which Grafana uses to communicate all information. This SDK uses tonic as its gRPC implementation.
The basic requirements for a backend plugin are to provide a main
function which:
- first, calls the
initialize
function from this module to initialize the plugin. This must be done before any other code can output to stdout or stderr! - performs any setup required by the plugin (such as connecting to databases or initializing any state)
- creates the struct representing the plugin’s services, which should implement one of the various traits exposed by this module
- create a
Plugin
to manage the plugin’s lifecycle with Grafana - use the
Plugin::*_service
methods to attach your plugin - begin serving on the listener returned by
initialize
usingPlugin::start
.
If you’re not sure where to start, take a look at the Plugin
struct, its four important methods, and
the trait bounds for each of them - those give an idea of what your plugin will need to implement.
Logging and tracing
The SDK provides a preconfigured tracing_subscriber::fmt::Layer
which, when installed,
will emit structured logs in a format understood by Grafana. Use the layer
function
to get the Layer
, and install it using tracing_subscriber::Registry::with
. Alternatively
use Plugin::init_subscriber
to automatically install a subscriber using the RUST_LOG
environment variable to set the directive (defaulting to info
if not set).
Once the layer is installed, any logs emitted by the various log
or tracing
macros
will be emitted to Grafana.
Example
use futures_util::stream::FuturesOrdered;
use grafana_plugin_sdk::{backend, data, prelude::*};
use thiserror::Error;
use tonic::transport::Server;
use tracing::info;
#[derive(Clone, Debug)]
struct MyPlugin;
/// An error that may occur during a query.
///
/// This must store the `ref_id` of the query so that Grafana can line it up.
#[derive(Debug, Error)]
#[error("Error querying backend for query {ref_id}: {source}")]
struct QueryError {
source: data::Error,
ref_id: String,
}
impl backend::DataQueryError for QueryError {
fn ref_id(self) -> String {
self.ref_id
}
}
#[tonic::async_trait]
impl backend::DataService for MyPlugin {
/// The type of JSON data sent from Grafana to our backend plugin.
///
/// This will correspond to the `TQuery` type parameter of the frontend
/// datasource.
///
/// We can use `serde_json::Value` if we want to accept any JSON.
type Query = serde_json::Value;
/// The type of error that could be returned by an individual query.
type QueryError = QueryError;
/// The type of iterator we're returning.
///
/// In general the concrete type will be impossible to name in advance,
/// so the `backend::BoxDataResponseStream` type alias will be useful.
type Stream = backend::BoxDataResponseStream<Self::QueryError>;
/// Respond to a request for data from Grafana.
///
/// This request will contain zero or more queries, as well as information
/// about the datasource instance on behalf of which this request is made,
/// such as address, credentials, etc.
///
/// Our plugin must respond to each query and return an iterator of `DataResponse`s,
/// which themselves can contain zero or more `Frame`s.
async fn query_data(&self, request: backend::QueryDataRequest<Self::Query>) -> Self::Stream {
Box::pin(
request
.queries
.into_iter()
.map(|x| async {
// Here we create a single response Frame for each query.
// Frames can be created from iterators of fields using [`IntoFrame`].
Ok(backend::DataResponse::new(
x.ref_id.clone(),
// Return zero or more frames.
// A real implementation would fetch this data from a database
// or something.
vec![[
[1_u32, 2, 3].into_field("x"),
["a", "b", "c"].into_field("y"),
]
.into_frame("foo")
.check()
.map_err(|source| QueryError {
ref_id: x.ref_id,
source,
})?],
))
})
.collect::<FuturesOrdered<_>>(),
)
}
}
#[grafana_plugin_sdk::main(services(data))]
async fn plugin() -> MyPlugin {
// Create our plugin struct. Any state, such as a database connection, should be
// held here, perhaps inside an `Arc` if required.
MyPlugin
}
Structs
- Settings for an app instance.
- A request for a resource call.
- A request to check the health of a plugin.
- The response to a health check request.
- A request to collect metrics about a plugin.
- A response to a metric collection request.
- A query made by Grafana to the plugin as part of a
QueryDataRequest
. - The results from a
DataQuery
. - Settings for a datasource instance.
- Data returned from an initial request to subscribe to a stream.
- Metrics collected from a plugin as part of a collect metrics.
- Main entrypoint into the Grafana plugin SDK.
- Holds contextual information about a plugin request: Grafana org, user, and plugin instance settings.
- A request to publish data to a stream.
- The response to a stream publish request.
- A request for data made by Grafana.
- A request to ‘run’ a stream, i.e. begin streaming data.
- A packet of data to be streamed back to the subscribed client.
- A request to subscribe to a stream.
- The response to a stream subscription request.
- The time range for a query.
- A Grafana user.
Enums
- Errors occurring when trying to interpret data passed from Grafana to this SDK.
- Errors occurring when trying to convert data into a format understood by Grafana.
- Status codes for
DataQueryError
. - Errors returned by plugin backends.
- The health status of a plugin.
- The status of a publish stream response.
- A role within Grafana.
- The status of a subscribe stream response.
Traits
- Error supertrait used in
DataService::query_data
. - Used to respond for requests for data from datasources and app plugins.
- Trait for services that provide a health check and/or metric collection endpoint.
- Trait describing how an error should be converted into a
http::Response<Bytes>
. - Trait indicating that a type can be fallibly converted into a
http::Response<Bytes>
. - Trait for plugins that can handle arbitrary resource requests.
- Trait for plugins that wish to provide uni- or bi-directional streaming.
Functions
- Initialize the plugin, returning the
TcpListener
that the gRPC service should serve on. - Create a
tracing
Layer
configured to log events in a format understood by Grafana.
Type Aliases
- Type alias for a boxed iterator of query responses, useful for returning from
DataService::query_data
. - Type alias for a pinned, boxed future with a fallible HTTP response as output, with a custom error type.
- Type alias for a pinned, boxed stream of HTTP responses with a custom error type.
- Type alias for a pinned, boxed stream of stream packets with a custom error type.
Attribute Macros
- Re-export of
async_trait
proc macro, so plugin implementations don’t have to import tonic manually.