| Crates.io | moniof |
| lib.rs | moniof |
| version | 0.1.0 |
| created_at | 2025-12-11 13:00:38.948308+00 |
| updated_at | 2025-12-11 13:00:38.948308+00 |
| description | Actix middleware to monitor over-fetching and detect N+1 / overfetch database patterns (Mongo + SQL-agnostic) |
| homepage | https://github.com/srotas-space/moniof |
| repository | https://github.com/srotas-space/moniof |
| max_upload_size | |
| id | 1979606 |
| size | 151,021 |

moniof (Monitor Over Fetch) is an Actix Web middleware + instrumentation crate to:
Inspired by Ruby's bullet gem โ but built for Rust + Actix.
MoniOF)x-moniof-totalx-moniof-db-total-msx-moniof-elapsed-msx-moniof-slowest-keyx-moniof-n-plus-one-keyAdd to your app's Cargo.toml:
[dependencies]
moniof = { version = "0.1.0", features = ["mongodb", "sqlx"] }
actix-web = "4"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt", "registry"] }
mongodb = "2"
sqlx = { version = "0.8", features = ["postgres", "runtime-tokio-rustls"] }
pub use config::{MoniOFGlobalConfig, initiate, global};
pub use config::MoniOFConfig;
pub use services::http::MoniOF;
pub use observability::prom;
#[cfg(feature = "mongodb")]
pub use instrumentation::mongo_events::MOFMongoEvents;
#[cfg(feature = "sqlx")]
pub use instrumentation::sql_events::MOFSqlEvents;
Call once in main():
use moniof::{MoniOFGlobalConfig, initiate as moniof_initiate};
fn main() {
moniof_initiate(MoniOFGlobalConfig {
slack_webhook: None,
slow_db_threshold_ms: Some(0),
low_db_threshold_ms: Some(0),
log_each_db_event: true,
..Default::default()
});
// Start Actix...
}
This installs:
use moniof::MoniOF;
HttpServer::new(|| {
App::new()
.wrap(MoniOF::new())
})
Now each request produces:
Attach moniof's MongoDB handler:
use moniof::MOFMongoEvents;
use std::sync::Arc;
use mongodb::{Client, options::ClientOptions};
let mut opts = ClientOptions::parse(&mongo_uri).await?;
opts.command_event_handler = Some(Arc::new(MOFMongoEvents::default()));
let client = Client::with_options(opts)?;
let db = client.database("mydb");
Every find, insert, update is tracked.
If your crate enables:
features = ["sqlx"]
Then SQLx logs are automatically hooked.
Use SQLx normally:
let rows = sqlx::query!("SELECT id FROM users")
.fetch_all(pool)
.await?;
moniof will record:
and log:
moniof::sql: SQL completed key="select from users" latency_ms=2
Expose /metrics:
use moniof::prom;
HttpServer::new(|| {
App::new()
.service(prom::metrics())
})
Example metrics:
moniof_http_requests_total
moniof_http_request_duration_seconds
moniof_db_total_latency_seconds
moniof_mongo_command_duration_seconds
Enabled when slack_webhook is set:
slack_webhook: Some("https://hooks.slack.com/...".to_string())
Alert types:
x-moniof-total: 5
x-moniof-db-total-ms: 12
x-moniof-elapsed-ms: 18
x-moniof-slowest-key: users/find
x-moniof-n-plus-one-key: users/find
This project is licensed under the MIT License - see the LICENSE file for details.
Built with Actix Web - Fast, powerful web framework
Made with โค๏ธ by the [Srotas Space] (https://srotas.space/open-source)