Skip to content

Add global metrics prefix#7438

Merged
JojiiOfficial merged 7 commits intodevfrom
metrics-qdrant-prefix
Oct 30, 2025
Merged

Add global metrics prefix#7438
JojiiOfficial merged 7 commits intodevfrom
metrics-qdrant-prefix

Conversation

@JojiiOfficial
Copy link
Contributor

@JojiiOfficial JojiiOfficial commented Oct 22, 2025

According to the Prometheus naming convention:

A metric name SHOULD have a (single-word) application prefix relevant
to the domain the metric belongs to.

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

coderabbitai[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

@JojiiOfficial JojiiOfficial requested review from timvisee and removed request for timvisee October 22, 2025 12:45
coderabbitai[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

@qdrant qdrant deleted a comment from coderabbitai bot Oct 23, 2025
Copy link
Member

@timvisee timvisee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy once the review remarks are handled 👍

coderabbitai[bot]

This comment was marked as resolved.

@qdrant qdrant deleted a comment from coderabbitai bot Oct 24, 2025
@qdrant qdrant deleted a comment from coderabbitai bot Oct 24, 2025
coderabbitai[bot]

This comment was marked as resolved.

@qdrant qdrant deleted a comment from coderabbitai bot Oct 29, 2025
@JojiiOfficial JojiiOfficial changed the base branch from dev to metrics-procfs-stats October 29, 2025 16:09
Base automatically changed from metrics-procfs-stats to dev October 29, 2025 16:27
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
src/common/metrics.rs (2)

732-750: Centralize and sanitize prefix/name join to ensure exactly one underscore

Malformed 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_family and 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 default

Consider 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 consistency

Imports mix web::{Data, Query} with web::... usage. Prefer one style. Suggest using web::Data and web::Query everywhere 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 values

Defensive: 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

📥 Commits

Reviewing files that changed from the base of the PR and between 9a69e02 and 1d12399.

📒 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.rs
  • src/actix/api/service_api.rs
  • src/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.rs
  • src/actix/api/service_api.rs
  • src/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 straightforward

Construction defers to TelemetryData and keeps formatting separate.


107-110: LGTM: trait now accepts optional prefix and keeps API minimal

Signature change is clear and propagates well.


113-135: LGTM: consistent prefix forwarding across TelemetryData providers

Forwarding 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 correctly

Also applies to: 396-435

src/actix/api/service_api.rs (1)

67-74: ServiceConfig is correctly injected into the Actix app

Verification confirms that ServiceConfig is properly registered via app.app_data(service_config.clone()) at line 146 of src/actix/mod.rs, using the pattern web::Data::new(settings.service.clone()). The handler at src/actix/api/service_api.rs:71 will receive the injected dependency correctly.

Comment on lines +61 to +63
/// Global prefix for metrics.
#[serde(default)]
pub metrics_prefix: Option<String>,
Copy link
Contributor

@coderabbitai coderabbitai bot Oct 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think it'd be nice to add something like this. We can probably simplify it a bit:

Require one of:

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented in ddf1181

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 qdrant deleted a comment from coderabbitai bot Oct 29, 2025
@timvisee timvisee added the release:1.16.0 Pull requests that should be merged for the Qdrant 1.16.0 release. label Oct 29, 2025
@qdrant qdrant deleted a comment from coderabbitai bot Oct 30, 2025
@qdrant qdrant deleted a comment from coderabbitai bot Oct 30, 2025
@JojiiOfficial JojiiOfficial merged commit 5c0863a into dev Oct 30, 2025
15 checks passed
@JojiiOfficial JojiiOfficial deleted the metrics-qdrant-prefix branch October 30, 2025 10:37
timvisee pushed a commit that referenced this pull request Nov 14, 2025
* 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
@timvisee timvisee mentioned this pull request Nov 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release:1.16.0 Pull requests that should be merged for the Qdrant 1.16.0 release.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants