Skip to content

Bulk api label filtering for experiment type container only#1918

Open
pinkygupta-hub wants to merge 13 commits into
kruize:mvp_demofrom
pinkygupta-hub:bulk-api-label-filtering
Open

Bulk api label filtering for experiment type container only#1918
pinkygupta-hub wants to merge 13 commits into
kruize:mvp_demofrom
pinkygupta-hub:bulk-api-label-filtering

Conversation

@pinkygupta-hub
Copy link
Copy Markdown
Contributor

@pinkygupta-hub pinkygupta-hub commented May 15, 2026

Description

Implement namespace and pod label selector filtering support in Bulk API resource selection and experiment creation flow. The implementation should ensure that experiments are created only for resources matching the provided labels for experiment type container only.

Namespace label selector filtering implemented

Pod label selector filtering implemented

Label-aware metadata retrieval integrated into Bulk API flow

Type of change

  • Bug fix
  • New feature
  • Docs update
  • Breaking change (What changes might users need to make in their application due to this PR?)
  • Requires DB changes

How has this been tested?

Manually tested - will raise separate PR for test cases

Test Configuration

  • Kubernetes clusters tested on: kind

Checklist 🎯

  • Followed coding guidelines
  • Comments added
  • Dependent changes merged
  • Documentation updated
  • Tests added or updated

Additional information

Include any additional information such as links, test results, screenshots here

Summary by Sourcery

Introduce label-based filtering support into bulk metadata retrieval and document the design and usage for Bulk API label filtering.

New Features:

  • Support label-based namespace and workload matching when building data source metadata for bulk operations.
  • Allow bulk jobs to construct resource filters from user-provided labels, including pod and namespace label filters.

Enhancements:

  • Filter the constructed metadata hierarchy (namespaces and workloads) to retain only objects that match the computed label-based filters.
  • Simplify and generalize bulk job resource filter construction by reusing a common builder for namespace, workload, container, and label filters.

Documentation:

  • Add a simple implementation guide for Bulk API label filtering usage and flow.
  • Add a Kubernetes label types guide explaining which labels are applicable for Bulk API filtering.
  • Add an architectural decision record describing the optimized label-filtering strategy for Bulk API metadata queries.

Summary by Sourcery

Add label-based namespace and pod filtering to the bulk metadata and experiment creation flow so that only matching container workloads are selected for experiments.

New Features:

  • Support namespace and pod label selectors in bulk metadata queries, driven by user-provided label filters.
  • Allow Bulk API filters to accept arbitrary Kubernetes label keys and multiple label values for matching workloads and namespaces.
  • Introduce metadata-profile-driven queries to fetch namespaces and workloads matching label-based filters.

Enhancements:

  • Apply label-based filtering ahead of full metadata retrieval and then prune the constructed metadata tree to keep only matched namespaces and workloads.
  • Improve robustness of metadata updates by creating missing namespaces/workloads discovered via label-based queries.
  • Refine experiment naming to use sanitized include-label values without affecting filtering behavior.
  • Harden PromQL query construction by escaping label values and centralizing resource and label filter building logic.
  • Extend metadata profile helper to safely lookup queries and log missing or misconfigured metrics.

Documentation:

  • Add label-filtering query definitions for namespaces and workloads to the local monitoring bulk metadata profile.

Pinky Gupta and others added 2 commits May 14, 2026 12:41
Signed-off-by: Pinky Gupta <pinkygupta@Pinkys-MacBook-Pro.local>
@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented May 15, 2026

Reviewer's Guide

Implements label-based namespace and pod filtering for bulk metadata retrieval and experiment creation, wiring Bulk API label filters through to Prometheus queries and post-processing so that only matching resources (for experiment type container) produce experiments.

Sequence diagram for Bulk API label-based metadata filtering

sequenceDiagram
    participant BulkJobManager
    participant DataSourceManager
    participant DataSourceMetadataOperator
    participant DataSourceMetadataHelper
    participant Prometheus

    BulkJobManager->>BulkJobManager: buildResourceFilters(filter.getInclude())
    BulkJobManager->>BulkJobManager: buildResourceFilters(filter.getExclude())
    BulkJobManager->>DataSourceManager: importMetadataFromDataSource(metadataProfileName, datasource, null, startTime, endTime, steps, measurementDuration, includeResourcesMap, excludeResourcesMap)
    DataSourceManager->>DataSourceMetadataOperator: processQueriesAndPopulateDataSourceMetadataInfo(metadataProfileName, dataSourceInfo, includeResources, excludeResources, startTime, endTime, steps, measurementDuration)

    DataSourceMetadataOperator->>DataSourceMetadataOperator: getNamespacesMatchingLabelFilter(dataSourceInfo, metadataProfile, includeResources, startTime, endTime, steps, measurementDuration)
    DataSourceMetadataOperator->>Prometheus: fetchQueryResults(dataSourceInfo, namespacesWithLabelFilterQuery, startTime, endTime, steps)
    Prometheus-->>DataSourceMetadataOperator: JsonArray(namespaceQueryResultArray)

    DataSourceMetadataOperator->>DataSourceMetadataOperator: getWorkloadsMatchingPodLabelFilter(dataSourceInfo, metadataProfile, includeResources, startTime, endTime, steps, measurementDuration)
    DataSourceMetadataOperator->>Prometheus: fetchQueryResults(dataSourceInfo, workloadsWithPodLabelFilterQuery, startTime, endTime, steps)
    Prometheus-->>DataSourceMetadataOperator: JsonArray(workloadQueryResultArray)

    DataSourceMetadataOperator->>Prometheus: fetchQueryResults(dataSourceInfo, namespaceQuery, startTime, endTime, steps)
    Prometheus-->>DataSourceMetadataOperator: JsonArray(namespacesDataResultArray)
    DataSourceMetadataOperator->>DataSourceMetadataHelper: getActiveNamespaces(namespacesDataResultArray)
    DataSourceMetadataHelper-->>DataSourceMetadataOperator: HashMap(namespaces)

    DataSourceMetadataOperator->>Prometheus: fetchQueryResults(dataSourceInfo, workloadQuery, startTime, endTime, steps)
    Prometheus-->>DataSourceMetadataOperator: JsonArray(workloadDataResultArray)
    DataSourceMetadataOperator->>DataSourceMetadataHelper: getWorkloadInfo(workloadDataResultArray)
    DataSourceMetadataHelper-->>DataSourceMetadataOperator: HashMap(namespaceWorkloadMap)

    DataSourceMetadataOperator->>Prometheus: fetchQueryResults(dataSourceInfo, containerQuery, startTime, endTime, steps)
    Prometheus-->>DataSourceMetadataOperator: JsonArray(containerDataResultArray)
    DataSourceMetadataOperator->>DataSourceMetadataHelper: getContainerInfo(containerDataResultArray)
    DataSourceMetadataHelper-->>DataSourceMetadataOperator: HashMap(workloadContainerMap)

    DataSourceMetadataOperator->>DataSourceMetadataHelper: updateContainerDataSourceMetadataInfoObject(dataSourceName, dataSourceMetadataInfo, namespaceWorkloadMap, workloadContainerMap)
    DataSourceMetadataOperator->>DataSourceMetadataHelper: filterMetadataInfoObject(dataSourceName, dataSourceMetadataInfo, matchedNamespaces, matchedWorkloads)
    DataSourceMetadataHelper-->>DataSourceMetadataOperator: filtered DataSourceMetadataInfo

    DataSourceMetadataOperator-->>DataSourceManager: DataSourceMetadataInfo
    DataSourceManager-->>BulkJobManager: DataSourceMetadataInfo
Loading

File-Level Changes

Change Details Files
Apply namespace and pod label filters in metadata retrieval before and after querying, using profile-driven Prometheus queries and a metadata post-filter step.
  • Add pre-query label-filtered namespace and workload discovery using profile queries namespacesWithLabelFilter and workloadsWithPodLabelFilter with OR semantics over multiple label matchers
  • Integrate matched namespaces and workloads into the existing import flow and then post-filter DataSourceMetadataInfo to drop non-matching namespaces/workloads while preserving data if filters return no matches
  • Extend container metadata update to create missing namespaces/workloads discovered only via label filtering
  • Enhance metadata profile query lookup with safer handling and logging when metrics or aggregation functions are missing
src/main/java/com/autotune/common/datasource/DataSourceMetadataOperator.java
src/main/java/com/autotune/common/data/dataSourceMetadata/DataSourceMetadataHelper.java
manifests/autotune/metadata-profiles/bulk_cluster_metadata_local_monitoring.yaml
manifests/autotune/metadata-profiles/bulk_cluster_metadata_local_monitoring.json
Plumb Bulk API label filters into resource selection, separating label usage for experiment naming from label-based metadata filtering and supporting array-valued label inputs.
  • Change BulkInput.Filter.labels to Map<String, Object> with @JsonAnySetter to preserve arbitrary label keys and support both scalar and list values
  • Rename and adjust label-string builder to getLabelsForExperimentName so it only affects experiment names and safely escapes PromQL label values
  • Replace buildRegexFilters with buildResourceFilters which adds namespace/workload/container regexes plus derived podLabelFilter and namespaceLabelFilter from user labels using normalized label keys
  • Add escapePromQLLabelValue helper and buildLabelFilters to construct safe PromQL label matchers from user-supplied labels
  • Add logging around experiment creation and label handling for traceability
src/main/java/com/autotune/analyzer/workerimpl/BulkJobManager.java
src/main/java/com/autotune/analyzer/serviceObjects/BulkInput.java

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 3 issues, and left some high level feedback:

  • In filterMetadataInfoObject, all errors are swallowed behind a generic log and the method becomes a no-op on any exception; consider tightening the try/catch scope and surfacing failures (or at least logging enough context) so that unexpected filtering issues are visible and debuggable.
  • getMatchedNamespaces and getMatchedWorkloads both construct a new DataSourceMetadataHelper instance instead of reusing the existing helper and share very similar patterns (build query → fetch → map); you can reduce object churn and duplication by reusing the helper and extracting the common query/fetch/mapping logic.
  • The label key normalization and filter construction in buildLabelFilters (key.replaceAll("[^a-zA-Z0-9_]", "_") and label_ prefix) hard-code Prometheus metric label naming assumptions; it would be safer and easier to maintain if this transformation logic were centralized (and shared with any other kube_pod_labels users) rather than embedded here as string manipulation.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `filterMetadataInfoObject`, all errors are swallowed behind a generic log and the method becomes a no-op on any exception; consider tightening the try/catch scope and surfacing failures (or at least logging enough context) so that unexpected filtering issues are visible and debuggable.
- `getMatchedNamespaces` and `getMatchedWorkloads` both construct a new `DataSourceMetadataHelper` instance instead of reusing the existing helper and share very similar patterns (build query → fetch → map); you can reduce object churn and duplication by reusing the helper and extracting the common query/fetch/mapping logic.
- The label key normalization and filter construction in `buildLabelFilters` (`key.replaceAll("[^a-zA-Z0-9_]", "_")` and `label_` prefix) hard-code Prometheus metric label naming assumptions; it would be safer and easier to maintain if this transformation logic were centralized (and shared with any other kube_pod_labels users) rather than embedded here as string manipulation.

## Individual Comments

### Comment 1
<location path="src/main/java/com/autotune/analyzer/workerimpl/BulkJobManager.java" line_range="596" />
<code_context>
+
+        labels.forEach((key, value) -> {
+            String normalizedKey = key.replaceAll("[^a-zA-Z0-9_]", "_");
+            String matcher = "label_" + normalizedKey + "=\"" + value + "\"";
+            podLabelBuilder.append(matcher).append(",");
+            namespaceLabelBuilder.append(matcher).append(",");
</code_context>
<issue_to_address>
**🚨 issue (security):** User-provided label values should be escaped/sanitized before embedding into PromQL matchers.

`labels` values appear to come from user input and are inserted directly into a PromQL selector. Unescaped quotes, backslashes, or PromQL metacharacters can break the query or allow query injection. Please escape `value` correctly (e.g., handle `"` and `\`) or use a dedicated helper to safely construct PromQL label matchers.
</issue_to_address>

### Comment 2
<location path="src/main/java/com/autotune/common/datasource/DataSourceMetadataOperator.java" line_range="333" />
<code_context>
+
+        LOGGER.info("namespaceLabelFilterQuery: {}", namespaceQuery);
+        JsonArray namespaceQueryResultArray = fetchQueryResults(dataSourceInfo, namespaceQuery, startTime, endTime, steps);
+        return new DataSourceMetadataHelper().getActiveNamespaces(namespaceQueryResultArray);
+    }
+
</code_context>
<issue_to_address>
**suggestion (performance):** Avoid instantiating `DataSourceMetadataHelper` for each query and reuse the existing helper where possible.

Here and in `getMatchedWorkloads`, a new `DataSourceMetadataHelper` is created instead of using the existing `dataSourceDetailsHelper` instance. Even if the helper is stateless, this adds unnecessary allocations and diverges from the class’s existing pattern. Please reuse the existing (or a shared) instance for consistency and to avoid extra overhead.
</issue_to_address>

### Comment 3
<location path="docs/bulk-api-label-filtering-simple-guide.md" line_range="39" />
<code_context>
+    image: myapp:v1.0
+```
+
+**Key Point**: Labels are on the **POD**, not on namespace or workload!
+
+---
</code_context>
<issue_to_address>
**nitpick (typo):** Consider pluralizing 'namespace or workload' for grammatical clarity.

Since this refers to the concepts in general, consider: "Labels are on the POD, not on namespaces or workloads!"

```suggestion
**Key Point**: Labels are on the **POD**, not on namespaces or workloads!
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.


labels.forEach((key, value) -> {
String normalizedKey = key.replaceAll("[^a-zA-Z0-9_]", "_");
String matcher = "label_" + normalizedKey + "=\"" + value + "\"";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🚨 issue (security): User-provided label values should be escaped/sanitized before embedding into PromQL matchers.

labels values appear to come from user input and are inserted directly into a PromQL selector. Unescaped quotes, backslashes, or PromQL metacharacters can break the query or allow query injection. Please escape value correctly (e.g., handle " and \) or use a dedicated helper to safely construct PromQL label matchers.


LOGGER.info("namespaceLabelFilterQuery: {}", namespaceQuery);
JsonArray namespaceQueryResultArray = fetchQueryResults(dataSourceInfo, namespaceQuery, startTime, endTime, steps);
return new DataSourceMetadataHelper().getActiveNamespaces(namespaceQueryResultArray);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion (performance): Avoid instantiating DataSourceMetadataHelper for each query and reuse the existing helper where possible.

Here and in getMatchedWorkloads, a new DataSourceMetadataHelper is created instead of using the existing dataSourceDetailsHelper instance. Even if the helper is stateless, this adds unnecessary allocations and diverges from the class’s existing pattern. Please reuse the existing (or a shared) instance for consistency and to avoid extra overhead.

image: myapp:v1.0
```

**Key Point**: Labels are on the **POD**, not on namespace or workload!
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nitpick (typo): Consider pluralizing 'namespace or workload' for grammatical clarity.

Since this refers to the concepts in general, consider: "Labels are on the POD, not on namespaces or workloads!"

Suggested change
**Key Point**: Labels are on the **POD**, not on namespace or workload!
**Key Point**: Labels are on the **POD**, not on namespaces or workloads!

@pinkygupta-hub pinkygupta-hub marked this pull request as draft May 15, 2026 08:41
Signed-off-by: Pinky Gupta <pinky.gupta1@ibm.com>
Signed-off-by: Pinky Gupta <pinky.gupta1@ibm.com>
Signed-off-by: Pinky Gupta <pinky.gupta1@ibm.com>
Signed-off-by: Pinky Gupta <pinky.gupta1@ibm.com>
Signed-off-by: Pinky Gupta <pinky.gupta1@ibm.com>
Signed-off-by: Pinky Gupta <pinky.gupta1@ibm.com>
Signed-off-by: Pinky Gupta <pinky.gupta1@ibm.com>
Signed-off-by: Pinky Gupta <pinky.gupta1@ibm.com>
@pinkygupta-hub pinkygupta-hub changed the title Bulk api label filtering Bulk api label filtering for experiment type container only May 22, 2026
@pinkygupta-hub pinkygupta-hub marked this pull request as ready for review May 22, 2026 07:23
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 2 issues, and left some high level feedback:

  • The new label-filtering path logs quite heavily at INFO level (per-label, per-query, per-merge, plus experiment creation); consider downgrading most of these to DEBUG to avoid noisy logs and performance impact in large clusters.
  • The semantics in filterMetadataInfoObject where a requested label filter that yields no matches results in no filtering (all resources kept) may be surprising for callers; it might be safer to distinguish between 'no metrics / query failure' and a genuine 'no matches' case and let the latter produce an empty selection.
  • In buildLabelFilters, pod and namespace label filters are built identically by duplicating the matcher lists; you could simplify this by building the matcher list once and reusing it for both podLabelFilter and namespaceLabelFilter to reduce code duplication.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new label-filtering path logs quite heavily at INFO level (per-label, per-query, per-merge, plus experiment creation); consider downgrading most of these to DEBUG to avoid noisy logs and performance impact in large clusters.
- The semantics in `filterMetadataInfoObject` where a requested label filter that yields no matches results in *no* filtering (all resources kept) may be surprising for callers; it might be safer to distinguish between 'no metrics / query failure' and a genuine 'no matches' case and let the latter produce an empty selection.
- In `buildLabelFilters`, pod and namespace label filters are built identically by duplicating the matcher lists; you could simplify this by building the matcher list once and reusing it for both `podLabelFilter` and `namespaceLabelFilter` to reduce code duplication.

## Individual Comments

### Comment 1
<location path="src/main/java/com/autotune/analyzer/workerimpl/BulkJobManager.java" line_range="158-159" />
<code_context>
-                    includeResourcesMap = buildRegexFilters(this.bulkInput.getFilter().getInclude());
-                    excludeResourcesMap = buildRegexFilters(this.bulkInput.getFilter().getExclude());
+                    labelString = getLabelsForExperimentName(this.bulkInput.getFilter());
+                    includeResourcesMap = buildResourceFilters(this.bulkInput.getFilter().getInclude());
+                    excludeResourcesMap = buildResourceFilters(this.bulkInput.getFilter().getExclude());
                 }
                 if (null == this.bulkInput.getDatasource()) {
</code_context>
<issue_to_address>
**issue (bug_risk):** Exclude label filters are built but never used in label-based metadata filtering.

`DataSourceMetadataOperator` only uses `includeResources` (`namespaceLabelFilter`, `podLabelFilter`) when calling `getNamespacesMatchingLabelFilter` and `getWorkloadsMatchingPodLabelFilter`. With this change, `excludeResourcesMap` is also populated by `buildResourceFilters`, but those exclude label filters are never consumed, so user-provided exclude labels are silently ignored in metadata import. Please either wire the exclude label filters through to `DataSourceMetadataOperator` with defined semantics, or stop adding `podLabelFilter`/`namespaceLabelFilter` to `excludeResourcesMap` to avoid misleading configuration.
</issue_to_address>

### Comment 2
<location path="src/main/java/com/autotune/analyzer/workerimpl/BulkJobManager.java" line_range="654-661" />
<code_context>
+        List<String> podLabelQueries = new ArrayList<>();
+        List<String> namespaceLabelQueries = new ArrayList<>();
+
+        labels.forEach((key, value) -> {
+            LOGGER.info("Processing label key: '{}' (original)", key);
+            
+            // kube-state-metrics normalizes label names by replacing special chars with underscores
+            // e.g., "pod-template-hash" becomes "label_pod_template_hash"
+            // e.g., "app.kubernetes.io/component" becomes "label_app_kubernetes_io_component"
+            String normalizedKey = key.replaceAll("[^a-zA-Z0-9_]", "_");
+            LOGGER.info("Normalized key for PromQL: '{}'", normalizedKey);
+            
+            // Handle both single string values and arrays of values
</code_context>
<issue_to_address>
**suggestion (performance):** High-volume INFO logging for each label key/value can be noisy in production.

These INFO logs in `buildLabelFilters`, `getLabelsForExperimentName`, and `escapePromQLLabelValue` run once per bulk request per label and can produce excessive log volume and I/O in large clusters. Since this is more diagnostic than operational, consider changing them to DEBUG or guarding them behind a debug flag.

Suggested implementation:

```java
        labels.forEach((key, value) -> {
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Processing label key: '{}' (original)", key);
            }

            // kube-state-metrics normalizes label names by replacing special chars with underscores
            // e.g., "pod-template-hash" becomes "label_pod_template_hash"
            // e.g., "app.kubernetes.io/component" becomes "label_app_kubernetes_io_component"
            String normalizedKey = key.replaceAll("[^a-zA-Z0-9_]", "_");
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Normalized key for PromQL: '{}'", normalizedKey);
            }

```

1. In the same file (`BulkJobManager.java`), locate similar per-label INFO logs in the methods `getLabelsForExperimentName` and `escapePromQLLabelValue` (e.g., logs that print raw label keys/values or normalized values).
2. For each such log:
   - Change `LOGGER.info(...)` to `LOGGER.debug(...)`.
   - Wrap the call in an `if (LOGGER.isDebugEnabled()) { ... }` guard, as done above, to avoid unnecessary string formatting when debug is off.
3. Verify that there are no remaining high-volume per-label INFO logs in these methods, keeping INFO for truly operational/summary messages only (e.g., totals, high-level outcomes).
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +158 to +159
includeResourcesMap = buildResourceFilters(this.bulkInput.getFilter().getInclude());
excludeResourcesMap = buildResourceFilters(this.bulkInput.getFilter().getExclude());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

issue (bug_risk): Exclude label filters are built but never used in label-based metadata filtering.

DataSourceMetadataOperator only uses includeResources (namespaceLabelFilter, podLabelFilter) when calling getNamespacesMatchingLabelFilter and getWorkloadsMatchingPodLabelFilter. With this change, excludeResourcesMap is also populated by buildResourceFilters, but those exclude label filters are never consumed, so user-provided exclude labels are silently ignored in metadata import. Please either wire the exclude label filters through to DataSourceMetadataOperator with defined semantics, or stop adding podLabelFilter/namespaceLabelFilter to excludeResourcesMap to avoid misleading configuration.

Comment on lines +654 to +661
labels.forEach((key, value) -> {
LOGGER.info("Processing label key: '{}' (original)", key);

// kube-state-metrics normalizes label names by replacing special chars with underscores
// e.g., "pod-template-hash" becomes "label_pod_template_hash"
// e.g., "app.kubernetes.io/component" becomes "label_app_kubernetes_io_component"
String normalizedKey = key.replaceAll("[^a-zA-Z0-9_]", "_");
LOGGER.info("Normalized key for PromQL: '{}'", normalizedKey);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion (performance): High-volume INFO logging for each label key/value can be noisy in production.

These INFO logs in buildLabelFilters, getLabelsForExperimentName, and escapePromQLLabelValue run once per bulk request per label and can produce excessive log volume and I/O in large clusters. Since this is more diagnostic than operational, consider changing them to DEBUG or guarding them behind a debug flag.

Suggested implementation:

        labels.forEach((key, value) -> {
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Processing label key: '{}' (original)", key);
            }

            // kube-state-metrics normalizes label names by replacing special chars with underscores
            // e.g., "pod-template-hash" becomes "label_pod_template_hash"
            // e.g., "app.kubernetes.io/component" becomes "label_app_kubernetes_io_component"
            String normalizedKey = key.replaceAll("[^a-zA-Z0-9_]", "_");
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Normalized key for PromQL: '{}'", normalizedKey);
            }
  1. In the same file (BulkJobManager.java), locate similar per-label INFO logs in the methods getLabelsForExperimentName and escapePromQLLabelValue (e.g., logs that print raw label keys/values or normalized values).
  2. For each such log:
    • Change LOGGER.info(...) to LOGGER.debug(...).
    • Wrap the call in an if (LOGGER.isDebugEnabled()) { ... } guard, as done above, to avoid unnecessary string formatting when debug is off.
  3. Verify that there are no remaining high-volume per-label INFO logs in these methods, keeping INFO for truly operational/summary messages only (e.g., totals, high-level outcomes).

Signed-off-by: Pinky Gupta <pinky.gupta1@ibm.com>
Signed-off-by: Pinky Gupta <pinky.gupta1@ibm.com>
Signed-off-by: Pinky Gupta <pinky.gupta1@ibm.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Under Review

Development

Successfully merging this pull request may close these issues.

5 participants