Skip to content

feat: add resourceAttributes support to OpenMetricsSink and PrometheusSink#213

Merged
Nek-12 merged 3 commits intorespawn-app:masterfrom
anshu7vyas:feature/metrics-metadata-structured-sinks
Mar 2, 2026
Merged

feat: add resourceAttributes support to OpenMetricsSink and PrometheusSink#213
Nek-12 merged 3 commits intorespawn-app:masterfrom
anshu7vyas:feature/metrics-metadata-structured-sinks

Conversation

@anshu7vyas
Copy link
Contributor

@anshu7vyas anshu7vyas commented Feb 28, 2026

Summary

  • OpenMetricsSink and PrometheusSink now accept a resourceAttributes: Map<String, String> parameter that appends fixed key-value labels (e.g. install_id, device_model) to every metric sample's label set.
  • update tests

Testing

  • ./gradlew :metrics:assemble
  • ./gradlew allTests

Closes #203

Summary by CodeRabbit

  • New Features
    • Metrics output now supports adding custom resource attributes to OpenMetrics and Prometheus labels; attributes can be static or computed dynamically from snapshot context.
    • Provider-supplied attributes take precedence over defaults, ensuring explicit values override static defaults.
    • OTLP output moved to a provider-based resource-attribute model with unchanged default behavior.

@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the metrics sinks by introducing a mechanism to attach global resource-level attributes to all emitted metrics. This allows for better contextualization and filtering of metrics in monitoring systems, enabling users to easily identify and categorize metrics based on their origin or environment.

Highlights

  • Resource Attributes Support: The OpenMetricsSink and PrometheusSink now support resourceAttributes, allowing fixed key-value labels (e.g., install_id, device_model) to be appended to every metric sample's label set.
  • Configurable Attributes: Users can provide a static resourceAttributes map or a dynamic resourceAttributesProvider function to supply these labels, with the provider taking precedence.
Changelog
  • metrics/src/commonMain/kotlin/pro/respawn/flowmvi/metrics/openmetrics/OpenMetricsSink.kt
    • Imported the Meta class for use in attribute provisioning.
    • Modified OpenMetricsRenderer to accept a resourceAttributesProvider function.
    • Updated the baseLabels function to incorporate additional extras (resource attributes) into the metric labels.
    • Added resourceAttributes and resourceAttributesProvider parameters to the OpenMetricsSink factory function.
    • Added resourceAttributes and resourceAttributesProvider parameters to the PrometheusSink factory function.
  • metrics/src/jvmTest/kotlin/pro/respawn/flowmvi/metrics/openmetrics/OpenMetricsSinkJvmTest.kt
    • Added new test cases to verify that resourceAttributes are correctly included as labels for OpenMetricsSink.
    • Included tests to confirm that the resourceAttributesProvider correctly overrides static attributes and meta defaults for OpenMetricsSink.
    • Added new test cases to verify that resourceAttributes are correctly included as labels for PrometheusSink.
    • Included tests to confirm that the resourceAttributesProvider correctly overrides static attributes and meta defaults for PrometheusSink.
Activity
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 28, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a6fbbc3 and fb356fa.

📒 Files selected for processing (4)
  • metrics/src/commonMain/kotlin/pro/respawn/flowmvi/metrics/openmetrics/OpenMetricsSink.kt
  • metrics/src/commonMain/kotlin/pro/respawn/flowmvi/metrics/otel/OtlpJsonSink.kt
  • metrics/src/jvmTest/kotlin/pro/respawn/flowmvi/metrics/openmetrics/OpenMetricsSinkJvmTest.kt
  • metrics/src/jvmTest/kotlin/pro/respawn/flowmvi/metrics/otel/OtlpJsonSinkTest.kt
✅ Files skipped from review due to trivial changes (1)
  • metrics/src/commonMain/kotlin/pro/respawn/flowmvi/metrics/otel/OtlpJsonSink.kt
🚧 Files skipped from review as they are similar to previous changes (2)
  • metrics/src/jvmTest/kotlin/pro/respawn/flowmvi/metrics/openmetrics/OpenMetricsSinkJvmTest.kt
  • metrics/src/commonMain/kotlin/pro/respawn/flowmvi/metrics/openmetrics/OpenMetricsSink.kt

📝 Walkthrough

Walkthrough

Added provider-based resource attributes across metrics sinks: OpenMetrics/Prometheus now accept a resourceAttributesProvider: (Meta) -> Map<String, String> and apply its output as extra labels; OTLP JSON sink removed the static resourceAttributes param and uses a provider defaulting to empty map. Tests updated/added.

Changes

Cohort / File(s) Summary
OpenMetrics / Prometheus sinks
metrics/src/commonMain/kotlin/pro/respawn/flowmvi/metrics/openmetrics/OpenMetricsSink.kt
Added resourceAttributesProvider: (Meta) -> Map<String, String> parameter to OpenMetricsSink and PrometheusSink, plumbed into OpenMetricsRenderer; renderer/base label construction updated to accept and merge provider-derived extras.
OpenMetrics JVM tests
metrics/src/jvmTest/kotlin/pro/respawn/flowmvi/metrics/openmetrics/OpenMetricsSinkJvmTest.kt
Added tests verifying emitted samples include resource attributes and that resourceAttributesProvider overrides static defaults for both OpenMetrics and Prometheus sinks.
OTLP JSON sink
metrics/src/commonMain/kotlin/pro/respawn/flowmvi/metrics/otel/OtlpJsonSink.kt
Removed the public resourceAttributes: Map<String,String> parameter; replaced with resourceAttributesProvider: (Meta) -> Map<String,String> = { emptyMap() }; updated call sites to pass the provider only.
OTLP JSON tests
metrics/src/jvmTest/kotlin/pro/respawn/flowmvi/metrics/otel/OtlpJsonSinkTest.kt
Updated tests/call sites to use resourceAttributesProvider instead of the removed static resourceAttributes argument.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped through code with ears so keen,
Labels now wear a brand-new sheen.
Providers whisper meta tales,
Merged with metrics on the trails.
Hooray — more tags for every stream!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Changes to OtlpJsonSink removing static resourceAttributes parameter appear out-of-scope; PR title and issue #203 focus on adding support to OpenMetricsSink/PrometheusSink, not refactoring OtlpJsonSink. Clarify whether OtlpJsonSink refactoring is intentional; if so, update PR title and objectives to reflect this broader API change, or move those changes to a separate PR.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main change: adding resourceAttributes support to OpenMetricsSink and PrometheusSink.
Linked Issues check ✅ Passed PR addresses issue #203 objectives by adding resourceAttributesProvider to OpenMetricsSink and PrometheusSink, includes tests, maintains backward compatibility with default empty map.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request adds support for resourceAttributes to OpenMetricsSink and PrometheusSink, allowing for custom labels to be added to all metrics. However, the current implementation is vulnerable to Prometheus Exposition Format Injection because it does not validate or escape the keys provided in the resourceAttributes map, which could allow an attacker to inject arbitrary labels or disrupt the monitoring system. It is strongly recommended to add validation for label keys to ensure they follow Prometheus naming conventions. Additionally, while the implementation is clean and well-tested, consider refactoring the new tests to reduce duplication and improve maintainability.

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

🧹 Nitpick comments (2)
metrics/src/jvmTest/kotlin/pro/respawn/flowmvi/metrics/openmetrics/OpenMetricsSinkJvmTest.kt (1)

151-163: Strengthen “on all samples” assertions

Current checks only prove labels exist somewhere in output, not on every sample line. A partial-label regression would still pass.

Proposed test tightening
         val rendered = buffer.toString()
-        rendered.shouldContain("install_id=\"abc-123\"")
-        rendered.shouldContain("device_model=\"Pixel 9\"")
+        rendered.lineSequence()
+            .filter { it.isNotBlank() && !it.startsWith("#") }
+            .forEach { line ->
+                line.shouldContain("""install_id="abc-123"""")
+                line.shouldContain("""device_model="Pixel 9"""")
+            }

Also applies to: 181-193

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@metrics/src/jvmTest/kotlin/pro/respawn/flowmvi/metrics/openmetrics/OpenMetricsSinkJvmTest.kt`
around lines 151 - 163, The test currently only asserts that resource labels
appear somewhere in the rendered output; update the "resource attributes are
included as labels on all samples" test to assert they appear on every sample
line by splitting the rendered output (from buffer.toString()) into lines,
filtering to metric/sample lines (e.g., lines that are not empty and do not
start with "#" or HELP/TYPE comments), and then for each remaining line assert
it contains both install_id="abc-123" and device_model="Pixel 9"; apply the same
tightening to the other test block that uses OpenMetricsSink and
AppendableStringSink around snapshot rendering (the similar assertions at the
other location).
metrics/src/commonMain/kotlin/pro/respawn/flowmvi/metrics/openmetrics/OpenMetricsSink.kt (1)

693-726: Document parameter precedence in public KDoc

Please add KDoc for resourceAttributes and resourceAttributesProvider, especially precedence/override behavior when both are provided.

As per coding guidelines **/*.kt: Document public code via kdocs.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@metrics/src/commonMain/kotlin/pro/respawn/flowmvi/metrics/openmetrics/OpenMetricsSink.kt`
around lines 693 - 726, Add KDoc to the public factory functions OpenMetricsSink
and PrometheusSink for the parameters resourceAttributes and
resourceAttributesProvider clarifying usage and precedence: state that
resourceAttributes is a convenience static map used when no provider is
supplied, resourceAttributesProvider is a function that will be invoked with the
Metric snapshot Meta to produce attributes, and when a non-default
resourceAttributesProvider is passed it takes precedence over the
resourceAttributes map (the default provider simply returns the
resourceAttributes map). Keep the description concise and include parameter
names exactly as resourceAttributes and resourceAttributesProvider so readers
can find them in the signatures.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@metrics/src/commonMain/kotlin/pro/respawn/flowmvi/metrics/openmetrics/OpenMetricsSink.kt`:
- Around line 677-686: The baseLabels function currently calls putAll(extras)
(the extras map derived from resourceAttributes), which can inject arbitrary
keys as metric label names; validate and sanitize those keys before merging: in
baseLabels (function baseLabels) filter the extras/resourceAttributes map to
only include keys that match Prometheus/OpenMetrics label name rules (e.g. regex
like "^[A-Za-z_][A-Za-z0-9_]*$") or transform invalid characters to valid ones,
then putAll the validated/sanitized map instead of the raw extras to prevent
emitting invalid label names.

---

Nitpick comments:
In
`@metrics/src/commonMain/kotlin/pro/respawn/flowmvi/metrics/openmetrics/OpenMetricsSink.kt`:
- Around line 693-726: Add KDoc to the public factory functions OpenMetricsSink
and PrometheusSink for the parameters resourceAttributes and
resourceAttributesProvider clarifying usage and precedence: state that
resourceAttributes is a convenience static map used when no provider is
supplied, resourceAttributesProvider is a function that will be invoked with the
Metric snapshot Meta to produce attributes, and when a non-default
resourceAttributesProvider is passed it takes precedence over the
resourceAttributes map (the default provider simply returns the
resourceAttributes map). Keep the description concise and include parameter
names exactly as resourceAttributes and resourceAttributesProvider so readers
can find them in the signatures.

In
`@metrics/src/jvmTest/kotlin/pro/respawn/flowmvi/metrics/openmetrics/OpenMetricsSinkJvmTest.kt`:
- Around line 151-163: The test currently only asserts that resource labels
appear somewhere in the rendered output; update the "resource attributes are
included as labels on all samples" test to assert they appear on every sample
line by splitting the rendered output (from buffer.toString()) into lines,
filtering to metric/sample lines (e.g., lines that are not empty and do not
start with "#" or HELP/TYPE comments), and then for each remaining line assert
it contains both install_id="abc-123" and device_model="Pixel 9"; apply the same
tightening to the other test block that uses OpenMetricsSink and
AppendableStringSink around snapshot rendering (the similar assertions at the
other location).

ℹ️ Review info

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0c19384 and a6fbbc3.

📒 Files selected for processing (2)
  • metrics/src/commonMain/kotlin/pro/respawn/flowmvi/metrics/openmetrics/OpenMetricsSink.kt
  • metrics/src/jvmTest/kotlin/pro/respawn/flowmvi/metrics/openmetrics/OpenMetricsSinkJvmTest.kt

coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 28, 2026
…utesProvider

The `resourceAttributes` parameter has been removed from `toOtlpPayload`, `OtlpJsonSink`, `OpenMetricsSink`, and `PrometheusSink`. Callers should now use `resourceAttributesProvider` to provide dynamic attributes based on the snapshot metadata. Tests have been updated to reflect this change.
@Nek-12 Nek-12 enabled auto-merge March 2, 2026 09:00
@Nek-12 Nek-12 merged commit f2146f3 into respawn-app:master Mar 2, 2026
3 checks passed
@anshu7vyas anshu7vyas deleted the feature/metrics-metadata-structured-sinks branch March 5, 2026 07:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🚀: [Metrics] Allow adding metadata to structured sinks

2 participants