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 using Plugin::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 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::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.

A tracing event formatter which writes events in a format compatible with hclog.

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.

Errors returned by plugin backends.

The health status of a plugin.

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 Definitions

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.