use crate::api::logs::LogsState;
use crate::storage::LogStorage;
use crate::subscriber::LogCaptureLayer;
use axum::routing::get;
use axum::Router;
use std::sync::Arc;
use tower_http::cors::{Any, CorsLayer};
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::EnvFilter;
#[derive(Clone)]
pub struct TracingLayer {
router: Router,
}
impl TracingLayer {
pub fn new(base_path: &str) -> Self {
Self::with_capacity(base_path, 10_000)
}
pub fn with_capacity(base_path: &str, capacity: usize) -> Self {
let storage = LogStorage::with_capacity(capacity);
let env_filter = EnvFilter::try_from_default_env()
.unwrap_or_else(|_| EnvFilter::new("trace,tracing_web_console=off,log=off"));
let log_capture_layer = LogCaptureLayer::new(storage.clone());
tracing_subscriber::registry()
.with(env_filter)
.with(log_capture_layer)
.try_init()
.ok();
let logs_state = Arc::new(LogsState::new(storage.clone()));
let frontend_state = crate::frontend::FrontendState {
base_path: Arc::new(base_path.to_string()),
};
let frontend_router = Router::new()
.route("/", get(crate::frontend::serve_index))
.route("/assets/{*path}", get(crate::frontend::serve_static))
.with_state(frontend_state);
let api_router = crate::api::create_api_router(logs_state);
let inner_router = frontend_router.merge(api_router);
let cors = CorsLayer::new()
.allow_origin(Any)
.allow_methods(Any)
.allow_headers(Any);
let router = Router::new().nest(base_path, inner_router).layer(cors);
Self { router }
}
pub fn into_router(self) -> Router {
self.router
}
}
#[allow(dead_code)]
pub struct TracingLayerBuilder {
base_path: String,
capacity: usize,
initial_filter: String,
}
impl TracingLayerBuilder {
#[allow(dead_code)]
pub fn new(base_path: &str) -> Self {
Self {
base_path: base_path.to_string(),
capacity: 10_000,
initial_filter: "trace".to_string(),
}
}
#[allow(dead_code)]
pub fn with_capacity(mut self, capacity: usize) -> Self {
self.capacity = capacity;
self
}
#[allow(dead_code)]
pub fn with_filter(mut self, filter: &str) -> Self {
self.initial_filter = filter.to_string();
self
}
#[allow(dead_code)]
pub fn build(self) -> TracingLayer {
TracingLayer::with_capacity(&self.base_path, self.capacity)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tracing_layer_creation() {
let _layer = TracingLayer::new("/tracing");
}
#[test]
fn test_builder_pattern() {
let builder = TracingLayerBuilder::new("/tracing")
.with_capacity(5000)
.with_filter("debug");
assert_eq!(builder.base_path, "/tracing");
assert_eq!(builder.capacity, 5000);
assert_eq!(builder.initial_filter, "debug");
}
#[test]
fn test_builder_defaults_to_trace() {
let builder = TracingLayerBuilder::new("/tracing");
assert_eq!(builder.initial_filter, "trace");
}
}