mirror of
https://gitlab.computer.surgery/matrix/grapevine.git
synced 2025-12-16 15:21:24 +01:00
Add admin commands to get and reset tracing filters
This commit is contained in:
parent
5eab758bd2
commit
99924e5779
4 changed files with 121 additions and 19 deletions
|
|
@ -261,9 +261,10 @@ This will be the first release of Grapevine since it was forked from Conduit
|
|||
([!46](https://gitlab.computer.surgery/matrix/grapevine/-/merge_requests/46))
|
||||
10. Recognize the `!admin` prefix to invoke admin commands.
|
||||
([!45](https://gitlab.computer.surgery/matrix/grapevine/-/merge_requests/45))
|
||||
11. Add the `set-tracing-filter` admin command to change log/metrics/flame
|
||||
11. Add the `tracing-filter` admin command to view and change log/metrics/flame
|
||||
filters dynamically at runtime.
|
||||
([!49](https://gitlab.computer.surgery/matrix/grapevine/-/merge_requests/49))
|
||||
([!49](https://gitlab.computer.surgery/matrix/grapevine/-/merge_requests/49),
|
||||
[!164](https://gitlab.computer.surgery/matrix/grapevine/-/merge_requests/164))
|
||||
12. Add more configuration options.
|
||||
([!49](https://gitlab.computer.surgery/matrix/grapevine/-/merge_requests/49))
|
||||
* `observability.traces.filter`: The `tracing` filter to use for
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use tracing_subscriber::EnvFilter;
|
|||
/// Use [`FromStr`] or [`Deserialize`] to construct this type, then [`From`] or
|
||||
/// [`Into`] to convert it into an [`EnvFilter`] when needed.
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct EnvFilterClone(String);
|
||||
pub(crate) struct EnvFilterClone(pub(crate) String);
|
||||
|
||||
impl FromStr for EnvFilterClone {
|
||||
type Err = <EnvFilter as FromStr>::Err;
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ use opentelemetry_sdk::{
|
|||
Resource,
|
||||
};
|
||||
use strum::{AsRefStr, IntoStaticStr};
|
||||
use thiserror::Error;
|
||||
use tokio::time::Instant;
|
||||
use tracing::{subscriber::SetGlobalDefaultError, Span};
|
||||
use tracing_flame::{FlameLayer, FlushGuard};
|
||||
|
|
@ -78,9 +79,67 @@ impl<L, S> ReloadHandle<L> for reload::Handle<L, S> {
|
|||
}
|
||||
}
|
||||
|
||||
/// A type-erased [reload handle][reload::Handle] for an [`EnvFilter`].
|
||||
pub(crate) type FilterReloadHandle =
|
||||
Box<dyn ReloadHandle<EnvFilter> + Send + Sync>;
|
||||
/// Error returned from [`FilterReloadHandle::set_filter()`]
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
#[derive(Debug, Error)]
|
||||
pub(crate) enum SetFilterError {
|
||||
#[error("invalid filter string")]
|
||||
InvalidFilter(#[from] tracing_subscriber::filter::ParseError),
|
||||
#[error("failed to reload filter layer")]
|
||||
Reload(#[from] reload::Error),
|
||||
}
|
||||
|
||||
/// A wrapper around a tracing filter [reload handle][reload::Handle] that
|
||||
/// remembers the filter string that was last set.
|
||||
pub(crate) struct FilterReloadHandle {
|
||||
/// The actual [`reload::Handle`] that can be used to modify the filter
|
||||
/// [`Layer`]
|
||||
inner: Box<dyn ReloadHandle<EnvFilter> + Send + Sync>,
|
||||
/// Filter string that was last applied to `inner`
|
||||
current_filter: String,
|
||||
/// Filter string that was initially loaded from the configuration
|
||||
initial_filter: String,
|
||||
}
|
||||
|
||||
impl FilterReloadHandle {
|
||||
/// Creates a new [`FilterReloadHandle`] from a filter string, returning the
|
||||
/// filter layer itself and the handle that can be used to modify it.
|
||||
pub(crate) fn new<S: tracing::Subscriber>(
|
||||
filter: EnvFilterClone,
|
||||
) -> (impl tracing_subscriber::layer::Filter<S>, Self) {
|
||||
let (layer, handle) = reload::Layer::new(EnvFilter::from(&filter));
|
||||
let handle = Self {
|
||||
inner: Box::new(handle),
|
||||
current_filter: filter.0.clone(),
|
||||
initial_filter: filter.0,
|
||||
};
|
||||
(layer, handle)
|
||||
}
|
||||
|
||||
/// Sets the filter string for the linked filter layer. Can fail if the
|
||||
/// filter string is invalid or when the link to the layer has been
|
||||
/// broken.
|
||||
pub(crate) fn set_filter(
|
||||
&mut self,
|
||||
filter: String,
|
||||
) -> Result<(), SetFilterError> {
|
||||
self.inner.reload(filter.parse()?)?;
|
||||
self.current_filter = filter;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the filter string that the underlying filter layer is currently
|
||||
/// configured for.
|
||||
pub(crate) fn get_filter(&self) -> &str {
|
||||
&self.current_filter
|
||||
}
|
||||
|
||||
/// Returns the filter string that the underlying filter layer was
|
||||
/// initialized with.
|
||||
pub(crate) fn get_initial_filter(&self) -> &str {
|
||||
&self.initial_filter
|
||||
}
|
||||
}
|
||||
|
||||
/// Collection of [`FilterReloadHandle`]s, allowing the filters for tracing
|
||||
/// backends to be changed dynamically. Handles may be [`None`] if the backend
|
||||
|
|
@ -153,9 +212,9 @@ where
|
|||
return Ok((None, None, None));
|
||||
}
|
||||
|
||||
let (filter, handle) = reload::Layer::new(EnvFilter::from(filter));
|
||||
let (filter, handle) = FilterReloadHandle::new(filter.clone());
|
||||
let (layer, data) = init()?;
|
||||
Ok((Some(layer.with_filter(filter)), Some(Box::new(handle)), Some(data)))
|
||||
Ok((Some(layer.with_filter(filter)), Some(handle), Some(data)))
|
||||
}
|
||||
|
||||
/// Initialize observability
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::{collections::BTreeMap, fmt::Write, sync::Arc, time::Instant};
|
||||
|
||||
use clap::{Parser, ValueEnum};
|
||||
use clap::{Parser, Subcommand, ValueEnum};
|
||||
use regex::Regex;
|
||||
use ruma::{
|
||||
api::appservice::Registration,
|
||||
|
|
@ -205,10 +205,41 @@ enum AdminCommand {
|
|||
VerifyJson,
|
||||
|
||||
/// Dynamically change a tracing backend's filter string
|
||||
SetTracingFilter {
|
||||
TracingFilter {
|
||||
#[command(subcommand)]
|
||||
cmd: TracingFilterCommand,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Subcommand)]
|
||||
enum TracingFilterCommand {
|
||||
Get {
|
||||
backend: TracingBackend,
|
||||
},
|
||||
Set {
|
||||
backend: TracingBackend,
|
||||
filter: String,
|
||||
},
|
||||
Reset {
|
||||
backend: TracingBackend,
|
||||
},
|
||||
}
|
||||
|
||||
impl TracingFilterCommand {
|
||||
fn backend(&self) -> &TracingBackend {
|
||||
match self {
|
||||
TracingFilterCommand::Get {
|
||||
backend,
|
||||
}
|
||||
| TracingFilterCommand::Set {
|
||||
backend,
|
||||
..
|
||||
}
|
||||
| TracingFilterCommand::Reset {
|
||||
backend,
|
||||
} => backend,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -1167,9 +1198,8 @@ impl Service {
|
|||
)
|
||||
}
|
||||
}
|
||||
AdminCommand::SetTracingFilter {
|
||||
backend,
|
||||
filter,
|
||||
AdminCommand::TracingFilter {
|
||||
cmd,
|
||||
} => {
|
||||
let Some(handles) = &services().globals.reload_handles else {
|
||||
return Ok(RoomMessageEventContent::text_plain(
|
||||
|
|
@ -1177,7 +1207,7 @@ impl Service {
|
|||
));
|
||||
};
|
||||
let mut handles = handles.write().await;
|
||||
let handle = match backend {
|
||||
let handle = match cmd.backend() {
|
||||
TracingBackend::Log => &mut handles.log,
|
||||
TracingBackend::Flame => &mut handles.flame,
|
||||
TracingBackend::Traces => &mut handles.traces,
|
||||
|
|
@ -1187,15 +1217,27 @@ impl Service {
|
|||
"Backend is disabled",
|
||||
));
|
||||
};
|
||||
let filter = match filter.parse() {
|
||||
Ok(filter) => filter,
|
||||
Err(e) => {
|
||||
|
||||
let filter = match cmd {
|
||||
TracingFilterCommand::Set {
|
||||
filter,
|
||||
..
|
||||
} => filter,
|
||||
TracingFilterCommand::Reset {
|
||||
..
|
||||
} => handle.get_initial_filter().to_owned(),
|
||||
TracingFilterCommand::Get {
|
||||
..
|
||||
} => {
|
||||
return Ok(RoomMessageEventContent::text_plain(
|
||||
format!("Invalid filter string: {e}"),
|
||||
format!(
|
||||
"Current filter string: {}",
|
||||
handle.get_filter()
|
||||
),
|
||||
));
|
||||
}
|
||||
};
|
||||
if let Err(e) = handle.reload(filter) {
|
||||
if let Err(e) = handle.set_filter(filter) {
|
||||
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||
"Failed to reload filter: {e}"
|
||||
)));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue