use serde::{Deserialize, Serialize};
use std::io::IsTerminal;
#[cfg(feature = "basic_tracing")]
pub use tracing_subscriber;
#[derive(Debug, Default, Copy, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct LoggingSettings {
}
#[cfg(feature = "basic_tracing")]
pub fn build_tracing_logger() -> impl tracing_subscriber::layer::SubscriberExt {
use tracing_subscriber::prelude::*;
tracing_subscriber::registry()
.with(default_tracing_fmt_layer(std::io::stderr))
.with(default_tracing_env_filter())
}
#[cfg(feature = "basic_tracing")]
pub fn default_tracing_env_filter() -> tracing_subscriber::filter::EnvFilter {
if ::std::env::var("RUST_LOG").is_ok() {
tracing_subscriber::filter::EnvFilter::from_default_env()
} else {
tracing_subscriber::filter::EnvFilter::builder()
.with_default_directive(tracing_subscriber::filter::LevelFilter::INFO.into())
.parse_lossy("")
}
}
#[cfg(feature = "basic_tracing")]
pub fn default_tracing_fmt_layer<S, W>(
writer: W,
) -> impl tracing_subscriber::Layer<S> + Sync + Send + 'static
where
S: tracing::Subscriber + for<'a> tracing_subscriber::registry::LookupSpan<'a>,
W: for<'writer> tracing_subscriber::fmt::MakeWriter<'writer> + Sync + Send + 'static,
{
tracing_subscriber::fmt::layer()
.with_writer(writer)
.compact()
.with_file(true)
.with_line_number(true)
.with_target(false)
}
#[cfg(feature = "basic_tracing")]
pub fn setup_tracing_logger() {
use tracing_subscriber::util::SubscriberInitExt;
build_tracing_logger().init()
}
#[cfg(feature = "otel-otlp")]
pub fn init_otel_layer<S>(
service_name: &str,
endpoint: &str,
ingestion_key: Option<&str>,
environment: &str,
sample_ratio: f64,
export_timeout_secs: u64,
) -> Result<
(
tracing_opentelemetry::OpenTelemetryLayer<S, opentelemetry_sdk::trace::SdkTracer>,
opentelemetry_sdk::trace::SdkTracerProvider,
),
Box<dyn std::error::Error + Send + Sync>,
>
where
S: tracing::Subscriber + for<'a> tracing_subscriber::registry::LookupSpan<'a>,
{
use opentelemetry::trace::TracerProvider as _;
use opentelemetry_otlp::WithExportConfig;
use opentelemetry_otlp::WithTonicConfig;
use opentelemetry_sdk::trace::Sampler;
use std::time::Duration;
if !endpoint.starts_with("http://") && !endpoint.starts_with("https://") {
return Err(format!(
"invalid OTLP endpoint URI: {endpoint} (must start with http:// or https://)"
)
.into());
}
let sample_ratio_clamped = sample_ratio.clamp(0.0, 1.0);
let mut builder = opentelemetry_otlp::SpanExporter::builder()
.with_tonic()
.with_endpoint(endpoint)
.with_timeout(Duration::from_secs(export_timeout_secs));
if endpoint.starts_with("https://") {
builder =
builder.with_tls_config(tonic::transport::ClientTlsConfig::new().with_native_roots());
}
if let Some(key) = ingestion_key {
let mut metadata = tonic::metadata::MetadataMap::new();
metadata.insert(
"signoz-ingestion-key",
key.parse()
.map_err(|_| "invalid ingestion key format (value redacted)")?,
);
builder = builder.with_metadata(metadata);
}
let exporter = builder
.build()
.map_err(|e| format!("failed to build OTLP exporter for endpoint {endpoint}: {e}"))?;
let tracer_provider = opentelemetry_sdk::trace::SdkTracerProvider::builder()
.with_sampler(Sampler::TraceIdRatioBased(sample_ratio_clamped))
.with_batch_exporter(exporter)
.with_resource(
opentelemetry_sdk::Resource::builder()
.with_service_name(service_name.to_owned())
.with_attribute(opentelemetry::KeyValue::new(
"deployment.environment",
environment.to_owned(),
))
.build(),
)
.build();
opentelemetry::global::set_tracer_provider(tracer_provider.clone());
let tracer = tracer_provider.tracer(service_name.to_owned());
Ok((
tracing_opentelemetry::layer().with_tracer(tracer),
tracer_provider,
))
}
pub fn banner(crate_name: &str, crate_version: &str) -> String {
format!(
r#"
_ __ _ _ _ __ ___
| '_ \| | | | '_ \ _ \
| | | | |_| | | | | | |
|_| |_|\__, |_| |_| |_|
|___/
({crate_name} - version {crate_version})
"#
)
}
pub fn maybe_print_banner(crate_name: &str, crate_version: &str) {
if std::io::stdout().is_terminal() {
println!("{}", banner(crate_name, crate_version))
}
}