1
0
Fork 0
mirror of https://github.com/dani-garcia/vaultwarden.git synced 2025-08-25 04:03:19 +00:00

fix: Resolve compilation errors and improve Docker build for metrics

- Fix Rocket response type issues in metrics endpoint
- Correct middleware request timer handling
- Resolve borrow checker issues with UUID string conversion
- Add proper EXTRA_FEATURES support to Dockerfile for optional features
- Suppress unused code warnings in proof-of-concept metrics implementation
- Update Cargo.lock with resolved dependencies

These fixes enable successful compilation of the metrics feature and
production-ready Docker image building with:
docker build --build-arg EXTRA_FEATURES="enable_metrics"

The metrics-enabled image has been successfully built and tested.
This commit is contained in:
Ross Golder 2025-08-17 15:07:52 +07:00
commit 8fac5f5060
No known key found for this signature in database
GPG key ID: 253A7E508D2D59CD
6 changed files with 54 additions and 78 deletions

58
Cargo.lock generated
View file

@ -223,7 +223,7 @@ dependencies = [
"futures-lite",
"parking",
"polling",
"rustix 1.0.8",
"rustix",
"slab",
"windows-sys 0.60.2",
]
@ -254,7 +254,7 @@ dependencies = [
"cfg-if",
"event-listener 5.4.1",
"futures-lite",
"rustix 1.0.8",
"rustix",
]
[[package]]
@ -269,7 +269,7 @@ dependencies = [
"cfg-if",
"futures-core",
"futures-io",
"rustix 1.0.8",
"rustix",
"signal-hook-registry",
"slab",
"windows-sys 0.60.2",
@ -2803,12 +2803,6 @@ dependencies = [
"vcpkg",
]
[[package]]
name = "linux-raw-sys"
version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
[[package]]
name = "linux-raw-sys"
version = "0.9.4"
@ -3712,7 +3706,7 @@ dependencies = [
"concurrent-queue",
"hermit-abi",
"pin-project-lite",
"rustix 1.0.8",
"rustix",
"windows-sys 0.60.2",
]
@ -3787,29 +3781,6 @@ dependencies = [
"yansi",
]
[[package]]
name = "procfs"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "731e0d9356b0c25f16f33b5be79b1c57b562f141ebfcdb0ad8ac2c13a24293b4"
dependencies = [
"bitflags",
"hex",
"lazy_static",
"procfs-core",
"rustix 0.38.44",
]
[[package]]
name = "procfs-core"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29"
dependencies = [
"bitflags",
"hex",
]
[[package]]
name = "prometheus"
version = "0.13.4"
@ -3819,10 +3790,8 @@ dependencies = [
"cfg-if",
"fnv",
"lazy_static",
"libc",
"memchr",
"parking_lot",
"procfs",
"thiserror 1.0.69",
]
@ -4451,19 +4420,6 @@ dependencies = [
"nom 7.1.3",
]
[[package]]
name = "rustix"
version = "0.38.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys 0.4.15",
"windows-sys 0.59.0",
]
[[package]]
name = "rustix"
version = "1.0.8"
@ -4473,7 +4429,7 @@ dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys 0.9.4",
"linux-raw-sys",
"windows-sys 0.60.2",
]
@ -5151,7 +5107,7 @@ dependencies = [
"fastrand",
"getrandom 0.3.3",
"once_cell",
"rustix 1.0.8",
"rustix",
"windows-sys 0.59.0",
]
@ -6038,7 +5994,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3fabb953106c3c8eea8306e4393700d7657561cb43122571b172bbfb7c7ba1d"
dependencies = [
"env_home",
"rustix 1.0.8",
"rustix",
"winsafe",
]

View file

@ -118,12 +118,17 @@ ARG CARGO_PROFILE=release
# Configure the DB ARG as late as possible to not invalidate the cached layers above
ARG DB=sqlite,mysql,postgresql
ARG EXTRA_FEATURES=""
# Builds your dependencies and removes the
# dummy project, except the target folder
# This folder contains the compiled dependencies
RUN source /env-cargo && \
cargo build --features ${DB} --profile "${CARGO_PROFILE}" --target="${CARGO_TARGET}" && \
if [ -n "${EXTRA_FEATURES}" ]; then \
cargo build --features "${DB},${EXTRA_FEATURES}" --profile "${CARGO_PROFILE}" --target="${CARGO_TARGET}"; \
else \
cargo build --features "${DB}" --profile "${CARGO_PROFILE}" --target="${CARGO_TARGET}"; \
fi && \
find . -not -path "./target*" -delete
# Copies the complete project
@ -138,7 +143,11 @@ RUN source /env-cargo && \
# Also do this for build.rs to ensure the version is rechecked
touch build.rs src/main.rs && \
# Create a symlink to the binary target folder to easy copy the binary in the final stage
cargo build --features ${DB} --profile "${CARGO_PROFILE}" --target="${CARGO_TARGET}" && \
if [ -n "${EXTRA_FEATURES}" ]; then \
cargo build --features "${DB},${EXTRA_FEATURES}" --profile "${CARGO_PROFILE}" --target="${CARGO_TARGET}"; \
else \
cargo build --features "${DB}" --profile "${CARGO_PROFILE}" --target="${CARGO_TARGET}"; \
fi && \
if [[ "${CARGO_PROFILE}" == "dev" ]] ; then \
ln -vfsr "/app/target/${CARGO_TARGET}/debug" /app/target/final ; \
else \

View file

@ -1,17 +1,20 @@
#![allow(dead_code, unused_imports)]
use rocket::{
http::{ContentType, Status},
request::{FromRequest, Outcome, Request},
response::{Content, Result},
response::{self, content::RawText},
Route,
};
use crate::{
auth::ClientIp,
db::DbConn,
error::Error,
CONFIG,
};
use log::error;
// Metrics endpoint routes
pub fn routes() -> Vec<Route> {
if CONFIG.enable_metrics() {
@ -46,7 +49,11 @@ impl<'r> FromRequest<'r> for MetricsToken {
.headers()
.get_one("Authorization")
.and_then(|auth| auth.strip_prefix("Bearer "))
.or_else(|| request.query_value::<&str>("token").and_then(Result::ok));
.or_else(|| {
request
.query_value::<&str>("token")
.and_then(|result| result.ok())
});
match provided_token {
Some(token) => {
@ -84,7 +91,7 @@ fn validate_metrics_token(provided: &str, configured: &str) -> bool {
/// Prometheus metrics endpoint
#[get("/")]
async fn get_metrics(_token: MetricsToken, mut conn: DbConn) -> Result<Content<String>, Status> {
async fn get_metrics(_token: MetricsToken, mut conn: DbConn) -> Result<RawText<String>, Status> {
// Update business metrics from database
if let Err(e) = crate::metrics::update_business_metrics(&mut conn).await {
error!("Failed to update business metrics: {e}");
@ -93,7 +100,7 @@ async fn get_metrics(_token: MetricsToken, mut conn: DbConn) -> Result<Content<S
// Gather all Prometheus metrics
match crate::metrics::gather_metrics() {
Ok(metrics) => Ok(Content(ContentType::Plain, metrics)),
Ok(metrics) => Ok(RawText(metrics)),
Err(e) => {
error!("Failed to gather metrics: {e}");
Err(Status::InternalServerError)
@ -103,7 +110,7 @@ async fn get_metrics(_token: MetricsToken, mut conn: DbConn) -> Result<Content<S
/// Health check endpoint that also updates some basic metrics
#[cfg(feature = "enable_metrics")]
pub async fn update_health_metrics(conn: &mut DbConn) -> Result<(), Error> {
pub async fn update_health_metrics(_conn: &mut DbConn) {
// Update basic system metrics
use std::time::SystemTime;
static START_TIME: std::sync::OnceLock<SystemTime> = std::sync::OnceLock::new();
@ -114,11 +121,7 @@ pub async fn update_health_metrics(conn: &mut DbConn) -> Result<(), Error> {
// Update database connection metrics
// Note: This is a simplified version - in production you'd want to get actual pool stats
crate::metrics::update_db_connections("main", 1, 0);
Ok(())
}
#[cfg(not(feature = "enable_metrics"))]
pub async fn update_health_metrics(_conn: &mut DbConn) -> Result<(), Error> {
Ok(())
}
pub async fn update_health_metrics(_conn: &mut DbConn) {}

View file

@ -1,7 +1,6 @@
/// Metrics middleware for automatic HTTP request instrumentation
use rocket::{
fairing::{Fairing, Info, Kind},
http::Method,
Data, Request, Response,
};
use std::time::Instant;
@ -24,16 +23,15 @@ impl Fairing for MetricsFairing {
}
async fn on_response<'r>(&self, req: &'r Request<'_>, res: &mut Response<'r>) {
if let Some(timer) = req.local_cache(|| RequestTimer { start_time: Instant::now() }) {
let duration = timer.start_time.elapsed();
let method = req.method().as_str();
let path = normalize_path(req.uri().path().as_str());
let status = res.status().code;
let timer = req.local_cache(|| RequestTimer { start_time: Instant::now() });
let duration = timer.start_time.elapsed();
let method = req.method().as_str();
let path = normalize_path(req.uri().path().as_str());
let status = res.status().code;
// Record metrics
crate::metrics::increment_http_requests(method, &path, status);
crate::metrics::observe_http_request_duration(method, &path, duration.as_secs_f64());
}
// Record metrics
crate::metrics::increment_http_requests(method, &path, status);
crate::metrics::observe_http_request_duration(method, &path, duration.as_secs_f64());
}
}

View file

@ -1,4 +1,6 @@
#![allow(dead_code, unused_imports)]
/// Database metrics collection utilities
use std::time::Instant;
/// Database operation tracker for metrics
@ -38,7 +40,7 @@ macro_rules! db_metric {
}
/// Track database connection pool statistics
pub async fn update_pool_metrics(pool: &crate::db::DbPool) {
pub async fn update_pool_metrics(_pool: &crate::db::DbPool) {
#[cfg(feature = "enable_metrics")]
{
// Note: This is a simplified implementation

View file

@ -1,9 +1,11 @@
#![allow(dead_code, unused_imports)]
#[cfg(feature = "enable_metrics")]
use once_cell::sync::Lazy;
#[cfg(feature = "enable_metrics")]
use prometheus::{
register_counter_vec, register_gauge_vec, register_histogram_vec, register_int_counter_vec, register_int_gauge_vec,
CounterVec, Encoder, GaugeVec, HistogramVec, IntCounterVec, IntGaugeVec, TextEncoder,
register_gauge_vec, register_histogram_vec, register_int_counter_vec, register_int_gauge_vec,
Encoder, GaugeVec, HistogramVec, IntCounterVec, IntGaugeVec, TextEncoder,
};
#[cfg(feature = "enable_metrics")]
@ -198,7 +200,13 @@ pub async fn update_business_metrics(conn: &mut DbConn) -> Result<(), crate::err
4 => "identity",
_ => "unknown",
};
let org_label = cipher.organization_uuid.as_ref().map(|id| id.as_str()).unwrap_or("personal");
let org_id_string;
let org_label = if let Some(id) = &cipher.organization_uuid {
org_id_string = id.to_string();
&org_id_string
} else {
"personal"
};
VAULT_ITEMS_TOTAL.with_label_values(&[cipher_type, org_label]).inc();
}
}