* test(targets): ship a builder MockTarget testkit and retire the in-crate Target mocks Adds crates/targets/src/testkit.rs with a builder-style MockTarget implementing Target<E> for every E: PluginEvent, with orthogonal off-by-default knobs: disabled/active override, health delay plus health-started signal plus a drop-guard counter proving a cancelled probe future was dropped, an init failure budget (usize::MAX = always fail) plus blocking init plus an init counter, a close counter/signal/semaphore gate with a runtime block toggle, a save counter plus save failure budget, caller-supplied store and failed-store handles, and a shared final-failure counter. Clones and clone_dyn share all counters, so an observer clone keeps watching a target after it is boxed into a runtime. The module is gated as #[cfg(any(test, feature = "test-support"))]: in-crate unit tests get it via cfg(test), and downstream test suites opt in through the new off-by-default test-support cargo feature (test-support = [], activating no dependencies). Migrates the five in-crate duplicate mocks onto it: the plugin.rs registry-factory TestTarget, the runtime/adapter.rs lifecycle TestTarget (init/close/store knobs), the runtime/mod.rs TestTarget plus HealthDropGuard (close gating and health-probe tests), the target/mod.rs MoveTestTarget (folded into the test_support helper constructors used by the NATS JetStream failed-store tests), and the target/mod.rs StoreBackedTarget (the default send_from_store purge test; the mock deliberately does not override send_from_store or handle_terminal_failure). The forced init failure now uses TargetError::Initialization instead of the old adapter mock's Configuration; the adapter derives its redacted failure summary from the target id alone, so the migrated assertions are unchanged. Leak guard: testkit unit tests assert the crate manifest still declares default = [] and that test-support = [] stays a pure cfg gate, complementing the compile-level cfg gate that keeps the mock out of production builds. Part of rustfs/backlog#1846 (cluster 3, step 1). * test(notify,audit): migrate the Target mocks onto the shared testkit Retires the hand-written Target mocks in crates/notify and crates/audit in favor of rustfs_targets::testkit::MockTarget: notify's notifier.rs TestTarget/DeferredTestTarget/ClosableTestTarget, lifecycle.rs BlockingInitTarget/RetryInitTarget (rebuilt as observed MockTarget templates cloned by their plugin-descriptor factories, sharing the init signal, close counter, and single-failure init budget across generations), runtime_view.rs TestTarget, runtime_facade.rs TestTarget, and audit's pipeline.rs MockTarget, system.rs TestTarget, registry.rs CloseTestTarget, plus TestTarget and FailingTarget in audit/tests/pipeline_layer_test.rs. Removing the two integration-test mocks also removes their respelled PluginEvent bound (E: Send + Sync + 'static + Clone + Serialize + DeserializeOwned), which the plugin-contract rules require to be spelled only via PluginEvent. lifecycle.rs ReplayTarget stays bespoke on purpose: its generation tags, mpsc observation channels, gated send_raw delivery, and ObservedQueueStore model the replay pipeline itself and would contort a general-purpose mock. The other bespoke mocks named out of scope in PR-3a (ProgrammedTarget, ClassifyingTarget, the ReloadableTargetTls fakes) are likewise untouched. New testkit knobs, each defaulted off and unit-tested: with_id (rename a clone while keeping the shared counters, for factory templates), with_first_save_gate (the first save notifies entered and waits on release; several mocks may share one pair), with_health_gate (is_active waits on a release handle after notifying health_started), with_delivery_snapshot (fixed snapshot overriding the store-derived default), with_close_failures (close-failure budget, default TargetError::Storage) with with_close_failure_error to shape the variant (audit's registry test pins TargetError::Unknown), and an always-on is_enabled call counter exposed as enabled_call_count (notifier's generation tests count dispatcher selections through it). Both crates enable the testkit through a dev-dependency on rustfs-targets with the test-support feature; the feature stays out of default and activates no dependencies, so production builds are unchanged. Part of rustfs/backlog#1846 (cluster 3, step 2).
rustfs-audit
Audit Target Management System for RustFS
rustfs-audit is a comprehensive audit logging system designed for RustFS. It provides multi-target fan-out, hot reload
capabilities, and rich observability features for distributed storage and event-driven systems.
Features
- Multi-Target Fan-Out: Dispatch audit logs to multiple targets (e.g., Webhook, MQTT) concurrently.
- Hot Reload: Dynamically reload configuration and update targets without downtime.
- Observability: Collect metrics such as EPS (Events Per Second), average latency, error rate, and target success rate.
- Performance Validation: Validate system performance against requirements and receive optimization recommendations.
- Extensible Registry: Manage audit targets with add, remove, enable, disable, and upsert operations.
- Global Singleton: Easy-to-use global audit system and logger.
- Async & Thread-Safe: Built on Tokio and Rust async primitives for high concurrency.
Getting Started
Add Dependency
Add to your Cargo.toml:
[dependencies]
rustfs-audit = "0.1"
Basic Usage
Initialize and Start Audit System
use rustfs_audit::{start_audit_system, AuditLogger};
use rustfs_config::server_config::Config;
#[tokio::main]
async fn main() {
let config = Config::load("path/to/config.toml").await.unwrap();
start_audit_system(config).await.unwrap();
}
Log an Audit Entry
use rustfs_audit::{AuditEntry, AuditLogger, ApiDetails};
use chrono::Utc;
use rustfs_targets::EventName;
let entry = AuditEntry::new(
"v1".to_string(),
Some("deployment-123".to_string()),
Some("siteA".to_string()),
Utc::now(),
EventName::ObjectCreatedPut,
Some("type".to_string()),
"trigger".to_string(),
ApiDetails::default (),
);
AuditLogger::log(entry).await;
Observability & Metrics
use rustfs_audit::{get_metrics_report, validate_performance};
let report = get_metrics_report().await;
println!("{}", report.format());
let validation = validate_performance().await;
println!("{}", validation.format());
Configuration
Targets are configured via TOML files and environment variables. Supported target types:
- Webhook
- MQTT
Environment variables override file configuration. See docs.rs/rustfs-audit for details.
API Overview
AuditSystem: Main system for managing targets and dispatching logs.AuditRegistry: Registry for audit targets.AuditEntry: Audit log entry structure.ApiDetails: API call details for audit logs.AuditLogger: Global logger singleton.AuditMetrics,AuditMetricsReport: Metrics and reporting.PerformanceValidation: Performance validation and recommendations.
Observability
- Metrics: EPS, average latency, error rate, target success rate, processed/failed events, config reloads, system starts.
- Validation: Checks if EPS ≥ 3000, latency ≤ 30ms, error rate ≤ 1%. Provides actionable recommendations.
Contributing
Issues and PRs are welcome!
See docs.rs/rustfs-audit for detailed developer documentation.
License
Apache License 2.0
Documentation
For detailed API documentation, refer to source code comments and docs.rs documentation.
Note:
This crate is designed for use within the RustFS ecosystem and may depend on other RustFS crates such as
rustfs-targets, rustfs-config, and rustfs-ecstore.
For integration examples and advanced usage, see the docs.rs
documentation.