🚧 (config): Opciones enumeradas para el log
This commit is contained in:
parent
16d6afbd98
commit
b76c4a4d23
4 changed files with 126 additions and 31 deletions
|
|
@ -10,6 +10,12 @@ pub use lang_negotiation::LangNegotiation;
|
||||||
mod startup_banner;
|
mod startup_banner;
|
||||||
pub use startup_banner::StartupBanner;
|
pub use startup_banner::StartupBanner;
|
||||||
|
|
||||||
|
mod log_rolling;
|
||||||
|
pub use log_rolling::LogRolling;
|
||||||
|
|
||||||
|
mod log_format;
|
||||||
|
pub use log_format::LogFormat;
|
||||||
|
|
||||||
// **< SETTINGS >***********************************************************************************
|
// **< SETTINGS >***********************************************************************************
|
||||||
|
|
||||||
include_config!(SETTINGS: Settings => [
|
include_config!(SETTINGS: Settings => [
|
||||||
|
|
@ -114,13 +120,13 @@ pub struct Log {
|
||||||
pub tracing: String,
|
pub tracing: String,
|
||||||
/// Muestra los mensajes de traza en el terminal (*"Stdout"*) o los vuelca en archivos con
|
/// Muestra los mensajes de traza en el terminal (*"Stdout"*) o los vuelca en archivos con
|
||||||
/// rotación: *"Daily"*, *"Hourly"*, *"Minutely"* o *"Endless"*.
|
/// rotación: *"Daily"*, *"Hourly"*, *"Minutely"* o *"Endless"*.
|
||||||
pub rolling: String,
|
pub rolling: LogRolling,
|
||||||
/// Directorio para los archivos de traza (si [`rolling`](Self::rolling) ≠ *"Stdout"*).
|
/// Directorio para los archivos de traza (si [`rolling`](Self::rolling) ≠ *"Stdout"*).
|
||||||
pub path: String,
|
pub path: String,
|
||||||
/// Prefijo para los archivos de traza (si [`rolling`](Self::rolling) ≠ *"Stdout"*).
|
/// Prefijo para los archivos de traza (si [`rolling`](Self::rolling) ≠ *"Stdout"*).
|
||||||
pub prefix: String,
|
pub prefix: String,
|
||||||
/// Formato de salida de las trazas. Opciones: *"Full"*, *"Compact"*, *"Pretty"* o *"Json"*.
|
/// Formato de salida de las trazas. Opciones: *"Full"*, *"Compact"*, *"Pretty"* o *"Json"*.
|
||||||
pub format: String,
|
pub format: LogFormat,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
|
|
|
||||||
51
src/global/log_format.rs
Normal file
51
src/global/log_format.rs
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
use crate::AutoDefault;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Deserializer};
|
||||||
|
|
||||||
|
/// Formatos disponibles para mostrar las trazas.
|
||||||
|
///
|
||||||
|
/// El valor se obtiene de [`global::SETTINGS.log.format`](crate::global::Log::format) y determina
|
||||||
|
/// la representación textual de los eventos registrados por `tracing`.
|
||||||
|
/// El valor configurado no distingue entre mayúsculas y minúsculas.
|
||||||
|
#[derive(AutoDefault, Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub enum LogFormat {
|
||||||
|
/// Formato JSON estructurado.
|
||||||
|
Json,
|
||||||
|
|
||||||
|
/// Formato completo con detalles adicionales. Es el valor por defecto.
|
||||||
|
#[default]
|
||||||
|
Full,
|
||||||
|
|
||||||
|
/// Formato más conciso y legible.
|
||||||
|
Compact,
|
||||||
|
|
||||||
|
/// Formato human-friendly con colores y saltos de línea.
|
||||||
|
Pretty,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for LogFormat {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let raw = String::deserialize(deserializer)?;
|
||||||
|
let result = match raw.trim().to_ascii_lowercase().as_str() {
|
||||||
|
"json" => Self::Json,
|
||||||
|
"full" => Self::Full,
|
||||||
|
"compact" => Self::Compact,
|
||||||
|
"pretty" => Self::Pretty,
|
||||||
|
_ => {
|
||||||
|
let default = Self::default();
|
||||||
|
println!(
|
||||||
|
concat!(
|
||||||
|
"\nInvalid value \"{}\" for [log].format. ",
|
||||||
|
"Using \"{:?}\". Check settings.",
|
||||||
|
),
|
||||||
|
raw, default,
|
||||||
|
);
|
||||||
|
default
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
51
src/global/log_rolling.rs
Normal file
51
src/global/log_rolling.rs
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
use crate::AutoDefault;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Deserializer};
|
||||||
|
|
||||||
|
/// Modos de salida y rotación para el registro de trazas.
|
||||||
|
///
|
||||||
|
/// El valor se obtiene de [`global::SETTINGS.log.rolling`](crate::global::Log::rolling) y
|
||||||
|
/// determina si las trazas se muestran por pantalla o se vuelcan en archivos con rotación.
|
||||||
|
/// El valor configurado no distingue entre mayúsculas y minúsculas.
|
||||||
|
#[derive(AutoDefault, Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub enum LogRolling {
|
||||||
|
/// Escribe las trazas en la salida estándar (sin rotación de archivos).
|
||||||
|
Stdout,
|
||||||
|
/// Rotación diaria de archivos de traza.
|
||||||
|
#[default]
|
||||||
|
Daily,
|
||||||
|
/// Rotación horaria de archivos de traza.
|
||||||
|
Hourly,
|
||||||
|
/// Rotación por minutos de archivos de traza.
|
||||||
|
Minutely,
|
||||||
|
/// Archivo de traza "infinito", sin rotación.
|
||||||
|
Endless,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for LogRolling {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let raw = String::deserialize(deserializer)?;
|
||||||
|
let result = match raw.trim().to_ascii_lowercase().as_str() {
|
||||||
|
"stdout" => Self::Stdout,
|
||||||
|
"daily" => Self::Daily,
|
||||||
|
"hourly" => Self::Hourly,
|
||||||
|
"minutely" => Self::Minutely,
|
||||||
|
"endless" => Self::Endless,
|
||||||
|
_ => {
|
||||||
|
let default = Self::default();
|
||||||
|
println!(
|
||||||
|
concat!(
|
||||||
|
"\nInvalid value \"{}\" for [log].rolling. ",
|
||||||
|
"Using \"{:?}\". Check settings.",
|
||||||
|
),
|
||||||
|
raw, default,
|
||||||
|
);
|
||||||
|
default
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
45
src/trace.rs
45
src/trace.rs
|
|
@ -14,6 +14,7 @@
|
||||||
//! *spans* son estructurados, con la capacidad de registrar tipos de datos y mensajes de texto.
|
//! *spans* son estructurados, con la capacidad de registrar tipos de datos y mensajes de texto.
|
||||||
|
|
||||||
use crate::global;
|
use crate::global;
|
||||||
|
use crate::global::{LogFormat, LogRolling};
|
||||||
|
|
||||||
pub use tracing::{debug, error, info, trace, warn};
|
pub use tracing::{debug, error, info, trace, warn};
|
||||||
pub use tracing::{debug_span, error_span, info_span, trace_span, warn_span};
|
pub use tracing::{debug_span, error_span, info_span, trace_span, warn_span};
|
||||||
|
|
@ -33,7 +34,6 @@ use std::sync::LazyLock;
|
||||||
/// Dado que las trazas o eventos registrados poco antes de un fallo suelen ser cruciales para
|
/// Dado que las trazas o eventos registrados poco antes de un fallo suelen ser cruciales para
|
||||||
/// diagnosticar la causa, `Lazy<WorkerGuard>` garantiza que todos los registros almacenados se
|
/// diagnosticar la causa, `Lazy<WorkerGuard>` garantiza que todos los registros almacenados se
|
||||||
/// envíen antes de finalizar la ejecución.
|
/// envíen antes de finalizar la ejecución.
|
||||||
#[rustfmt::skip]
|
|
||||||
pub(crate) static TRACING: LazyLock<WorkerGuard> = LazyLock::new(|| {
|
pub(crate) static TRACING: LazyLock<WorkerGuard> = LazyLock::new(|| {
|
||||||
if !global::SETTINGS.log.enabled || cfg!(test) || cfg!(feature = "testing") {
|
if !global::SETTINGS.log.enabled || cfg!(test) || cfg!(feature = "testing") {
|
||||||
// Tracing desactivado, se instala un subscriber nulo.
|
// Tracing desactivado, se instala un subscriber nulo.
|
||||||
|
|
@ -46,25 +46,19 @@ pub(crate) static TRACING: LazyLock<WorkerGuard> = LazyLock::new(|| {
|
||||||
let env_filter = EnvFilter::try_new(&global::SETTINGS.log.tracing)
|
let env_filter = EnvFilter::try_new(&global::SETTINGS.log.tracing)
|
||||||
.unwrap_or_else(|_| EnvFilter::new("Info"));
|
.unwrap_or_else(|_| EnvFilter::new("Info"));
|
||||||
|
|
||||||
let rolling = global::SETTINGS.log.rolling.to_lowercase();
|
let rolling = global::SETTINGS.log.rolling;
|
||||||
|
|
||||||
let (non_blocking, guard) = match rolling.as_str() {
|
let (non_blocking, guard) = match rolling {
|
||||||
"stdout" => tracing_appender::non_blocking(std::io::stdout()),
|
LogRolling::Stdout => tracing_appender::non_blocking(std::io::stdout()),
|
||||||
_ => tracing_appender::non_blocking({
|
_ => tracing_appender::non_blocking({
|
||||||
let path = &global::SETTINGS.log.path;
|
let path = &global::SETTINGS.log.path;
|
||||||
let prefix = &global::SETTINGS.log.prefix;
|
let prefix = &global::SETTINGS.log.prefix;
|
||||||
match rolling.as_str() {
|
match rolling {
|
||||||
"daily" => tracing_appender::rolling::daily(path, prefix),
|
LogRolling::Daily => tracing_appender::rolling::daily(path, prefix),
|
||||||
"hourly" => tracing_appender::rolling::hourly(path, prefix),
|
LogRolling::Hourly => tracing_appender::rolling::hourly(path, prefix),
|
||||||
"minutely" => tracing_appender::rolling::minutely(path, prefix),
|
LogRolling::Minutely => tracing_appender::rolling::minutely(path, prefix),
|
||||||
"endless" => tracing_appender::rolling::never(path, prefix),
|
LogRolling::Endless => tracing_appender::rolling::never(path, prefix),
|
||||||
_ => {
|
LogRolling::Stdout => unreachable!("Stdout rolling already handled above"),
|
||||||
println!(
|
|
||||||
"Rolling value \"{}\" not valid. Using \"daily\". Check the settings file.",
|
|
||||||
global::SETTINGS.log.rolling,
|
|
||||||
);
|
|
||||||
tracing_appender::rolling::daily(path, prefix)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
@ -72,20 +66,13 @@ pub(crate) static TRACING: LazyLock<WorkerGuard> = LazyLock::new(|| {
|
||||||
let subscriber = tracing_subscriber::fmt()
|
let subscriber = tracing_subscriber::fmt()
|
||||||
.with_env_filter(env_filter)
|
.with_env_filter(env_filter)
|
||||||
.with_writer(non_blocking)
|
.with_writer(non_blocking)
|
||||||
.with_ansi(rolling.as_str() == "stdout");
|
.with_ansi(matches!(rolling, LogRolling::Stdout));
|
||||||
|
|
||||||
match global::SETTINGS.log.format.to_lowercase().as_str() {
|
match global::SETTINGS.log.format {
|
||||||
"json" => subscriber.json().init(),
|
LogFormat::Json => subscriber.json().init(),
|
||||||
"full" => subscriber.init(),
|
LogFormat::Full => subscriber.init(),
|
||||||
"compact" => subscriber.compact().init(),
|
LogFormat::Compact => subscriber.compact().init(),
|
||||||
"pretty" => subscriber.pretty().init(),
|
LogFormat::Pretty => subscriber.pretty().init(),
|
||||||
_ => {
|
|
||||||
println!(
|
|
||||||
"Tracing format \"{}\" not valid. Using \"Full\". Check the settings file.",
|
|
||||||
global::SETTINGS.log.format,
|
|
||||||
);
|
|
||||||
subscriber.init();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
guard
|
guard
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue