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
+7 -5
View File
@@ -1,19 +1,19 @@
use crate::OtelConfig; 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 nu_ansi_term::Color;
use opentelemetry::trace::TracerProvider; use opentelemetry::trace::TracerProvider;
use opentelemetry::{KeyValue, global}; use opentelemetry::{global, KeyValue};
use opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge; use opentelemetry_appender_tracing::layer::OpenTelemetryTracingBridge;
use opentelemetry_otlp::WithExportConfig; use opentelemetry_otlp::WithExportConfig;
use opentelemetry_sdk::logs::SdkLoggerProvider; use opentelemetry_sdk::logs::SdkLoggerProvider;
use opentelemetry_sdk::{ use opentelemetry_sdk::{
Resource,
metrics::{MeterProviderBuilder, PeriodicReader, SdkMeterProvider}, metrics::{MeterProviderBuilder, PeriodicReader, SdkMeterProvider},
trace::{RandomIdGenerator, Sampler, SdkTracerProvider}, trace::{RandomIdGenerator, Sampler, SdkTracerProvider},
Resource,
}; };
use opentelemetry_semantic_conventions::{ use opentelemetry_semantic_conventions::{
SCHEMA_URL,
attribute::{DEPLOYMENT_ENVIRONMENT_NAME, NETWORK_LOCAL_ADDRESS, SERVICE_VERSION as OTEL_SERVICE_VERSION}, attribute::{DEPLOYMENT_ENVIRONMENT_NAME, NETWORK_LOCAL_ADDRESS, SERVICE_VERSION as OTEL_SERVICE_VERSION},
SCHEMA_URL,
}; };
use rustfs_config::{ use rustfs_config::{
APP_NAME, DEFAULT_LOG_DIR, DEFAULT_LOG_KEEP_FILES, DEFAULT_LOG_LEVEL, ENVIRONMENT, METER_INTERVAL, SAMPLE_RATIO, 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_error::ErrorLayer;
use tracing_opentelemetry::{MetricsLayer, OpenTelemetryLayer}; use tracing_opentelemetry::{MetricsLayer, OpenTelemetryLayer};
use tracing_subscriber::fmt::format::FmtSpan; 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. /// 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 fmt_layer = {
let enable_color = std::io::stdout().is_terminal(); let enable_color = std::io::stdout().is_terminal();
let mut layer = tracing_subscriber::fmt::layer() let mut layer = tracing_subscriber::fmt::layer()
.with_timer(LocalTime::rfc_3339())
.with_target(true) .with_target(true)
.with_ansi(enable_color) .with_ansi(enable_color)
.with_thread_names(true) .with_thread_names(true)
+3 -1
View File
@@ -38,6 +38,7 @@ rand = { workspace = true, optional = true }
futures = { workspace = true, optional = true } futures = { workspace = true, optional = true }
transform-stream = { workspace = true, optional = true } transform-stream = { workspace = true, optional = true }
bytes = { workspace = true, optional = true } bytes = { workspace = true, optional = true }
sysinfo = { workspace = true, optional = true }
[dev-dependencies] [dev-dependencies]
tempfile = { workspace = true } 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"] hash = ["dep:highway", "dep:md-5", "dep:sha2", "dep:blake3", "dep:serde", "dep:siphasher"]
os = ["dep:nix", "dep:tempfile", "winapi"] # operating system utilities os = ["dep:nix", "dep:tempfile", "winapi"] # operating system utilities
integration = [] # integration test features 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
+6
View File
@@ -33,10 +33,13 @@ pub mod dirs;
#[cfg(feature = "tls")] #[cfg(feature = "tls")]
pub use certs::*; pub use certs::*;
#[cfg(feature = "hash")] #[cfg(feature = "hash")]
pub use hash::*; pub use hash::*;
#[cfg(feature = "io")] #[cfg(feature = "io")]
pub use io::*; pub use io::*;
#[cfg(feature = "ip")] #[cfg(feature = "ip")]
pub use ip::*; pub use ip::*;
@@ -45,3 +48,6 @@ pub use crypto::*;
#[cfg(feature = "compress")] #[cfg(feature = "compress")]
pub use compress::*; pub use compress::*;
#[cfg(feature = "sys")]
pub mod sys;
+4
View File
@@ -0,0 +1,4 @@
mod user_agent;
pub use user_agent::get_user_agent;
pub use user_agent::ServiceType;
@@ -1,14 +1,9 @@
use rustfs_config::VERSION;
use std::env;
use std::fmt; use std::fmt;
#[cfg(unix)] use sysinfo::System;
use std::os::unix::process::ExitStatusExt;
#[cfg(windows)]
use std::os::windows::process::ExitStatusExt;
use std::{env, process};
// Define Rustfs version /// Business Type Enumeration
const RUSTFS_VERSION: &str = "1.0.0";
// Business Type Enumeration
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum ServiceType { pub enum ServiceType {
Basis, Basis,
@@ -39,11 +34,16 @@ struct UserAgent {
} }
impl 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 { fn new(service: ServiceType) -> Self {
let os_platform = Self::get_os_platform(); let os_platform = Self::get_os_platform();
let arch = env::consts::ARCH.to_string(); let arch = env::consts::ARCH.to_string();
let version = RUSTFS_VERSION.to_string(); let version = VERSION.to_string();
UserAgent { UserAgent {
os_platform, os_platform,
@@ -53,64 +53,57 @@ impl UserAgent {
} }
} }
// Obtain operating system platform information /// Obtain operating system platform information
fn get_os_platform() -> String { fn get_os_platform() -> String {
let sys = System::new_all();
if cfg!(target_os = "windows") { if cfg!(target_os = "windows") {
Self::get_windows_platform() Self::get_windows_platform(&sys)
} else if cfg!(target_os = "macos") { } else if cfg!(target_os = "macos") {
Self::get_macos_platform() Self::get_macos_platform(&sys)
} else if cfg!(target_os = "linux") { } else if cfg!(target_os = "linux") {
Self::get_linux_platform() Self::get_linux_platform(&sys)
} else { } else {
"Unknown".to_string() "Unknown".to_string()
} }
} }
// Get Windows platform information /// Get Windows platform information
#[cfg(windows)] #[cfg(windows)]
fn get_windows_platform() -> String { fn get_windows_platform(sys: &System) -> String {
// Use cmd /c ver to get the version // Priority to using sysinfo to get versions
let output = process::Command::new("cmd") if let Some(version) = sys.os_version() {
.args(&["/C", "ver"]) format!("Windows NT {}", version)
.output() } else {
.unwrap_or_else(|_| process::Output { // Fallback to cmd /c ver
status: process::ExitStatus::from_raw(0), let output = std::process::Command::new("cmd")
stdout: Vec::new(), .args(&["/C", "ver"])
stderr: Vec::new(), .output()
}); .unwrap_or_default();
let version = String::from_utf8_lossy(&output.stdout); let version = String::from_utf8_lossy(&output.stdout);
let version = version let version = version
.lines() .lines()
.next() .next()
.unwrap_or("Windows NT 10.0") .unwrap_or("Windows NT 10.0")
.replace("Microsoft Windows [Version ", "") .replace("Microsoft Windows [Version ", "")
.replace("]", ""); .replace("]", "");
format!("Windows NT {}", version.trim()) format!("Windows NT {}", version.trim())
}
} }
#[cfg(not(windows))] #[cfg(not(windows))]
fn get_windows_platform() -> String { fn get_windows_platform(_sys: &System) -> String {
"N/A".to_string() "N/A".to_string()
} }
// Get macOS platform information /// Get macOS platform information
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
fn get_macos_platform() -> String { fn get_macos_platform(_sys: &System) -> String {
let output = process::Command::new("sw_vers") let binding = System::os_version().unwrap_or("14.5.0".to_string());
.args(&["-productVersion"]) let version = binding.split('.').collect::<Vec<&str>>();
.output() let major = version.get(0).unwrap_or(&"14").to_string();
.unwrap_or_else(|_| process::Output { let minor = version.get(1).unwrap_or(&"5").to_string();
status: process::ExitStatus::from_raw(0), let patch = version.get(2).unwrap_or(&"0").to_string();
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);
// Detect whether it is an Apple Silicon chip
let arch = env::consts::ARCH; let arch = env::consts::ARCH;
let cpu_info = if arch == "aarch64" { "Apple" } else { "Intel" }; let cpu_info = if arch == "aarch64" { "Apple" } else { "Intel" };
@@ -119,36 +112,25 @@ impl UserAgent {
} }
#[cfg(not(target_os = "macos"))] #[cfg(not(target_os = "macos"))]
fn get_macos_platform() -> String { fn get_macos_platform(_sys: &System) -> String {
"N/A".to_string() "N/A".to_string()
} }
// Get Linux platform information /// Get Linux platform information
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
fn get_linux_platform() -> String { fn get_linux_platform(sys: &System) -> String {
let output = process::Command::new("uname") let name = sys.name().unwrap_or("Linux".to_string());
.arg("-r") let version = sys.os_version().unwrap_or("Unknown".to_string());
.output() format!("X11; {} {}", name, version)
.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()
}
} }
#[cfg(not(target_os = "linux"))] #[cfg(not(target_os = "linux"))]
fn get_linux_platform() -> String { fn get_linux_platform(_sys: &System) -> String {
"N/A".to_string() "N/A".to_string()
} }
} }
// Implement Display trait to format User-Agent /// Implement Display trait to format User-Agent
impl fmt::Display for UserAgent { impl fmt::Display for UserAgent {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.service == ServiceType::Basis { if self.service == ServiceType::Basis {
@@ -195,7 +177,6 @@ mod tests {
let ua = get_user_agent(ServiceType::Event); let ua = get_user_agent(ServiceType::Event);
assert!(ua.starts_with("Mozilla/5.0")); assert!(ua.starts_with("Mozilla/5.0"));
assert!(ua.contains("Rustfs/1.0.0 (event)")); assert!(ua.contains("Rustfs/1.0.0 (event)"));
println!("User-Agent: {}", ua); println!("User-Agent: {}", ua);
} }
@@ -214,4 +195,18 @@ mod tests {
assert!(ua.contains("Rustfs/1.0.0 (monitor)")); assert!(ua.contains("Rustfs/1.0.0 (monitor)"));
println!("User-Agent: {}", ua); 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);
}
} }