trace log use local time and get custom user agent

This commit is contained in:
houseme
2025-06-22 10:31:32 +08:00
parent e0f65e5e24
commit c7af6587f5
5 changed files with 86 additions and 77 deletions

View File

@@ -1,19 +1,19 @@
use crate::OtelConfig;
use flexi_logger::{Age, Cleanup, Criterion, DeferredNow, FileSpec, LogSpecification, Naming, Record, WriteMode, style};
use flexi_logger::{style, Age, Cleanup, Criterion, DeferredNow, FileSpec, LogSpecification, Naming, Record, WriteMode};
use nu_ansi_term::Color;
use opentelemetry::trace::TracerProvider;
use opentelemetry::{KeyValue, global};
use opentelemetry::{global, KeyValue};
use opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge;
use opentelemetry_otlp::WithExportConfig;
use opentelemetry_sdk::logs::SdkLoggerProvider;
use opentelemetry_sdk::{
Resource,
metrics::{MeterProviderBuilder, PeriodicReader, SdkMeterProvider},
trace::{RandomIdGenerator, Sampler, SdkTracerProvider},
Resource,
};
use opentelemetry_semantic_conventions::{
SCHEMA_URL,
attribute::{DEPLOYMENT_ENVIRONMENT_NAME, NETWORK_LOCAL_ADDRESS, SERVICE_VERSION as OTEL_SERVICE_VERSION},
SCHEMA_URL,
};
use rustfs_config::{
APP_NAME, DEFAULT_LOG_DIR, DEFAULT_LOG_KEEP_FILES, DEFAULT_LOG_LEVEL, ENVIRONMENT, METER_INTERVAL, SAMPLE_RATIO,
@@ -27,7 +27,8 @@ use tracing::info;
use tracing_error::ErrorLayer;
use tracing_opentelemetry::{MetricsLayer, OpenTelemetryLayer};
use tracing_subscriber::fmt::format::FmtSpan;
use tracing_subscriber::{EnvFilter, Layer, layer::SubscriberExt, util::SubscriberInitExt};
use tracing_subscriber::fmt::time::LocalTime;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Layer};
/// A guard object that manages the lifecycle of OpenTelemetry components.
///
@@ -224,6 +225,7 @@ pub(crate) fn init_telemetry(config: &OtelConfig) -> OtelGuard {
let fmt_layer = {
let enable_color = std::io::stdout().is_terminal();
let mut layer = tracing_subscriber::fmt::layer()
.with_timer(LocalTime::rfc_3339())
.with_target(true)
.with_ansi(enable_color)
.with_thread_names(true)

View File

@@ -38,6 +38,7 @@ rand = { workspace = true, optional = true }
futures = { workspace = true, optional = true }
transform-stream = { workspace = true, optional = true }
bytes = { workspace = true, optional = true }
sysinfo = { workspace = true, optional = true }
[dev-dependencies]
tempfile = { workspace = true }
@@ -62,4 +63,5 @@ crypto = ["dep:base64-simd", "dep:hex-simd"]
hash = ["dep:highway", "dep:md-5", "dep:sha2", "dep:blake3", "dep:serde", "dep:siphasher"]
os = ["dep:nix", "dep:tempfile", "winapi"] # operating system utilities
integration = [] # integration test features
full = ["ip", "tls", "net", "io", "hash", "os", "integration", "path", "crypto", "string", "compress"] # all features
sys = ["dep:sysinfo"] # system information features
full = ["ip", "tls", "net", "io", "hash", "os", "integration", "path", "crypto", "string", "compress", "sys"] # all features

View File

@@ -33,10 +33,13 @@ pub mod dirs;
#[cfg(feature = "tls")]
pub use certs::*;
#[cfg(feature = "hash")]
pub use hash::*;
#[cfg(feature = "io")]
pub use io::*;
#[cfg(feature = "ip")]
pub use ip::*;
@@ -45,3 +48,6 @@ pub use crypto::*;
#[cfg(feature = "compress")]
pub use compress::*;
#[cfg(feature = "sys")]
pub mod sys;

View File

@@ -0,0 +1,4 @@
mod user_agent;
pub use user_agent::get_user_agent;
pub use user_agent::ServiceType;

View File

@@ -1,14 +1,9 @@
use rustfs_config::VERSION;
use std::env;
use std::fmt;
#[cfg(unix)]
use std::os::unix::process::ExitStatusExt;
#[cfg(windows)]
use std::os::windows::process::ExitStatusExt;
use std::{env, process};
use sysinfo::System;
// Define Rustfs version
const RUSTFS_VERSION: &str = "1.0.0";
// Business Type Enumeration
/// Business Type Enumeration
#[derive(Debug, Clone, PartialEq)]
pub enum ServiceType {
Basis,
@@ -39,11 +34,16 @@ struct UserAgent {
}
impl UserAgent {
// Create a new UserAgent instance and accept business type parameters
/// Create a new UserAgent instance and accept business type parameters
///
/// # Arguments
/// * `service` - The type of service for which the User-Agent is being created.
/// # Returns
/// A new instance of `UserAgent` with the current OS platform, architecture, version, and service type.
fn new(service: ServiceType) -> Self {
let os_platform = Self::get_os_platform();
let arch = env::consts::ARCH.to_string();
let version = RUSTFS_VERSION.to_string();
let version = VERSION.to_string();
UserAgent {
os_platform,
@@ -53,64 +53,57 @@ impl UserAgent {
}
}
// Obtain operating system platform information
/// Obtain operating system platform information
fn get_os_platform() -> String {
let sys = System::new_all();
if cfg!(target_os = "windows") {
Self::get_windows_platform()
Self::get_windows_platform(&sys)
} else if cfg!(target_os = "macos") {
Self::get_macos_platform()
Self::get_macos_platform(&sys)
} else if cfg!(target_os = "linux") {
Self::get_linux_platform()
Self::get_linux_platform(&sys)
} else {
"Unknown".to_string()
}
}
// Get Windows platform information
/// Get Windows platform information
#[cfg(windows)]
fn get_windows_platform() -> String {
// Use cmd /c ver to get the version
let output = process::Command::new("cmd")
.args(&["/C", "ver"])
.output()
.unwrap_or_else(|_| process::Output {
status: process::ExitStatus::from_raw(0),
stdout: Vec::new(),
stderr: Vec::new(),
});
let version = String::from_utf8_lossy(&output.stdout);
let version = version
.lines()
.next()
.unwrap_or("Windows NT 10.0")
.replace("Microsoft Windows [Version ", "")
.replace("]", "");
format!("Windows NT {}", version.trim())
fn get_windows_platform(sys: &System) -> String {
// Priority to using sysinfo to get versions
if let Some(version) = sys.os_version() {
format!("Windows NT {}", version)
} else {
// Fallback to cmd /c ver
let output = std::process::Command::new("cmd")
.args(&["/C", "ver"])
.output()
.unwrap_or_default();
let version = String::from_utf8_lossy(&output.stdout);
let version = version
.lines()
.next()
.unwrap_or("Windows NT 10.0")
.replace("Microsoft Windows [Version ", "")
.replace("]", "");
format!("Windows NT {}", version.trim())
}
}
#[cfg(not(windows))]
fn get_windows_platform() -> String {
fn get_windows_platform(_sys: &System) -> String {
"N/A".to_string()
}
// Get macOS platform information
/// Get macOS platform information
#[cfg(target_os = "macos")]
fn get_macos_platform() -> String {
let output = process::Command::new("sw_vers")
.args(&["-productVersion"])
.output()
.unwrap_or_else(|_| process::Output {
status: process::ExitStatus::from_raw(0),
stdout: Vec::new(),
stderr: Vec::new(),
});
let version = String::from_utf8_lossy(&output.stdout).trim().to_string();
let parts: Vec<&str> = version.split('.').collect();
let major = parts.get(0).unwrap_or(&"10").parse::<i32>().unwrap_or(10);
let minor = parts.get(1).map_or("15", |&m| m);
let patch = parts.get(2).map_or("0", |&p| p);
fn get_macos_platform(_sys: &System) -> String {
let binding = System::os_version().unwrap_or("14.5.0".to_string());
let version = binding.split('.').collect::<Vec<&str>>();
let major = version.get(0).unwrap_or(&"14").to_string();
let minor = version.get(1).unwrap_or(&"5").to_string();
let patch = version.get(2).unwrap_or(&"0").to_string();
// Detect whether it is an Apple Silicon chip
let arch = env::consts::ARCH;
let cpu_info = if arch == "aarch64" { "Apple" } else { "Intel" };
@@ -119,36 +112,25 @@ impl UserAgent {
}
#[cfg(not(target_os = "macos"))]
fn get_macos_platform() -> String {
fn get_macos_platform(_sys: &System) -> String {
"N/A".to_string()
}
// Get Linux platform information
/// Get Linux platform information
#[cfg(target_os = "linux")]
fn get_linux_platform() -> String {
let output = process::Command::new("uname")
.arg("-r")
.output()
.unwrap_or_else(|_| process::Output {
status: process::ExitStatus::from_raw(0),
stdout: Vec::new(),
stderr: Vec::new(),
});
if output.status.success() {
let release = String::from_utf8_lossy(&output.stdout).trim().to_string();
format!("X11; Linux {}", release)
} else {
"X11; Linux Unknown".to_string()
}
fn get_linux_platform(sys: &System) -> String {
let name = sys.name().unwrap_or("Linux".to_string());
let version = sys.os_version().unwrap_or("Unknown".to_string());
format!("X11; {} {}", name, version)
}
#[cfg(not(target_os = "linux"))]
fn get_linux_platform() -> String {
fn get_linux_platform(_sys: &System) -> String {
"N/A".to_string()
}
}
// Implement Display trait to format User-Agent
/// Implement Display trait to format User-Agent
impl fmt::Display for UserAgent {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.service == ServiceType::Basis {
@@ -195,7 +177,6 @@ mod tests {
let ua = get_user_agent(ServiceType::Event);
assert!(ua.starts_with("Mozilla/5.0"));
assert!(ua.contains("Rustfs/1.0.0 (event)"));
println!("User-Agent: {}", ua);
}
@@ -214,4 +195,18 @@ mod tests {
assert!(ua.contains("Rustfs/1.0.0 (monitor)"));
println!("User-Agent: {}", ua);
}
#[test]
fn test_all_service_type() {
// Example: Generate User-Agents of Different Business Types
let ua_core = get_user_agent(ServiceType::Core);
let ua_event = get_user_agent(ServiceType::Event);
let ua_logger = get_user_agent(ServiceType::Logger);
let ua_custom = get_user_agent(ServiceType::Custom("monitor".to_string()));
println!("Core User-Agent: {}", ua_core);
println!("Event User-Agent: {}", ua_event);
println!("Logger User-Agent: {}", ua_logger);
println!("Custom User-Agent: {}", ua_custom);
}
}