mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-21 20:06:37 +00:00
fix(logging): bound hot-path span amplification (#5763)
* fix(logging): bound hot-path span amplification * refactor(logging): reuse HTTP log target constant Co-Authored-By: heihutu <heihutu@gmail.com> --------- Co-authored-by: Anthony Martin <949506+anthonymartin@users.noreply.github.com> Co-authored-by: houseme <housemecn@gmail.com> Co-authored-by: heihutu <heihutu@gmail.com>
This commit is contained in:
@@ -749,7 +749,7 @@ impl crate::storage_api_contracts::list::ListOperations for Sets {
|
|||||||
type WalkCancellation = CancellationToken;
|
type WalkCancellation = CancellationToken;
|
||||||
type WalkResultSender = tokio::sync::mpsc::Sender<ObjectInfoOrErr>;
|
type WalkResultSender = tokio::sync::mpsc::Sender<ObjectInfoOrErr>;
|
||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(level = "trace", skip(self))]
|
||||||
async fn list_objects_v2(
|
async fn list_objects_v2(
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
bucket: &str,
|
bucket: &str,
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ impl crate::storage_api_contracts::list::ListOperations for SetDisks {
|
|||||||
type WalkCancellation = CancellationToken;
|
type WalkCancellation = CancellationToken;
|
||||||
type WalkResultSender = Sender<ObjectInfoOrErr>;
|
type WalkResultSender = Sender<ObjectInfoOrErr>;
|
||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(level = "trace", skip(self))]
|
||||||
async fn list_objects_v2(
|
async fn list_objects_v2(
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
bucket: &str,
|
bucket: &str,
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ impl crate::storage_api_contracts::namespace::NamespaceLocking for SetDisks {
|
|||||||
type Error = Error;
|
type Error = Error;
|
||||||
type NamespaceLock = NamespaceLockWrapper;
|
type NamespaceLock = NamespaceLockWrapper;
|
||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(level = "trace", skip(self))]
|
||||||
async fn new_ns_lock(&self, bucket: &str, object: &str) -> Result<NamespaceLockWrapper> {
|
async fn new_ns_lock(&self, bucket: &str, object: &str) -> Result<NamespaceLockWrapper> {
|
||||||
// Resolved from this set's own instance context (backlog#1052), not the
|
// Resolved from this set's own instance context (backlog#1052), not the
|
||||||
// ambient facade: the facade tracks whichever context is currently
|
// ambient facade: the facade tracks whichever context is currently
|
||||||
|
|||||||
@@ -4343,7 +4343,7 @@ impl crate::storage_api_contracts::object::ObjectOperations for SetDisks {
|
|||||||
Ok(obj_info)
|
Ok(obj_info)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(level = "trace", skip(self))]
|
||||||
async fn get_object_info(&self, bucket: &str, object: &str, opts: &ObjectOptions) -> Result<ObjectInfo> {
|
async fn get_object_info(&self, bucket: &str, object: &str, opts: &ObjectOptions) -> Result<ObjectInfo> {
|
||||||
crate::hp_guard!("SetDisks::get_object_info");
|
crate::hp_guard!("SetDisks::get_object_info");
|
||||||
// Acquire a shared read-lock to protect consistency during info fetch
|
// Acquire a shared read-lock to protect consistency during info fetch
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
impl ECStore {
|
impl ECStore {
|
||||||
#[instrument(skip(self))]
|
#[instrument(level = "trace", skip(self))]
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub(super) async fn handle_list_objects_v2(
|
pub(super) async fn handle_list_objects_v2(
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
|
|||||||
@@ -582,7 +582,7 @@ impl crate::storage_api_contracts::list::ListOperations for ECStore {
|
|||||||
// @start_after as marker when continuation_token empty
|
// @start_after as marker when continuation_token empty
|
||||||
// @delimiter default="/", empty when recursive
|
// @delimiter default="/", empty when recursive
|
||||||
// @max_keys limit
|
// @max_keys limit
|
||||||
#[instrument(skip(self))]
|
#[instrument(level = "trace", skip(self))]
|
||||||
async fn list_objects_v2(
|
async fn list_objects_v2(
|
||||||
self: Arc<Self>,
|
self: Arc<Self>,
|
||||||
bucket: &str,
|
bucket: &str,
|
||||||
|
|||||||
@@ -1253,7 +1253,7 @@ impl ECStore {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(self))]
|
#[instrument(level = "trace", skip(self))]
|
||||||
pub(super) async fn handle_get_object_info(&self, bucket: &str, object: &str, opts: &ObjectOptions) -> Result<ObjectInfo> {
|
pub(super) async fn handle_get_object_info(&self, bucket: &str, object: &str, opts: &ObjectOptions) -> Result<ObjectInfo> {
|
||||||
check_object_args(bucket, object)?;
|
check_object_args(bucket, object)?;
|
||||||
|
|
||||||
|
|||||||
@@ -661,7 +661,7 @@ impl ECStore {
|
|||||||
unique_disks.into_values().collect()
|
unique_disks.into_values().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(self))]
|
#[instrument(level = "trace", skip(self))]
|
||||||
pub(super) async fn handle_new_ns_lock(&self, bucket: &str, object: &str) -> Result<NamespaceLockWrapper> {
|
pub(super) async fn handle_new_ns_lock(&self, bucket: &str, object: &str) -> Result<NamespaceLockWrapper> {
|
||||||
self.pools[0].new_ns_lock(bucket, object).await
|
self.pools[0].new_ns_lock(bucket, object).await
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ pub use metrics::{
|
|||||||
MetricsRuntimeShutdownHandle, MetricsRuntimeStatusSnapshot, MetricsRuntimeWorkerMutation, init_metrics_runtime,
|
MetricsRuntimeShutdownHandle, MetricsRuntimeStatusSnapshot, MetricsRuntimeWorkerMutation, init_metrics_runtime,
|
||||||
metrics_runtime_controller_snapshot, metrics_runtime_status_snapshot,
|
metrics_runtime_controller_snapshot, metrics_runtime_status_snapshot,
|
||||||
};
|
};
|
||||||
pub use telemetry::{OtelGuard, Recorder};
|
pub use telemetry::{HTTP_SERVER_LOG_TARGET, OtelGuard, Recorder};
|
||||||
|
|
||||||
// Dial9 Tokio runtime telemetry
|
// Dial9 Tokio runtime telemetry
|
||||||
// Re-export dial9 types at crate root level for easier access
|
// Re-export dial9 types at crate root level for easier access
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ use tracing_subscriber::{
|
|||||||
filter::{FilterFn, LevelFilter, filter_fn},
|
filter::{FilterFn, LevelFilter, filter_fn},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const HTTP_SERVER_LOG_TARGET: &str = "rustfs::server::http";
|
||||||
|
|
||||||
/// Pyroscope emits raw reqwest errors from its background session manager.
|
/// Pyroscope emits raw reqwest errors from its background session manager.
|
||||||
/// Those errors can include the configured endpoint, so they must never reach
|
/// Those errors can include the configured endpoint, so they must never reach
|
||||||
/// a RustFS logging sink even when an operator enables verbose dependency logs.
|
/// a RustFS logging sink even when an operator enables verbose dependency logs.
|
||||||
@@ -43,9 +45,9 @@ pub(super) fn pyroscope_log_filter() -> FilterFn {
|
|||||||
///
|
///
|
||||||
/// If `default_level` is provided, it is used directly. Otherwise, the
|
/// If `default_level` is provided, it is used directly. Otherwise, the
|
||||||
/// `RUST_LOG` environment variable takes precedence over `logger_level`.
|
/// `RUST_LOG` environment variable takes precedence over `logger_level`.
|
||||||
/// For non-verbose levels (`info`, `warn`, `error`), noisy internal crates
|
/// For non-verbose levels (`info`, `warn`, `error`), noisy dependency targets
|
||||||
/// (`hyper`, `tonic`, `h2`, `reqwest`, `tower`) are automatically silenced
|
/// are automatically suppressed based on the effective log configuration.
|
||||||
/// based on the effective log configuration.
|
/// Transport internals are disabled, while `s3s` remains visible at WARN.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `logger_level` - The desired log level string (e.g., `"info"`, `"debug"`).
|
/// * `logger_level` - The desired log level string (e.g., `"info"`, `"debug"`).
|
||||||
@@ -157,7 +159,26 @@ fn should_demote_http_request_logs(logger_level: &str, default_level: Option<&st
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(rust_log) = rust_log {
|
if let Some(rust_log) = rust_log {
|
||||||
if let Some(level) = effective_level_for_target(rust_log, "rustfs::server::http") {
|
if let Some(level) = effective_level_for_target(rust_log, HTTP_SERVER_LOG_TARGET) {
|
||||||
|
let level = level.trim().to_ascii_lowercase();
|
||||||
|
return matches!(level.as_str(), "info" | "warn");
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let level = logger_level.trim().to_ascii_lowercase();
|
||||||
|
matches!(level.as_str(), "info" | "warn")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn should_demote_s3s_logs(logger_level: &str, default_level: Option<&str>, rust_log: Option<&str>) -> bool {
|
||||||
|
if let Some(level) = default_level {
|
||||||
|
let level = level.trim().to_ascii_lowercase();
|
||||||
|
return matches!(level.as_str(), "info" | "warn");
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(rust_log) = rust_log {
|
||||||
|
if let Some(level) = effective_level_for_target(rust_log, "s3s") {
|
||||||
let level = level.trim().to_ascii_lowercase();
|
let level = level.trim().to_ascii_lowercase();
|
||||||
return matches!(level.as_str(), "info" | "warn");
|
return matches!(level.as_str(), "info" | "warn");
|
||||||
}
|
}
|
||||||
@@ -214,7 +235,14 @@ pub(super) fn build_env_filter(logger_level: &str, default_level: Option<&str>)
|
|||||||
if should_demote_http_request_logs(logger_level, default_level, rust_log_env.as_deref()) {
|
if should_demote_http_request_logs(logger_level, default_level, rust_log_env.as_deref()) {
|
||||||
// HTTP request logs are demoted to WARN to reduce volume in production,
|
// HTTP request logs are demoted to WARN to reduce volume in production,
|
||||||
// but only when the effective log level is not stricter than WARN.
|
// but only when the effective log level is not stricter than WARN.
|
||||||
directives.push(("rustfs::server::http", LevelFilter::WARN));
|
directives.push((HTTP_SERVER_LOG_TARGET, LevelFilter::WARN));
|
||||||
|
}
|
||||||
|
|
||||||
|
if should_demote_s3s_logs(logger_level, default_level, rust_log_env.as_deref()) {
|
||||||
|
// s3s instruments each authentication request through multiple
|
||||||
|
// nested INFO spans. Keep warnings and errors in normal production
|
||||||
|
// logs without promoting it when the effective base is stricter.
|
||||||
|
directives.push(("s3s", LevelFilter::WARN));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (crate_name, level) in directives {
|
for (crate_name, level) in directives {
|
||||||
@@ -250,6 +278,54 @@ pub(super) fn build_env_filter(logger_level: &str, default_level: Option<&str>)
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use std::{
|
||||||
|
io::{self, Write},
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
};
|
||||||
|
use tracing::subscriber::with_default;
|
||||||
|
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
struct SharedWriter(Arc<Mutex<Vec<u8>>>);
|
||||||
|
|
||||||
|
struct SharedWriterGuard(Arc<Mutex<Vec<u8>>>);
|
||||||
|
|
||||||
|
impl<'a> tracing_subscriber::fmt::MakeWriter<'a> for SharedWriter {
|
||||||
|
type Writer = SharedWriterGuard;
|
||||||
|
|
||||||
|
fn make_writer(&'a self) -> Self::Writer {
|
||||||
|
SharedWriterGuard(Arc::clone(&self.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Write for SharedWriterGuard {
|
||||||
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||||
|
self.0.lock().expect("log buffer").extend_from_slice(buf);
|
||||||
|
Ok(buf.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> io::Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn capture_with_filter(filter: EnvFilter, emit: impl FnOnce()) -> String {
|
||||||
|
let writer = SharedWriter::default();
|
||||||
|
let captured = Arc::clone(&writer.0);
|
||||||
|
let subscriber = tracing_subscriber::fmt()
|
||||||
|
.without_time()
|
||||||
|
.with_ansi(false)
|
||||||
|
.with_env_filter(filter)
|
||||||
|
.with_writer(writer)
|
||||||
|
.finish();
|
||||||
|
|
||||||
|
with_default(subscriber, emit);
|
||||||
|
let bytes = captured.lock().expect("captured logs").clone();
|
||||||
|
String::from_utf8(bytes).expect("utf8 logs")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn http_log_directive(level: &str) -> String {
|
||||||
|
format!("{HTTP_SERVER_LOG_TARGET}={level}")
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_is_verbose_level() {
|
fn test_is_verbose_level() {
|
||||||
@@ -302,9 +378,30 @@ mod tests {
|
|||||||
assert!(!should_demote_http_request_logs("info", None, Some("foo=warn")));
|
assert!(!should_demote_http_request_logs("info", None, Some("foo=warn")));
|
||||||
assert!(!should_demote_http_request_logs("info", None, Some("rustfs=error")));
|
assert!(!should_demote_http_request_logs("info", None, Some("rustfs=error")));
|
||||||
assert!(!should_demote_http_request_logs("info", None, Some("rustfs::server=error")));
|
assert!(!should_demote_http_request_logs("info", None, Some("rustfs::server=error")));
|
||||||
assert!(!should_demote_http_request_logs("info", None, Some("rustfs::server::http=error")));
|
assert!(!should_demote_http_request_logs("info", None, Some(&http_log_directive("error"))));
|
||||||
assert!(!should_demote_http_request_logs("info", None, Some("WARN,rustfs::server::http=error")));
|
assert!(!should_demote_http_request_logs(
|
||||||
assert!(should_demote_http_request_logs("error", None, Some("WARN,rustfs::server::http=warn")));
|
"info",
|
||||||
|
None,
|
||||||
|
Some(&format!("WARN,{}", http_log_directive("error")))
|
||||||
|
));
|
||||||
|
assert!(should_demote_http_request_logs(
|
||||||
|
"error",
|
||||||
|
None,
|
||||||
|
Some(&format!("WARN,{}", http_log_directive("warn")))
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_should_demote_s3s_logs() {
|
||||||
|
assert!(should_demote_s3s_logs("info", None, None));
|
||||||
|
assert!(should_demote_s3s_logs("warn", None, None));
|
||||||
|
assert!(!should_demote_s3s_logs("error", None, None));
|
||||||
|
assert!(!should_demote_s3s_logs("off", None, None));
|
||||||
|
assert!(!should_demote_s3s_logs("info", None, Some("ERROR")));
|
||||||
|
assert!(should_demote_s3s_logs("error", None, Some("WARN")));
|
||||||
|
assert!(!should_demote_s3s_logs("info", None, Some("foo=warn")));
|
||||||
|
assert!(!should_demote_s3s_logs("info", None, Some("s3s=error")));
|
||||||
|
assert!(should_demote_s3s_logs("error", None, Some("WARN,s3s=warn")));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -315,7 +412,7 @@ mod tests {
|
|||||||
let filter = build_env_filter("info", None);
|
let filter = build_env_filter("info", None);
|
||||||
let filter_str = filter.to_string();
|
let filter_str = filter.to_string();
|
||||||
|
|
||||||
for noisy_crate in ["hyper", "tonic", "h2", "reqwest", "tower"] {
|
for noisy_crate in ["hyper", "tonic", "h2", "reqwest", "tower", "s3s"] {
|
||||||
assert!(
|
assert!(
|
||||||
filter_str.contains(noisy_crate),
|
filter_str.contains(noisy_crate),
|
||||||
"expected EnvFilter to contain suppression directive for `{}`; got `{}`",
|
"expected EnvFilter to contain suppression directive for `{}`; got `{}`",
|
||||||
@@ -385,7 +482,7 @@ mod tests {
|
|||||||
let filter_str = filter.to_string().to_ascii_lowercase();
|
let filter_str = filter.to_string().to_ascii_lowercase();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
!filter_str.contains("rustfs::server::http=warn"),
|
!filter_str.contains(&http_log_directive("warn")),
|
||||||
"http logs must not be promoted above error level when RUST_LOG=ERROR overrides logger_level=info: {filter_str}"
|
"http logs must not be promoted above error level when RUST_LOG=ERROR overrides logger_level=info: {filter_str}"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -395,12 +492,25 @@ mod tests {
|
|||||||
let filter_str = filter.to_string().to_ascii_lowercase();
|
let filter_str = filter.to_string().to_ascii_lowercase();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
!filter_str.contains("rustfs::server::http=warn"),
|
!filter_str.contains(&http_log_directive("warn")),
|
||||||
"http logs must not be promoted above error level when RUST_LOG=rustfs=error overrides logger_level=info: {filter_str}"
|
"http logs must not be promoted above error level when RUST_LOG=rustfs=error overrides logger_level=info: {filter_str}"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_build_env_filter_does_not_promote_s3s_above_error() {
|
||||||
|
temp_env::with_var("RUST_LOG", Some("ERROR"), || {
|
||||||
|
let filter = build_env_filter("info", None).to_string().to_ascii_lowercase();
|
||||||
|
assert!(!filter.contains("s3s=warn"), "s3s must not be promoted above ERROR: {filter}");
|
||||||
|
});
|
||||||
|
|
||||||
|
temp_env::with_var("RUST_LOG", Some("foo=warn"), || {
|
||||||
|
let filter = build_env_filter("info", None).to_string().to_ascii_lowercase();
|
||||||
|
assert!(!filter.contains("s3s=warn"), "an unrelated target must not enable s3s: {filter}");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_build_env_filter_does_not_fallback_to_logger_level_for_http_demotion() {
|
fn test_build_env_filter_does_not_fallback_to_logger_level_for_http_demotion() {
|
||||||
temp_env::with_var("RUST_LOG", Some("foo=warn"), || {
|
temp_env::with_var("RUST_LOG", Some("foo=warn"), || {
|
||||||
@@ -408,7 +518,7 @@ mod tests {
|
|||||||
let filter_str = filter.to_string().to_ascii_lowercase();
|
let filter_str = filter.to_string().to_ascii_lowercase();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
!filter_str.contains("rustfs::server::http=warn"),
|
!filter_str.contains(&http_log_directive("warn")),
|
||||||
"http log demotion must not fall back to logger_level when RUST_LOG only defines unrelated targets: {filter_str}"
|
"http log demotion must not fall back to logger_level when RUST_LOG only defines unrelated targets: {filter_str}"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -426,4 +536,41 @@ mod tests {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_production_filter_suppresses_s3s_info_but_keeps_warn() {
|
||||||
|
temp_env::with_var("RUST_LOG", None::<&str>, || {
|
||||||
|
let output = capture_with_filter(build_env_filter("info", None), || {
|
||||||
|
tracing::info!(target: "s3s::auth", "s3s info must be suppressed");
|
||||||
|
tracing::warn!(target: "s3s::auth", "s3s warning must remain");
|
||||||
|
});
|
||||||
|
|
||||||
|
assert!(!output.contains("s3s info must be suppressed"), "{output}");
|
||||||
|
assert!(output.contains("s3s warning must remain"), "{output}");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_explicit_s3s_target_restores_info_diagnostics() {
|
||||||
|
temp_env::with_var("RUST_LOG", Some("info,s3s=info"), || {
|
||||||
|
let output = capture_with_filter(build_env_filter("info", None), || {
|
||||||
|
tracing::info!(target: "s3s::auth", "explicit s3s info");
|
||||||
|
});
|
||||||
|
|
||||||
|
assert!(output.contains("explicit s3s info"), "{output}");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_http_target_suppresses_success_but_keeps_errors() {
|
||||||
|
temp_env::with_var("RUST_LOG", None::<&str>, || {
|
||||||
|
let output = capture_with_filter(build_env_filter("info", None), || {
|
||||||
|
tracing::info!(target: HTTP_SERVER_LOG_TARGET, "healthy readiness response");
|
||||||
|
tracing::error!(target: HTTP_SERVER_LOG_TARGET, "failed readiness response");
|
||||||
|
});
|
||||||
|
|
||||||
|
assert!(!output.contains("healthy readiness response"), "{output}");
|
||||||
|
assert!(output.contains("failed readiness response"), "{output}");
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ mod rolling;
|
|||||||
|
|
||||||
use crate::TelemetryError;
|
use crate::TelemetryError;
|
||||||
use crate::config::OtelConfig;
|
use crate::config::OtelConfig;
|
||||||
|
pub use filter::HTTP_SERVER_LOG_TARGET;
|
||||||
pub use guard::OtelGuard;
|
pub use guard::OtelGuard;
|
||||||
pub use recorder::{Recorder, retire_metric_series};
|
pub use recorder::{Recorder, retire_metric_series};
|
||||||
use rustfs_config::observability::ENV_OBS_LOG_DIRECTORY;
|
use rustfs_config::observability::ENV_OBS_LOG_DIRECTORY;
|
||||||
|
|||||||
@@ -2550,7 +2550,7 @@ impl DefaultBucketUsecase {
|
|||||||
Ok(S3Response::new(PutBucketVersioningOutput {}))
|
Ok(S3Response::new(PutBucketVersioningOutput {}))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "info", skip(self, req))]
|
#[instrument(level = "trace", skip(self, req))]
|
||||||
pub async fn execute_list_objects_v2(&self, req: S3Request<ListObjectsV2Input>) -> S3Result<S3Response<ListObjectsV2Output>> {
|
pub async fn execute_list_objects_v2(&self, req: S3Request<ListObjectsV2Input>) -> S3Result<S3Response<ListObjectsV2Output>> {
|
||||||
// warn!("list_objects_v2 req {:?}", &req.input);
|
// warn!("list_objects_v2 req {:?}", &req.input);
|
||||||
let ListObjectsV2Input {
|
let ListObjectsV2Input {
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ use http_body_util::{BodyExt, Full};
|
|||||||
use hyper::body::Incoming;
|
use hyper::body::Incoming;
|
||||||
use pin_project_lite::pin_project;
|
use pin_project_lite::pin_project;
|
||||||
use quick_xml::events::Event;
|
use quick_xml::events::Event;
|
||||||
|
use rustfs_obs::HTTP_SERVER_LOG_TARGET;
|
||||||
#[cfg(feature = "swift")]
|
#[cfg(feature = "swift")]
|
||||||
use rustfs_protocols::swift::SwiftRouter;
|
use rustfs_protocols::swift::SwiftRouter;
|
||||||
use rustfs_trusted_proxies::ClientInfo;
|
use rustfs_trusted_proxies::ClientInfo;
|
||||||
@@ -391,6 +392,7 @@ impl RequestLogContext {
|
|||||||
|
|
||||||
if status.is_server_error() {
|
if status.is_server_error() {
|
||||||
error!(
|
error!(
|
||||||
|
target: HTTP_SERVER_LOG_TARGET,
|
||||||
event = HTTP_REQUEST_COMPLETED_EVENT,
|
event = HTTP_REQUEST_COMPLETED_EVENT,
|
||||||
component = LOG_COMPONENT_SERVER,
|
component = LOG_COMPONENT_SERVER,
|
||||||
subsystem = LOG_SUBSYSTEM_HTTP,
|
subsystem = LOG_SUBSYSTEM_HTTP,
|
||||||
@@ -407,6 +409,7 @@ impl RequestLogContext {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
info!(
|
info!(
|
||||||
|
target: HTTP_SERVER_LOG_TARGET,
|
||||||
event = HTTP_REQUEST_COMPLETED_EVENT,
|
event = HTTP_REQUEST_COMPLETED_EVENT,
|
||||||
component = LOG_COMPONENT_SERVER,
|
component = LOG_COMPONENT_SERVER,
|
||||||
subsystem = LOG_SUBSYSTEM_HTTP,
|
subsystem = LOG_SUBSYSTEM_HTTP,
|
||||||
@@ -429,6 +432,7 @@ impl RequestLogContext {
|
|||||||
E: std::fmt::Display,
|
E: std::fmt::Display,
|
||||||
{
|
{
|
||||||
error!(
|
error!(
|
||||||
|
target: HTTP_SERVER_LOG_TARGET,
|
||||||
event = HTTP_REQUEST_FAILED_EVENT,
|
event = HTTP_REQUEST_FAILED_EVENT,
|
||||||
component = LOG_COMPONENT_SERVER,
|
component = LOG_COMPONENT_SERVER,
|
||||||
subsystem = LOG_SUBSYSTEM_HTTP,
|
subsystem = LOG_SUBSYSTEM_HTTP,
|
||||||
|
|||||||
@@ -875,6 +875,43 @@ if [[ "$erasure_sampled_sites" -lt 2 ]]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Object-read request fan-out crosses several thin wrappers. These spans are
|
||||||
|
# useful for opt-in latency attribution, but default INFO turns one S3 request
|
||||||
|
# into many redundant span-close records. Keep only the measured hot wrappers
|
||||||
|
# TRACE-only; write, heal, rebalance, and admin operations are intentionally not
|
||||||
|
# included here.
|
||||||
|
trace_hot_spans=(
|
||||||
|
"crates/ecstore/src/set_disk/ops/locking.rs:new_ns_lock"
|
||||||
|
"crates/ecstore/src/store/rebalance.rs:handle_new_ns_lock"
|
||||||
|
"crates/ecstore/src/store/object.rs:handle_get_object_info"
|
||||||
|
"crates/ecstore/src/set_disk/ops/object.rs:get_object_info"
|
||||||
|
"crates/ecstore/src/store/mod.rs:list_objects_v2"
|
||||||
|
"crates/ecstore/src/store/list.rs:handle_list_objects_v2"
|
||||||
|
"crates/ecstore/src/core/sets.rs:list_objects_v2"
|
||||||
|
"crates/ecstore/src/set_disk/ops/list.rs:list_objects_v2"
|
||||||
|
"rustfs/src/app/bucket_usecase.rs:execute_list_objects_v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
for hot_span in "${trace_hot_spans[@]}"; do
|
||||||
|
file="${hot_span%%:*}"
|
||||||
|
function="${hot_span##*:}"
|
||||||
|
trace_span_pattern="#\\[(tracing::)?instrument\\([^]]*level = \\\"trace\\\"[^]]*\\)\\]([[:space:]]+#\\[[^]]+\\])*[[:space:]]+(pub(\\([^)]*\\))?[[:space:]]+)?(super[[:space:]]+)?async fn ${function}\\b"
|
||||||
|
if ! rg -U "$trace_span_pattern" "$file" >/dev/null; then
|
||||||
|
echo "❌ logging guardrail violation: $file::$function must remain TRACE-only" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if ! rg -U 'info!\([[:space:]]+target: HTTP_SERVER_LOG_TARGET,[[:space:]]+event = HTTP_REQUEST_COMPLETED_EVENT' rustfs/src/server/layer.rs >/dev/null; then
|
||||||
|
echo "❌ logging guardrail violation: successful HTTP completion events must use HTTP_SERVER_LOG_TARGET" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if rg -n -F 'target: "rustfs::server::http"' rustfs/src/server/layer.rs >/dev/null; then
|
||||||
|
echo "❌ logging guardrail violation: HTTP request log target must use HTTP_SERVER_LOG_TARGET" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
demoted_admission_sites="$(rg -c -F 'demote_to_debug_when!(' crates/heal/src/heal/manager.rs || echo 0)"
|
demoted_admission_sites="$(rg -c -F 'demote_to_debug_when!(' crates/heal/src/heal/manager.rs || echo 0)"
|
||||||
if [[ "$demoted_admission_sites" -lt 6 ]]; then
|
if [[ "$demoted_admission_sites" -lt 6 ]]; then
|
||||||
echo "❌ logging guardrail violation: heal queue admission/scheduler warns for per-object requests must stay level-split via demote_to_debug_when! (expected >= 6 sites in crates/heal/src/heal/manager.rs, found $demoted_admission_sites)" >&2
|
echo "❌ logging guardrail violation: heal queue admission/scheduler warns for per-object requests must stay level-split via demote_to_debug_when! (expected >= 6 sites in crates/heal/src/heal/manager.rs, found $demoted_admission_sites)" >&2
|
||||||
|
|||||||
Reference in New Issue
Block a user