Skip to content

Commit 202572a

Browse files
authored
Merge pull request #3 from msalinas92/feature/prometheus-metrics
feat: prometheus-metrics
2 parents fa25e56 + 194d9f3 commit 202572a

File tree

6 files changed

+222
-21
lines changed

6 files changed

+222
-21
lines changed

Cargo.lock

Lines changed: 101 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,14 @@ hex = "0.4.3"
5252
bincode = "2.0.1"
5353
base64 = "0.22.1"
5454
regex = "1.11.1"
55+
metrics = "0.24.2"
56+
metrics-macros = "0.7.1"
57+
metrics-exporter-prometheus = "0.17.0"
5558

5659

5760
[dev-dependencies]
5861
tokio = { version = "1", features = ["macros", "rt-multi-thread", "test-util"] }
5962
ctor = "0.2"
6063
tempfile = "3"
6164
http-body-util = "0.1"
62-
http = "0.2"
65+
http = "0.2"

README.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,62 @@ See `.github/workflows/release.yml` for cross-target examples.
191191

192192
---
193193

194+
## 📊 Prometheus Metrics
195+
196+
CacheBolt exposes Prometheus-compatible metrics at the `/metrics` endpoint on port `3000`. These metrics allow you to monitor request flow, latency thresholds, memory caching, and backend persistence.
197+
198+
### Request Metrics
199+
200+
- `cachebolt_proxy_requests_total{uri}`
201+
Total number of proxy requests received, labeled by URI.
202+
203+
- `cachebolt_downstream_failures_total{uri}`
204+
Count of downstream request failures per URI.
205+
206+
- `cachebolt_rejected_due_to_concurrency_total{uri}`
207+
Requests rejected due to max concurrency being exceeded.
208+
209+
- `cachebolt_failover_total{uri}`
210+
Requests served via failover mode due to recent high latency.
211+
212+
### In-Memory Cache Metrics
213+
214+
- `cachebolt_memory_hits_total{uri}`
215+
Requests served directly from the in-memory cache.
216+
217+
- `cachebolt_memory_store_total{uri}`
218+
Responses stored into the in-memory cache.
219+
220+
- `cachebolt_memory_fallback_hits_total`
221+
Failover-mode requests served from memory cache.
222+
223+
### Latency Monitoring
224+
225+
- `cachebolt_proxy_request_latency_ms{uri}`
226+
Histogram of proxy request latency in milliseconds.
227+
228+
- `cachebolt_latency_exceeded_ms{uri}`
229+
Histogram of requests whose latency exceeded the configured threshold.
230+
231+
- `cachebolt_latency_exceeded_total{uri}`
232+
Count of latency threshold violations per URI.
233+
234+
### Persistent Storage Metrics
235+
236+
- `cachebolt_persist_attempts_total{backend}`
237+
Number of attempts to persist cache entries into the selected backend.
238+
239+
- `cachebolt_persist_errors_total{backend}`
240+
Number of failed attempts to persist cache entries.
241+
242+
- `cachebolt_persistent_fallback_hits_total`
243+
Requests served from persistent storage (GCS, S3, Azure, or local) during failover.
244+
245+
- `cachebolt_fallback_miss_total`
246+
Count of failover attempts that missed both memory and persistent storage.
247+
248+
---
249+
194250
## 📄 License
195251

196252
Licensed under the [Apache License 2.0](./LICENSE).

config.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,5 @@ latency_failover:
2222
max_latency_ms: 100
2323

2424
ignored_headers:
25-
- postman-token
25+
- postman-token
26+
- if-none-match

src/main.rs

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,30 +17,31 @@
1717
// ----------------------
1818
// These are internal modules for handling the proxy logic, caching layers,
1919
// configuration loading, and in-memory eviction based on memory pressure.
20-
mod proxy;
21-
mod storage;
22-
mod memory;
2320
mod config;
2421
mod eviction;
22+
mod memory;
23+
mod proxy;
2524
mod rules;
25+
mod storage;
2626

2727
// ----------------------
2828
// External dependencies
2929
// ----------------------
30-
use axum::{routing::get, Router}; // Axum: Web framework for routing and request handling
31-
use hyper::Server; // Hyper: High-performance HTTP server
32-
use std::{net::SocketAddr, process::exit}; // Network + system utilities
30+
use axum::{Router, routing::get}; // Axum: Web framework for routing and request handling
31+
use hyper::Server; // Hyper: High-performance HTTP server
32+
use std::{net::SocketAddr, process::exit}; // Network + system utilities
3333

34-
use clap::Parser; // CLI argument parsing (via `--config`)
35-
use tracing::{info, warn, error}; // Structured logging macros
36-
use tracing_subscriber::EnvFilter; // Log filtering via LOG_LEVEL
34+
use clap::Parser; // CLI argument parsing (via `--config`)
35+
use tracing::{error, info, warn}; // Structured logging macros
36+
use tracing_subscriber::EnvFilter; // Log filtering via LOG_LEVEL
3737

3838
// ----------------------
3939
// Internal dependencies
4040
// ----------------------
41-
use crate::config::{Config, CONFIG, StorageBackend}; // App-wide config definitions
42-
use crate::eviction::start_background_eviction_task; // Memory pressure eviction
43-
use crate::storage::{gcs, s3, azure}; // Persistent storage backends
41+
use crate::config::{CONFIG, Config, StorageBackend}; // App-wide config definitions
42+
use crate::eviction::start_background_eviction_task; // Memory pressure eviction
43+
use crate::storage::{azure, gcs, s3}; // Persistent storage backends
44+
use metrics_exporter_prometheus::PrometheusBuilder;
4445

4546
/// ----------------------------
4647
/// CLI ARGUMENT STRUCTURE
@@ -79,9 +80,9 @@ fn init_logging(app_id: &str) {
7980
.unwrap_or_else(|_| EnvFilter::new("info"));
8081

8182
tracing_subscriber::fmt()
82-
.with_env_filter(filter) // Uses LOG_LEVEL to filter verbosity
83-
.with_target(false) // Hides the module path in each log line
84-
.compact() // Compact single-line logs (less verbose)
83+
.with_env_filter(filter) // Uses LOG_LEVEL to filter verbosity
84+
.with_target(false) // Hides the module path in each log line
85+
.compact() // Compact single-line logs (less verbose)
8586
.init();
8687

8788
info!("🚀 Logging initialized for app_id: {app_id}");
@@ -159,11 +160,17 @@ async fn main() {
159160
// 3. Initialize the logger using app_id for context
160161
// ------------------------------------------------------
161162
init_logging(&config.app_id);
163+
let builder = PrometheusBuilder::new();
164+
let handle = builder
165+
.install_recorder()
166+
.expect("❌ Failed to install Prometheus recorder");
162167

163168
// ------------------------------------------------------
164169
// 4. Set global CONFIG (OnceCell) for use across modules
165170
// ------------------------------------------------------
166-
CONFIG.set(config).expect("❌ CONFIG was already initialized");
171+
CONFIG
172+
.set(config)
173+
.expect("❌ CONFIG was already initialized");
167174

168175
// ------------------------------------------------------
169176
// 5. Initialize persistent storage backend (GCS, S3, Azure, Local)
@@ -181,7 +188,9 @@ async fn main() {
181188
// 7. Define Axum router with a single wildcard route
182189
// All incoming GET requests will be handled by the proxy logic.
183190
// ------------------------------------------------------
184-
let app = Router::new().route("/*path", get(proxy::proxy_handler));
191+
let app = Router::new()
192+
.route("/metrics", get(move || async move { handle.render() }))
193+
.route("/*path", get(proxy::proxy_handler));
185194

186195
// ------------------------------------------------------
187196
// 8. Bind the server to all interfaces on port 3000
@@ -196,4 +205,4 @@ async fn main() {
196205
.serve(app.into_make_service())
197206
.await
198207
.unwrap();
199-
}
208+
}

0 commit comments

Comments
 (0)