use crate::config::{LogConfig, LogDestination};
use std::io;
use tracing_subscriber::{EnvFilter, Registry, fmt, layer::SubscriberExt, util::SubscriberInitExt};
pub fn init_logging() {
let filter = EnvFilter::try_from_default_env()
.unwrap_or_else(|_| EnvFilter::new("jacs=info"))
.add_directive("hyper=warn".parse().expect("valid directive"))
.add_directive("tonic=warn".parse().expect("valid directive"))
.add_directive("h2=warn".parse().expect("valid directive"))
.add_directive("reqwest=warn".parse().expect("valid directive"));
let _ = Registry::default()
.with(filter)
.with(fmt::layer().with_writer(io::stderr))
.try_init();
}
#[cfg(not(target_arch = "wasm32"))]
use tracing_appender::non_blocking::WorkerGuard;
#[cfg(not(target_arch = "wasm32"))]
use tracing_appender::rolling::{RollingFileAppender, Rotation};
#[cfg(all(not(target_arch = "wasm32"), feature = "otlp-logs"))]
use opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge;
#[cfg(all(not(target_arch = "wasm32"), feature = "otlp-logs"))]
use opentelemetry_otlp::{LogExporter, Protocol, WithExportConfig, WithHttpConfig};
#[cfg(all(not(target_arch = "wasm32"), feature = "otlp-logs"))]
use opentelemetry_sdk::{Resource, logs::SdkLoggerProvider};
#[cfg(not(target_arch = "wasm32"))]
pub fn init_logs(config: &LogConfig) -> Result<Option<WorkerGuard>, Box<dyn std::error::Error>> {
if !config.enabled {
return Ok(None);
}
let filter = EnvFilter::new(&config.level)
.add_directive("hyper=warn".parse()?)
.add_directive("tonic=warn".parse()?)
.add_directive("h2=warn".parse()?)
.add_directive("reqwest=warn".parse()?);
match &config.destination {
LogDestination::File { path } => {
let file_appender = RollingFileAppender::new(Rotation::DAILY, path, "app.log");
let (non_blocking, guard) = tracing_appender::non_blocking(file_appender);
Registry::default()
.with(filter)
.with(fmt::layer().with_writer(non_blocking).with_ansi(false))
.try_init()?;
Ok(Some(guard))
}
LogDestination::Stderr => {
let _ = Registry::default()
.with(filter)
.with(fmt::layer().with_writer(io::stderr))
.try_init();
Ok(None)
}
LogDestination::Otlp {
endpoint: _,
headers: _,
} => {
#[cfg(all(not(target_arch = "wasm32"), feature = "otlp-logs"))]
{
let exporter = LogExporter::builder()
.with_http()
.with_protocol(Protocol::HttpBinary)
.with_endpoint(endpoint)
.build()?;
let logger_provider = SdkLoggerProvider::builder()
.with_batch_exporter(exporter)
.with_resource(Resource::builder().with_service_name("jacs-demo").build())
.build();
let otel_layer = OpenTelemetryTracingBridge::new(&logger_provider);
Registry::default()
.with(filter)
.with(fmt::layer().with_writer(io::stderr)) .with(otel_layer)
.try_init()?;
return Ok(None);
}
#[cfg(any(target_arch = "wasm32", not(feature = "otlp-logs")))]
{
Err("OTLP logs feature not enabled: rebuild with --features otlp-logs".into())
}
}
LogDestination::Null => Ok(None),
}
}
#[cfg(target_arch = "wasm32")]
pub fn init_logs(config: &LogConfig) -> Result<Option<()>, Box<dyn std::error::Error>> {
if !config.enabled {
return Ok(None);
}
let filter = EnvFilter::new(&config.level)
.add_directive("hyper=off".parse()?)
.add_directive("tonic=off".parse()?)
.add_directive("h2=off".parse()?)
.add_directive("reqwest=off".parse()?);
if tracing::subscriber::try_with_default(|_| {}).is_err() {
Registry::default()
.with(filter)
.with(fmt::layer())
.try_init()?;
} else {
warn!("Subscriber already initialized, skipping logs initialization");
}
match &config.destination {
LogDestination::Console => {
Registry::default()
.with(filter)
.with(fmt::layer())
.try_init()?;
}
LogDestination::Http { endpoint } => {
warn!(
"Warning: HTTP logging for WASM configured for {} but using Console fallback.",
endpoint
);
Registry::default()
.with(filter)
.with(fmt::layer())
.try_init()?;
}
LogDestination::Null => {
}
}
Ok(None)
}