mirror of
https://gitlab.computer.surgery/matrix/grapevine.git
synced 2025-12-16 15:21:24 +01:00
add observability infrastructure for cli subcmds
This commit is contained in:
parent
b93c39ee93
commit
b03c2a15b3
5 changed files with 96 additions and 10 deletions
34
src/cli.rs
34
src/cli.rs
|
|
@ -7,7 +7,10 @@ use std::path::PathBuf;
|
|||
|
||||
use clap::{Parser, Subcommand};
|
||||
|
||||
use crate::error;
|
||||
use crate::{
|
||||
config::{default_tracing_filter, EnvFilterClone, LogFormat},
|
||||
error, observability,
|
||||
};
|
||||
|
||||
mod serve;
|
||||
|
||||
|
|
@ -51,6 +54,21 @@ pub(crate) struct ConfigArg {
|
|||
pub(crate) config: Option<PathBuf>,
|
||||
}
|
||||
|
||||
/// Observability arguments for CLI subcommands
|
||||
#[derive(clap::Args)]
|
||||
struct ObservabilityArgs {
|
||||
/// Log format
|
||||
#[clap(long, default_value_t = LogFormat::Full)]
|
||||
log_format: LogFormat,
|
||||
|
||||
/// Log filter
|
||||
///
|
||||
/// For information about the syntax, see here:
|
||||
/// <https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives>
|
||||
#[clap(long, default_value_t = default_tracing_filter())]
|
||||
log_filter: EnvFilterClone,
|
||||
}
|
||||
|
||||
#[derive(clap::Args)]
|
||||
pub(crate) struct ServeArgs {
|
||||
#[clap(flatten)]
|
||||
|
|
@ -59,9 +77,23 @@ pub(crate) struct ServeArgs {
|
|||
|
||||
impl Args {
|
||||
pub(crate) async fn run(self) -> Result<(), error::Main> {
|
||||
if let Some((format, filter)) = self.command.cli_observability_args() {
|
||||
observability::init_for_cli(format, filter.into())?;
|
||||
}
|
||||
|
||||
match self.command {
|
||||
Command::Serve(args) => serve::run(args).await?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Command {
|
||||
fn cli_observability_args(&self) -> Option<(LogFormat, EnvFilterClone)> {
|
||||
// All subcommands other than `serve` should return `Some`. Keep these
|
||||
// match arms sorted by the enum variant name.
|
||||
match self {
|
||||
Command::Serve(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,20 +180,34 @@ impl Display for ListenConfig {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default, Debug, Deserialize)]
|
||||
#[derive(Copy, Clone, Default, Debug, Deserialize, clap::ValueEnum)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub(crate) enum LogFormat {
|
||||
/// Use the [`tracing_subscriber::fmt::format::Pretty`] formatter
|
||||
/// Multiple lines per event, includes all information
|
||||
Pretty,
|
||||
/// Use the [`tracing_subscriber::fmt::format::Full`] formatter
|
||||
|
||||
/// One line per event, includes most information
|
||||
#[default]
|
||||
Full,
|
||||
/// Use the [`tracing_subscriber::fmt::format::Compact`] formatter
|
||||
|
||||
/// One line per event, includes less information
|
||||
Compact,
|
||||
/// Use the [`tracing_subscriber::fmt::format::Json`] formatter
|
||||
|
||||
/// One JSON object per line per event, includes most information
|
||||
Json,
|
||||
}
|
||||
|
||||
impl Display for LogFormat {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
LogFormat::Pretty => write!(f, "pretty"),
|
||||
LogFormat::Full => write!(f, "full"),
|
||||
LogFormat::Compact => write!(f, "compact"),
|
||||
LogFormat::Json => write!(f, "json"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub(crate) struct TurnConfig {
|
||||
|
|
@ -404,7 +418,7 @@ fn default_max_request_size() -> u32 {
|
|||
20 * 1024 * 1024
|
||||
}
|
||||
|
||||
fn default_tracing_filter() -> EnvFilterClone {
|
||||
pub(crate) fn default_tracing_filter() -> EnvFilterClone {
|
||||
"info,ruma_state_res=warn"
|
||||
.parse()
|
||||
.expect("hardcoded env filter should be valid")
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
//! [0]: https://github.com/tokio-rs/tracing/pull/2956
|
||||
#![warn(missing_docs, clippy::missing_docs_in_private_items)]
|
||||
|
||||
use std::str::FromStr;
|
||||
use std::{fmt, str::FromStr};
|
||||
|
||||
use serde::{de, Deserialize, Deserializer};
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
|
@ -14,7 +14,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)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct EnvFilterClone(String);
|
||||
|
||||
impl FromStr for EnvFilterClone {
|
||||
|
|
@ -26,6 +26,12 @@ impl FromStr for EnvFilterClone {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for EnvFilterClone {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&EnvFilterClone> for EnvFilter {
|
||||
fn from(other: &EnvFilterClone) -> Self {
|
||||
EnvFilter::from_str(&other.0)
|
||||
|
|
@ -33,6 +39,13 @@ impl From<&EnvFilterClone> for EnvFilter {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<EnvFilterClone> for EnvFilter {
|
||||
fn from(other: EnvFilterClone) -> Self {
|
||||
EnvFilter::from_str(&other.0)
|
||||
.expect("env filter syntax should have been validated already")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for EnvFilterClone {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
|
|
|
|||
|
|
@ -42,6 +42,9 @@ impl fmt::Display for DisplayWithSources<'_> {
|
|||
pub(crate) enum Main {
|
||||
#[error(transparent)]
|
||||
ServeCommand(#[from] ServeCommand),
|
||||
|
||||
#[error("failed to install global default tracing subscriber")]
|
||||
SetSubscriber(#[from] tracing::subscriber::SetGlobalDefaultError),
|
||||
}
|
||||
|
||||
/// Errors returned from the `serve` CLI subcommand.
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use opentelemetry_sdk::{
|
|||
};
|
||||
use strum::{AsRefStr, IntoStaticStr};
|
||||
use tokio::time::Instant;
|
||||
use tracing::Span;
|
||||
use tracing::{subscriber::SetGlobalDefaultError, Span};
|
||||
use tracing_flame::{FlameLayer, FlushGuard};
|
||||
use tracing_opentelemetry::OtelData;
|
||||
use tracing_subscriber::{
|
||||
|
|
@ -469,3 +469,27 @@ pub(crate) async fn traceresponse_layer(req: Request, next: Next) -> Response {
|
|||
|
||||
resp
|
||||
}
|
||||
|
||||
/// Set up observability for CLI-oriented subcommands.
|
||||
///
|
||||
/// Tracing spans and events will be sent to `stderr`.
|
||||
pub(crate) fn init_for_cli(
|
||||
log_format: LogFormat,
|
||||
env_filter: EnvFilter,
|
||||
) -> Result<(), SetGlobalDefaultError> {
|
||||
let log_layer =
|
||||
tracing_subscriber::fmt::Layer::new().with_writer(std::io::stderr);
|
||||
|
||||
let log_layer = match log_format {
|
||||
LogFormat::Pretty => log_layer.pretty().boxed(),
|
||||
LogFormat::Full => log_layer.boxed(),
|
||||
LogFormat::Compact => log_layer.compact().boxed(),
|
||||
LogFormat::Json => log_layer.json().boxed(),
|
||||
};
|
||||
|
||||
let log_layer = log_layer.with_filter(env_filter);
|
||||
|
||||
let subscriber = Registry::default().with(log_layer);
|
||||
|
||||
tracing::subscriber::set_global_default(subscriber).map_err(Into::into)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue