Skip to content

Commit

Permalink
feat: improving tracing initialization (#1049)
Browse files Browse the repository at this point in the history
  • Loading branch information
dinhani-cw authored Jun 10, 2024
1 parent 525a76a commit 57a9ffd
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 73 deletions.
72 changes: 55 additions & 17 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,32 +82,37 @@ pub struct CommonConfig {
#[arg(long = "blocking-threads", env = "BLOCKING_THREADS", default_value = "10")]
pub num_blocking_threads: usize,

// Address where Prometheus metrics will be exposed.
#[arg(long = "metrics-exporter-address", env = "METRICS_EXPORTER_ADDRESS", default_value = "0.0.0.0:9000")]
pub metrics_exporter_address: SocketAddr,

/// Metrics histograms will be collected using summaries or histograms (buckets)?
#[arg(long = "metrics-histogram-kind", env = "METRICS_HISTOGRAM_KIND", default_value = "summary")]
pub metrics_histogram_kind: MetricsHistogramKind,

/// Prevents clap from breaking when passing `nocapture` options in tests.
#[arg(long = "nocapture")]
pub nocapture: bool,
// Address where Tokio Console GRPC server will be exposed.
#[arg(long = "tokio-console-address", env = "TRACING_TOKIO_CONSOLE_ADDRESS", default_value = "0.0.0.0:6669")]
pub tokio_console_address: SocketAddr,

/// Direct access to peers via IP address, why will be included on data propagation and leader election.
#[arg(long = "candidate-peers", env = "CANDIDATE_PEERS", value_delimiter = ',')]
pub candidate_peers: Vec<String>,
/// URL of the OpenTelemetry collector where tracing will be pushed.
#[arg(long = "tracing-collector-url", env = "TRACING_COLLECTOR_URL")]
pub opentelemetry_url: Option<String>,

/// How tracing events will be formatted.
#[arg(long = "log-format", env = "LOG_FORMAT", default_value = "normal")]
pub log_format: LogFormat,

/// Url to the sentry project
/// Sentry URL where error events will be pushed.
#[arg(long = "sentry-url", env = "SENTRY_URL")]
pub sentry_url: Option<String>,

/// Url to the tracing collector (Opentelemetry over gRPC)
#[arg(long = "tracing-collector-url", env = "TRACING_COLLECTOR_URL")]
pub tracing_url: Option<String>,

// Address for the Tokio Console
#[arg(long = "tokio-console-address", env = "TOKIO_CONSOLE_ADDRESS", default_value = "0.0.0.0:6669")]
pub tokio_console_address: SocketAddr,
/// Direct access to peers via IP address, why will be included on data propagation and leader election.
#[arg(long = "candidate-peers", env = "CANDIDATE_PEERS", value_delimiter = ',')]
pub candidate_peers: Vec<String>,

// Address for the Prometheus Metrics Exporter
#[arg(long = "metrics-exporter-address", env = "METRICS_EXPORTER_ADDRESS", default_value = "0.0.0.0:9000")]
pub metrics_exporter_address: SocketAddr,
/// Prevents clap from breaking when passing `nocapture` options in tests.
#[arg(long = "nocapture")]
pub nocapture: bool,
}

impl WithCommonConfig for CommonConfig {
Expand Down Expand Up @@ -880,6 +885,39 @@ impl FromStr for PermanentStorageKind {
}
}

// -----------------------------------------------------------------------------
// Enum: LogFormat
// -----------------------------------------------------------------------------

#[derive(DebugAsJson, strum::Display, Clone, Copy, Eq, PartialEq, serde::Serialize)]
pub enum LogFormat {
#[strum(to_string = "json")]
Json,

#[strum(to_string = "minimal")]
Minimal,

#[strum(to_string = "normal")]
Normal,

#[strum(to_string = "verbose")]
Verbose,
}

impl FromStr for LogFormat {
type Err = anyhow::Error;

fn from_str(s: &str) -> anyhow::Result<Self, Self::Err> {
match s.to_lowercase().trim() {
"json" => Ok(Self::Json),
"minimal" => Ok(Self::Minimal),
"normal" => Ok(Self::Normal),
"verbose" | "full" => Ok(Self::Verbose),
s => Err(anyhow!("unknown log format: {}", s)),
}
}
}

// -----------------------------------------------------------------------------
// Enum: MetricsHistogramKind
// -----------------------------------------------------------------------------
Expand Down
15 changes: 10 additions & 5 deletions src/globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,22 +40,27 @@ where
if env::var("PERM_STORAGE_CONNECTIONS").is_ok_and(|value| value == "1") {
println!("WARNING: env var PERM_STORAGE_CONNECTIONS is set to 1, if it cause connection problems, try increasing it");
}
let common = config.common();

// init tokio
let runtime = config.common().init_runtime().expect("failed to init tokio runtime");
let runtime = common.init_runtime().expect("failed to init tokio runtime");

// init tracing
runtime
.block_on(infra::init_tracing(config.common().tracing_url.as_ref(), config.common().tokio_console_address))
.block_on(infra::init_tracing(
common.log_format,
common.opentelemetry_url.as_deref(),
common.sentry_url.as_deref(),
common.tokio_console_address,
))
.expect("failed to init tracing");

// init metrics
#[cfg(feature = "metrics")]
infra::init_metrics(config.common().metrics_exporter_address, config.common().metrics_histogram_kind).expect("failed to init metrics");
infra::init_metrics(common.metrics_exporter_address, common.metrics_histogram_kind).expect("failed to init metrics");

// init sentry
let _sentry_guard = config
.common()
let _sentry_guard = common
.sentry_url
.as_ref()
.map(|sentry_url| infra::init_sentry(sentry_url).expect("failed to init sentry"));
Expand Down
101 changes: 50 additions & 51 deletions src/infra/tracing.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
//! Tracing services.
use std::env;
use std::env::VarError;
use std::io::stdout;
use std::io::IsTerminal;
use std::net::SocketAddr;
Expand All @@ -20,59 +18,51 @@ use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::EnvFilter;
use tracing_subscriber::Layer;

use crate::config::LogFormat;
use crate::ext::binary_name;
use crate::ext::named_spawn;

/// Init application global tracing.
pub async fn init_tracing(url: Option<&String>, console_address: SocketAddr) -> anyhow::Result<()> {
println!("creating global tracing registry");
/// Init application tracing.
pub async fn init_tracing(
log_format: LogFormat,
opentelemetry_url: Option<&str>,
sentry_url: Option<&str>,
tokio_console_address: SocketAddr,
) -> anyhow::Result<()> {
println!("creating tracing registry");

// configure stdout log layer
let log_format = env::var("LOG_FORMAT").map(|x| x.trim().to_lowercase());
let enable_ansi = stdout().is_terminal();

let stdout_layer = match log_format.as_deref() {
Ok("json") => {
println!("tracing registry: enabling json logs");
fmt::Layer::default()
.json()
.with_target(true)
.with_thread_ids(true)
.with_thread_names(true)
.with_filter(EnvFilter::from_default_env())
.boxed()
}
Ok("verbose") | Ok("full") => {
println!("tracing registry: enabling verbose text logs");
fmt::Layer::default()
.with_ansi(enable_ansi)
.with_target(true)
.with_thread_ids(true)
.with_thread_names(true)
.with_filter(EnvFilter::from_default_env())
.boxed()
}
Ok("minimal") => {
println!("tracing registry: enabling minimal text logs");
fmt::Layer::default()
.with_thread_ids(false)
.with_thread_names(false)
.with_target(false)
.with_ansi(enable_ansi)
.with_timer(MinimalTimer)
.with_filter(EnvFilter::from_default_env())
.boxed()
}
Ok("normal") | Err(VarError::NotPresent) => {
println!("tracing registry: enabling normal text logs");
fmt::Layer::default().with_ansi(enable_ansi).with_filter(EnvFilter::from_default_env()).boxed()
}
Ok(unexpected) => panic!("unexpected `LOG_FORMAT={unexpected}`"),
Err(e) => panic!("invalid utf-8 in `LOG_FORMAT`: {e}"),
println!("tracing registry: enabling console logs | format={} ansi={}", log_format, enable_ansi);
let stdout_layer = match log_format {
LogFormat::Json => fmt::Layer::default()
.json()
.with_target(true)
.with_thread_ids(true)
.with_thread_names(true)
.with_filter(EnvFilter::from_default_env())
.boxed(),
LogFormat::Minimal => fmt::Layer::default()
.with_thread_ids(false)
.with_thread_names(false)
.with_target(false)
.with_ansi(enable_ansi)
.with_timer(MinimalTimer)
.with_filter(EnvFilter::from_default_env())
.boxed(),
LogFormat::Normal => fmt::Layer::default().with_ansi(enable_ansi).with_filter(EnvFilter::from_default_env()).boxed(),
LogFormat::Verbose => fmt::Layer::default()
.with_ansi(enable_ansi)
.with_target(true)
.with_thread_ids(true)
.with_thread_names(true)
.with_filter(EnvFilter::from_default_env())
.boxed(),
};

// configure opentelemetry layer
let opentelemetry_layer = match url {
let opentelemetry_layer = match opentelemetry_url {
Some(url) => {
let service_name = format!("stratus-{}", binary_name());
println!("tracing registry: enabling opentelemetry exporter | url={} service={}", url, service_name);
Expand All @@ -99,15 +89,24 @@ pub async fn init_tracing(url: Option<&String>, console_address: SocketAddr) ->
};

// configure sentry layer
println!("tracing registry: enabling tracing layer");
let sentry_layer = sentry_tracing::layer().with_filter(EnvFilter::from_default_env());
let sentry_layer = match sentry_url {
Some(sentry_url) => {
println!("tracing registry: enabling sentry exporter | url={}", sentry_url);
let layer = sentry_tracing::layer().with_filter(EnvFilter::from_default_env());
Some(layer)
}
None => {
println!("tracing registry: skipping sentry exporter");
None
}
};

// configure tokio-console layer
println!("tracing registry: enabling tokio console | address={}", console_address);
let (console_layer, console_server) = ConsoleLayer::builder().with_default_env().server_addr(console_address).build();
println!("tracing registry: enabling tokio console exporter | address={}", tokio_console_address);
let (console_layer, console_server) = ConsoleLayer::builder().with_default_env().server_addr(tokio_console_address).build();
named_spawn("console::grpc-server", async move {
if let Err(e) = console_server.serve().await {
tracing::error!(reason = ?e, address = %console_address, "failed to create tokio-console server");
tracing::error!(reason = ?e, address = %tokio_console_address, "failed to create tokio-console server");
};
});

Expand All @@ -122,7 +121,7 @@ pub async fn init_tracing(url: Option<&String>, console_address: SocketAddr) ->
match result {
Ok(()) => Ok(()),
Err(e) => {
println!("failed to create global tracing registry | reason={:?}", e);
println!("failed to create tracing registry | reason={:?}", e);
Err(e.into())
}
}
Expand Down

0 comments on commit 57a9ffd

Please sign in to comment.