Conversation
ec0dc0a to
4c3355f
Compare
9a53331 to
34c1c7e
Compare
34c1c7e to
e1c051a
Compare
timvisee
left a comment
There was a problem hiding this comment.
Happy once the review remarks are handled 👍
8ca1fca to
6e29f6f
Compare
6aad96e to
06e7cc2
Compare
06e7cc2 to
52c692e
Compare
52c692e to
1d12399
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (2)
src/common/metrics.rs (2)
732-750: Centralize and sanitize prefix/name join to ensure exactly one underscoreMalformed names occur when:
- global prefix present but user omits trailing
_- global prefix absent (local
"rest"/"grpc"missing separator)- user sets
metrics_prefix = "qdrant"(no_)Normalize here so all call sites are correct:
- let name_with_prefix = prefix - .map(|prefix| format!("{prefix}{name}")) - .unwrap_or_else(|| name.to_string()); + let name_with_prefix = match prefix { + Some(p) if !p.is_empty() => { + let p = p.trim(); + if p.ends_with('_') || name.starts_with('_') { + format!("{p}{name}") + } else { + format!("{p}_{name}") + } + } + _ => name.to_string(), + };This yields
qdrant_app_info,qdrant_rest_responses_total, and handles a user-provided"qdrant"or"qdrant_"identically.
669-675: Prefix composition misses underscore when global_prefix is None
unwrap_or_else(|| prefix.to_string())produces "restresponses_total". Normalize prefix joining centrally (see next comment) and avoid hardcoding underscores here.Option A (prefer): Delegate underscore insertion to
metric_familyand stop adding a trailing_here.- let prefix = global_prefix - .map(|global_prefix| format!("{global_prefix}{prefix}_")) - .unwrap_or_else(|| prefix.to_string()); + let prefix = global_prefix + .map(|global_prefix| format!("{global_prefix}{prefix}")) + .unwrap_or_else(|| prefix.to_string());Option B: If you keep local handling, ensure the None branch also adds
_:- .unwrap_or_else(|| prefix.to_string()); + .unwrap_or_else(|| format!("{prefix}_"));
🧹 Nitpick comments (3)
config/config.yaml (1)
300-304: Good: option is documented and disabled by defaultConsider clarifying allowed characters and underscore behavior to reduce user error.
Suggested wording:
# Prefix for metric names in /metrics. Must match ^[a-zA-Z_:][a-zA-Z0-9_:]*$. # If it doesn't end with '_', one will be inserted automatically. # Recommended: "qdrant_" # metrics_prefix: qdrant_src/actix/api/service_api.rs (2)
7-8: Unify actix-web import style for consistencyImports mix
web::{Data, Query}withweb::...usage. Prefer one style. Suggest usingweb::Dataandweb::Queryeverywhere to match the rest of the file.-use actix_web::web::{Data, Query}; +// use web::Data and web::Query consistently via the `web` module // ... -async fn metrics( - telemetry_collector: web::Data<Mutex<TelemetryCollector>>, - params: Query<MetricsParam>, - config: Data<ServiceConfig>, +async fn metrics( + telemetry_collector: web::Data<Mutex<TelemetryCollector>>, + params: web::Query<MetricsParam>, + config: web::Data<ServiceConfig>, ActixAccess(access): ActixAccess, ) -> HttpResponse {Also applies to: 69-74
95-99: Trim and ignore empty metrics_prefix valuesDefensive: treat whitespace-only strings as unset to avoid odd names like " _app_info".
- let metrics_prefix = config.metrics_prefix.as_deref(); + let metrics_prefix = config + .metrics_prefix + .as_deref() + .map(str::trim) + .filter(|s| !s.is_empty());
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
config/config.yaml(1 hunks)src/actix/api/service_api.rs(4 hunks)src/common/metrics.rs(13 hunks)src/settings.rs(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs
📄 CodeRabbit inference engine (.github/review-rules.md)
**/*.rs: Prefer explicit SomeType::from(x) over implicit x.into() in Rust code
Do not use transmute_from_u8, transmute_to_u8, transmute_from_u8_to_slice, transmute_from_u8_to_mut_slice, transmute_to_u8_slice in new code; use bytemuck or zerocopy instead
Files:
src/settings.rssrc/actix/api/service_api.rssrc/common/metrics.rs
**/src/**/*.rs
📄 CodeRabbit inference engine (.github/review-rules.md)
**/src/**/*.rs: Prefer exhaustive match arms over a catch-all _ arm to avoid missing new enum variants (except in tests/benchmarks or when provably safe)
Prefer explicit field ignoring with : _ over .. in struct patterns (except in tests/benchmarks or when provably safe)
Files:
src/settings.rssrc/actix/api/service_api.rssrc/common/metrics.rs
🧬 Code graph analysis (2)
src/actix/api/service_api.rs (1)
src/common/metrics.rs (1)
new_from_telemetry(100-104)
src/common/metrics.rs (1)
src/actix/api/service_api.rs (1)
metrics(68-100)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
- GitHub Check: test-consensus-compose
- GitHub Check: test-shard-snapshot-api-s3-minio
- GitHub Check: rust-tests (macos-latest)
- GitHub Check: test-consistency
- GitHub Check: e2e-tests
- GitHub Check: rust-tests (ubuntu-latest)
- GitHub Check: rust-tests (windows-latest)
- GitHub Check: rust-tests-no-rocksdb (ubuntu-latest)
- GitHub Check: integration-tests-consensus
- GitHub Check: integration-tests
- GitHub Check: lint
🔇 Additional comments (11)
src/common/metrics.rs (10)
99-104: LGTM: prefix-aware constructor is straightforwardConstruction defers to TelemetryData and keeps formatting separate.
107-110: LGTM: trait now accepts optional prefix and keeps API minimalSignature change is clear and propagates well.
113-135: LGTM: consistent prefix forwarding across TelemetryData providersForwarding is uniform and guarded where needed.
138-153: LGTM: app_info family respects prefix and forwards to features
155-165: LGTM: app_status_recovery_mode family wired with prefix
168-176: LGTM: collections_total family includes prefix
446-469: LGTM: REST response metrics use builder with per-scope prefix
473-486: LGTM: gRPC response metrics parallel the REST implementation
856-919: LGTM: procfs metrics now honor prefix consistently
381-388: LGTM: cluster metrics families prefixed and composed correctlyAlso applies to: 396-435
src/actix/api/service_api.rs (1)
67-74: ServiceConfig is correctly injected into the Actix appVerification confirms that
ServiceConfigis properly registered viaapp.app_data(service_config.clone())at line 146 ofsrc/actix/mod.rs, using the patternweb::Data::new(settings.service.clone()). The handler atsrc/actix/api/service_api.rs:71will receive the injected dependency correctly.
| /// Global prefix for metrics. | ||
| #[serde(default)] | ||
| pub metrics_prefix: Option<String>, |
There was a problem hiding this comment.
Validate user-supplied metrics_prefix to prevent invalid Prometheus names
As-is, a value like "123" or "bad space" would yield invalid metric names (Prometheus requires [a-zA-Z_:][a-zA-Z0-9_:]*). Add a custom validator to reject empty/invalid prefixes early.
Apply on-field validator:
- #[serde(default)]
- pub metrics_prefix: Option<String>,
+ /// Global prefix for metrics. Must match Prometheus metric name charset:
+ /// ^[a-zA-Z_:][a-zA-Z0-9_:]*$
+ #[serde(default)]
+ #[validate(custom = "validate_metrics_prefix")]
+ pub metrics_prefix: Option<String>,Add the validator (anywhere in this module, e.g., below defaults):
fn validate_metrics_prefix(v: &Option<String>) -> Result<(), validator::ValidationError> {
if let Some(p) = v {
if p.is_empty() {
return Err(validator::ValidationError::new("empty_metrics_prefix"));
}
let mut chars = p.chars();
if let Some(first) = chars.next() {
let is_first_ok = first.is_ascii_alphabetic() || first == '_' || first == ':';
if !is_first_ok {
return Err(validator::ValidationError::new("invalid_metrics_prefix_start"));
}
}
if !chars.all(|c| c.is_ascii_alphanumeric() || c == '_' || c == ':') {
return Err(validator::ValidationError::new("invalid_metrics_prefix_chars"));
}
}
Ok(())
}🤖 Prompt for AI Agents
In src/settings.rs around lines 61 to 63, the metrics_prefix field lacks
validation allowing values that produce invalid Prometheus metric names; add a
custom validator function (e.g., validate_metrics_prefix) in this module that
checks Option<String> for non-empty value, verifies the first char is A-Z a-z
'_' or ':' and all subsequent chars are A-Z a-z 0-9 '_' or ':' and returns
appropriate validator::ValidationError variants on failure, then apply it to the
field with the serde/validator on-field attribute (e.g., #[validate(custom =
"validate_metrics_prefix")]) so invalid prefixes are rejected at config
validation time.
There was a problem hiding this comment.
Yes, I think it'd be nice to add something like this. We can probably simplify it a bit:
Require one of:
- empty string
- a string with
- all chars
is_ascii_alphanumericor'_'
- all chars
If this validation fails in configuration, Qdrant will only print a warning on startup and will still continue. I actually think that is desired behavior in this case. In the end the user is responsible for configuring it correctly.
There was a problem hiding this comment.
Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!
* Qdrant prefix for metrics * Update metrics tests * Update openapi docs * Make prefix configurable * don't enable metrics prefix by default * Adjust tests and openapi specs * Custom validation for metrics_prefix setting
According to the Prometheus naming convention:
This PR adds the
qdrant_prefix to all metrics to align with this convention. This prefix can be configured in the config file.Note, this is potentially breaking and might need discussion before merging