pub trait Plugin: BasePluginExported + Sized {
type ConfigType: ConfigSchema;
const NAME: &'static CStr;
const PLUGIN_VERSION: &'static CStr;
const DESCRIPTION: &'static CStr;
const CONTACT: &'static CStr;
// Required method
fn new(
input: Option<&TablesInput<'_>>,
config: Self::ConfigType,
) -> Result<Self, Error>;
// Provided methods
fn set_config(&mut self, _config: Self::ConfigType) -> Result<(), Error> { ... }
fn get_metrics(&mut self) -> impl IntoIterator<Item = Metric> { ... }
}
Expand description
§A base trait for implementing Falco plugins
There are several constants you need to set to describe the metadata for your plugin, described
below. All the constants are C-style strings: you can initialize the fields with c"foo"
.
For example, a plugin that doesn’t support any capabilities (which is useless and would fail to load, but is a necessary step to building an actually useful plugin) might look like:
use std::ffi::CStr;
use falco_plugin::base::{Metric, Plugin};
use falco_plugin::plugin;
use falco_plugin::FailureReason;
use falco_plugin::tables::TablesInput;
// define the type holding the plugin state
struct NoOpPlugin;
// implement the base::Plugin trait
impl Plugin for NoOpPlugin {
const NAME: &'static CStr = c"sample-plugin-rs";
const PLUGIN_VERSION: &'static CStr = c"0.0.1";
const DESCRIPTION: &'static CStr = c"A sample Falco plugin that does nothing";
const CONTACT: &'static CStr = c"you@example.com";
type ConfigType = ();
fn new(input: Option<&TablesInput>, config: Self::ConfigType)
-> Result<Self, anyhow::Error> {
Ok(NoOpPlugin)
}
}
// generate the actual plugin wrapper code
// note we need to decorate the type name with `#[no_capabilities]` to bypass
// the safeguard against building an invalid plugin
plugin!(#[no_capabilities] NoOpPlugin);
Required Associated Constants§
Sourceconst NAME: &'static CStr
const NAME: &'static CStr
the name of your plugin, must match the plugin name in the Falco config file
Sourceconst PLUGIN_VERSION: &'static CStr
const PLUGIN_VERSION: &'static CStr
the version of your plugin
Sourceconst DESCRIPTION: &'static CStr
const DESCRIPTION: &'static CStr
a free-form description of what your plugin does
Required Associated Types§
Sourcetype ConfigType: ConfigSchema
type ConfigType: ConfigSchema
The plugin can be configured in three different ways. In all cases, an instance of the type
you specify will be passed to the Plugin::new
method.
See https://falco.org/docs/plugins/usage/ for more information about plugin configuration in Falco.
§No configuration
If your plugin does not need any configuration, set the ConfigType
to an empty tuple.
§Configuration as a string
If you set the ConfigType
to String
, your plugin will receive the configuration
as a string, read directly from the Falco config file.
§Configuration as JSON
Plugins can also be configured using a JSON object. This will be parsed by the SDK and your
plugin will receive a data structure containing all the parsed fields. In order to use JSON
configuration, set the ConfigType
to Json<T>
, where the Json
type is provided by this crate and the type T
must implement serde::de::DeserializeOwned
and [schemars::JsonSchema
].
You will also need to provide a JSON schema for the plugin API to validate the configuration.
Please note that you can use the reexports (falco_plugin::serde
and falco_plugin::schemars
)
to ensure you’re using the same version of serde and schemars as the SDK.
Your config struct might look like:
use falco_plugin::schemars::JsonSchema;
use falco_plugin::serde::Deserialize;
#[derive(JsonSchema, Deserialize)]
#[schemars(crate = "falco_plugin::schemars")]
#[serde(crate = "falco_plugin::serde")]
struct MyConfig {
/* ... */
}
You can use irrefutable patterns in your new
and set_config
methods to make JSON configs
a little more ergonomic:
use std::ffi::CStr;
use anyhow::Error;
use falco_plugin::base::{Json, Metric, Plugin};
use falco_plugin::schemars::JsonSchema;
use falco_plugin::serde::Deserialize;
use falco_plugin::tables::TablesInput;
#[derive(JsonSchema, Deserialize)]
#[schemars(crate = "falco_plugin::schemars")]
#[serde(crate = "falco_plugin::serde")]
struct MyConfig {
debug: bool,
}
struct MyPlugin;
impl Plugin for MyPlugin {
// ...
type ConfigType = Json<MyConfig>;
fn new(input: Option<&TablesInput>, Json(config): Json<MyConfig>) -> Result<Self, Error> {
// ^^^^^^^^^^^^
if config.debug { /* ... */ }
// ...
}
fn set_config(&mut self, Json(config): Json<MyConfig>) -> Result<(), Error> {
// ^^^^^^^^^^^^
if config.debug { /* ... */ }
// ...
}
// ...
}
Required Methods§
Sourcefn new(
input: Option<&TablesInput<'_>>,
config: Self::ConfigType,
) -> Result<Self, Error>
fn new( input: Option<&TablesInput<'_>>, config: Self::ConfigType, ) -> Result<Self, Error>
This method takes a TablesInput
instance, which lets you
access tables exposed by other plugins (and Falco core).
It should return a new instance of Self
Provided Methods§
Sourcefn set_config(&mut self, _config: Self::ConfigType) -> Result<(), Error>
fn set_config(&mut self, _config: Self::ConfigType) -> Result<(), Error>
Update the configuration of a running plugin
The default implementation does nothing
Sourcefn get_metrics(&mut self) -> impl IntoIterator<Item = Metric>
fn get_metrics(&mut self) -> impl IntoIterator<Item = Metric>
Return the plugin metrics
Metrics are described by:
- a name (just a string)
- a type (monotonic vs non-monotonic:
crate::base::MetricType
) - a value of one of the supported types (
crate::base::MetricValue
)
Note: The plugin name is prepended to the metric name, so a metric called foo
in a plugin called bar
will be emitted by the plugin framework as bar.foo
.
Note: Metrics aren’t registered in the framework in any way and there is no
requirement to report the same metrics on each call to get_metrics
. However, it’s
probably a good idea to do so, or at least not to change the type of metric or the type
of its value from call to call.
There are two general patterns to use when emitting metrics from a plugin:
- Predefined metrics
struct MyPlugin {
// ...
my_metric: MetricLabel,
}
fn new(input: Option<&TablesInput>, config: Self::ConfigType)
-> Result<Self, anyhow::Error> {
Ok(MyPlugin {
// ...
my_metric: MetricLabel::new(c"my_metric", MetricType::Monotonic),
})
}
fn get_metrics(&mut self) -> impl IntoIterator<Item=Metric> {
[self.my_metric.with_value(MetricValue::U64(10u64))]
}
- Inline metrics
fn get_metrics(&mut self) -> impl IntoIterator<Item=Metric> {
[Metric::new(
MetricLabel::new(c"my_metric", MetricType::Monotonic),
MetricValue::U64(10u64),
)]
}
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.