343 lines
8.3 KiB
Rust
343 lines
8.3 KiB
Rust
//! Logging utilities for Veza Rust services
|
|
//!
|
|
//! This module provides centralized logging configuration and utilities.
|
|
|
|
use tracing::{Level, Subscriber};
|
|
use tracing_subscriber::{
|
|
fmt::{self, format::FmtSpan},
|
|
layer::SubscriberExt,
|
|
util::SubscriberInitExt,
|
|
EnvFilter, Registry,
|
|
};
|
|
|
|
use crate::{VezaError, VezaResult};
|
|
|
|
/// Initialize logging for Veza services
|
|
pub fn init() -> VezaResult<()> {
|
|
// Set default log level if not specified
|
|
if std::env::var("RUST_LOG").is_err() {
|
|
std::env::set_var("RUST_LOG", "info");
|
|
}
|
|
|
|
// Create environment filter
|
|
let env_filter = EnvFilter::try_from_default_env()
|
|
.unwrap_or_else(|_| EnvFilter::new("info"));
|
|
|
|
// Create formatting layer
|
|
let fmt_layer = fmt::layer()
|
|
.with_target(true)
|
|
.with_thread_ids(true)
|
|
.with_thread_names(true)
|
|
.with_span_events(FmtSpan::CLOSE)
|
|
.with_file(true)
|
|
.with_line_number(true)
|
|
.with_ansi(true);
|
|
|
|
// Initialize the subscriber
|
|
Registry::default()
|
|
.with(env_filter)
|
|
.with(fmt_layer)
|
|
.init();
|
|
|
|
tracing::info!("Logging initialized");
|
|
Ok(())
|
|
}
|
|
|
|
/// Initialize logging with custom configuration
|
|
pub fn init_with_config(config: LoggingConfig) -> VezaResult<()> {
|
|
// Set log level
|
|
std::env::set_var("RUST_LOG", &config.level);
|
|
|
|
// Create environment filter
|
|
let env_filter = EnvFilter::try_from_default_env()
|
|
.unwrap_or_else(|_| EnvFilter::new(&config.level));
|
|
|
|
// Create formatting layer based on format
|
|
let fmt_layer = match config.format.as_str() {
|
|
"json" => fmt::layer()
|
|
.json()
|
|
.with_target(true)
|
|
.with_thread_ids(true)
|
|
.with_thread_names(true)
|
|
.with_span_events(FmtSpan::CLOSE)
|
|
.with_file(true)
|
|
.with_line_number(true)
|
|
.boxed(),
|
|
"text" => fmt::layer()
|
|
.with_target(true)
|
|
.with_thread_ids(true)
|
|
.with_thread_names(true)
|
|
.with_span_events(FmtSpan::CLOSE)
|
|
.with_file(true)
|
|
.with_line_number(true)
|
|
.with_ansi(true)
|
|
.boxed(),
|
|
_ => return Err(VezaError::Config(format!("Invalid log format: {}", config.format))),
|
|
};
|
|
|
|
// Initialize the subscriber
|
|
Registry::default()
|
|
.with(env_filter)
|
|
.with(fmt_layer)
|
|
.init();
|
|
|
|
tracing::info!("Logging initialized with custom config");
|
|
Ok(())
|
|
}
|
|
|
|
/// Logging configuration
|
|
#[derive(Debug, Clone)]
|
|
pub struct LoggingConfig {
|
|
pub level: String,
|
|
pub format: String,
|
|
pub file: Option<String>,
|
|
pub max_size: u64,
|
|
pub max_files: u32,
|
|
pub compress: bool,
|
|
}
|
|
|
|
impl Default for LoggingConfig {
|
|
fn default() -> Self {
|
|
Self {
|
|
level: "info".to_string(),
|
|
format: "json".to_string(),
|
|
file: None,
|
|
max_size: 100 * 1024 * 1024, // 100MB
|
|
max_files: 5,
|
|
compress: true,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Structured logging macros
|
|
#[macro_export]
|
|
macro_rules! log_info {
|
|
($($arg:tt)*) => {
|
|
tracing::info!($($arg)*)
|
|
};
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! log_warn {
|
|
($($arg:tt)*) => {
|
|
tracing::warn!($($arg)*)
|
|
};
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! log_error {
|
|
($($arg:tt)*) => {
|
|
tracing::error!($($arg)*)
|
|
};
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! log_debug {
|
|
($($arg:tt)*) => {
|
|
tracing::debug!($($arg)*)
|
|
};
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! log_trace {
|
|
($($arg:tt)*) => {
|
|
tracing::trace!($($arg)*)
|
|
};
|
|
}
|
|
|
|
/// Log performance metrics
|
|
pub fn log_performance(operation: &str, duration: std::time::Duration, metadata: &[(&str, &dyn std::fmt::Display)]) {
|
|
tracing::info!(
|
|
operation = operation,
|
|
duration_ms = duration.as_millis(),
|
|
?metadata,
|
|
"Performance metric"
|
|
);
|
|
}
|
|
|
|
/// Log security events
|
|
pub fn log_security_event(event: &str, user_id: Option<uuid::Uuid>, ip_address: Option<&str>, metadata: &[(&str, &dyn std::fmt::Display)]) {
|
|
tracing::warn!(
|
|
event = event,
|
|
user_id = ?user_id,
|
|
ip_address = ip_address,
|
|
?metadata,
|
|
"Security event"
|
|
);
|
|
}
|
|
|
|
/// Log business events
|
|
pub fn log_business_event(event: &str, user_id: Option<uuid::Uuid>, resource_id: Option<uuid::Uuid>, metadata: &[(&str, &dyn std::fmt::Display)]) {
|
|
tracing::info!(
|
|
event = event,
|
|
user_id = ?user_id,
|
|
resource_id = ?resource_id,
|
|
?metadata,
|
|
"Business event"
|
|
);
|
|
}
|
|
|
|
/// Log system events
|
|
pub fn log_system_event(event: &str, component: &str, metadata: &[(&str, &dyn std::fmt::Display)]) {
|
|
tracing::info!(
|
|
event = event,
|
|
component = component,
|
|
?metadata,
|
|
"System event"
|
|
);
|
|
}
|
|
|
|
/// Log error with context
|
|
pub fn log_error_with_context(error: &VezaError, context: &[(&str, &dyn std::fmt::Display)]) {
|
|
if error.should_log() {
|
|
tracing::error!(
|
|
error = %error,
|
|
?context,
|
|
"Error occurred"
|
|
);
|
|
} else {
|
|
tracing::debug!(
|
|
error = %error,
|
|
?context,
|
|
"Error occurred"
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Log request/response
|
|
pub fn log_request_response(
|
|
method: &str,
|
|
path: &str,
|
|
status_code: u16,
|
|
duration: std::time::Duration,
|
|
user_id: Option<uuid::Uuid>,
|
|
request_id: Option<&str>,
|
|
) {
|
|
let level = if status_code >= 500 {
|
|
Level::ERROR
|
|
} else if status_code >= 400 {
|
|
Level::WARN
|
|
} else {
|
|
Level::INFO
|
|
};
|
|
|
|
tracing::event!(
|
|
level,
|
|
method = method,
|
|
path = path,
|
|
status_code = status_code,
|
|
duration_ms = duration.as_millis(),
|
|
user_id = ?user_id,
|
|
request_id = request_id,
|
|
"HTTP request"
|
|
);
|
|
}
|
|
|
|
/// Log database query
|
|
pub fn log_db_query(
|
|
query: &str,
|
|
duration: std::time::Duration,
|
|
rows_affected: Option<u64>,
|
|
error: Option<&str>,
|
|
) {
|
|
if let Some(error) = error {
|
|
tracing::error!(
|
|
query = query,
|
|
duration_ms = duration.as_millis(),
|
|
rows_affected = ?rows_affected,
|
|
error = error,
|
|
"Database query failed"
|
|
);
|
|
} else {
|
|
tracing::debug!(
|
|
query = query,
|
|
duration_ms = duration.as_millis(),
|
|
rows_affected = ?rows_affected,
|
|
"Database query"
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Log cache operations
|
|
pub fn log_cache_operation(
|
|
operation: &str,
|
|
key: &str,
|
|
hit: bool,
|
|
duration: std::time::Duration,
|
|
error: Option<&str>,
|
|
) {
|
|
if let Some(error) = error {
|
|
tracing::warn!(
|
|
operation = operation,
|
|
key = key,
|
|
hit = hit,
|
|
duration_ms = duration.as_millis(),
|
|
error = error,
|
|
"Cache operation failed"
|
|
);
|
|
} else {
|
|
tracing::debug!(
|
|
operation = operation,
|
|
key = key,
|
|
hit = hit,
|
|
duration_ms = duration.as_millis(),
|
|
"Cache operation"
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Log WebSocket events
|
|
pub fn log_websocket_event(
|
|
event: &str,
|
|
user_id: Option<uuid::Uuid>,
|
|
connection_id: Option<uuid::Uuid>,
|
|
metadata: &[(&str, &dyn std::fmt::Display)],
|
|
) {
|
|
tracing::info!(
|
|
event = event,
|
|
user_id = ?user_id,
|
|
connection_id = ?connection_id,
|
|
?metadata,
|
|
"WebSocket event"
|
|
);
|
|
}
|
|
|
|
/// Log streaming events
|
|
pub fn log_streaming_event(
|
|
event: &str,
|
|
track_id: Option<uuid::Uuid>,
|
|
user_id: Option<uuid::Uuid>,
|
|
metadata: &[(&str, &dyn std::fmt::Display)],
|
|
) {
|
|
tracing::info!(
|
|
event = event,
|
|
track_id = ?track_id,
|
|
user_id = ?user_id,
|
|
?metadata,
|
|
"Streaming event"
|
|
);
|
|
}
|
|
|
|
/// Create a span for tracing
|
|
pub fn create_span(name: &str, metadata: &[(&str, &dyn std::fmt::Display)]) -> tracing::Span {
|
|
tracing::info_span!(name, ?metadata)
|
|
}
|
|
|
|
/// Log startup information
|
|
pub fn log_startup(service_name: &str, version: &str, config: &[(&str, &dyn std::fmt::Display)]) {
|
|
tracing::info!(
|
|
service = service_name,
|
|
version = version,
|
|
?config,
|
|
"Service starting"
|
|
);
|
|
}
|
|
|
|
/// Log shutdown information
|
|
pub fn log_shutdown(service_name: &str, uptime: std::time::Duration) {
|
|
tracing::info!(
|
|
service = service_name,
|
|
uptime_seconds = uptime.as_secs(),
|
|
"Service shutting down"
|
|
);
|
|
}
|