Skip to content

Conversation

UltimatePlutoC
Copy link

@UltimatePlutoC UltimatePlutoC commented Sep 8, 2025

Related issue

Fixes #3144

  • I have added tests that cover my changes.
  • If adding a new instrumentation or changing an existing one, I've added screenshots from some observability platform showing the change.
  • PR name follows conventional commits format: feat(instrumentation): ... or fix(instrumentation): ....
  • (If applicable) I have updated the documentation accordingly.

Summary

This PR adds the gen_ai.request.model attribute to all meter data points in the OpenAI instrumentation package, alongside the existing gen_ai.response.model. This provides richer context for metrics and observability.

Details

  • Adds gen_ai.request.model to meter attributes in both sync and async streaming metric paths.
  • Updates tests to assert the presence and correctness of the new attribute.
  • Updates documentation README to describe the new attribute.

Screenshots

sc1 sc2

Motivation

Including both the request and response model names in metrics allows for better debugging, analysis, and correlation of model usage, especially when the requested and returned models may differ.


Important

Adds gen_ai.request.model to meter attributes in OpenAI instrumentation for enhanced observability, updates tests and documentation.

  • Behavior:
    • Adds gen_ai.request.model attribute to meter data points in chat_wrappers.py for both sync and async streaming paths.
    • Updates tests in test_openai_metrics.py to verify the presence and correctness of gen_ai.request.model.
  • Documentation:
    • Updates README.md to include gen_ai.request.model in the meter attributes section.

This description was created by Ellipsis for d2607d7. You can customize this summary. It will automatically update as commits are pushed.

Summary by CodeRabbit

  • New Features

    • Metrics now include the request model name (gen_ai.request.model) alongside the response model name (gen_ai.response.model), enabling richer filtering and analysis across data points.
  • Documentation

    • Added a “Meter Attributes” section explaining the new and existing model name attributes and how they appear in metrics.
  • Tests

    • Expanded metric tests to validate the presence and consistency of gen_ai.request.model across token usage, generation choices, and operation duration metrics.

Copy link

coderabbitai bot commented Sep 8, 2025

Walkthrough

Adds gen_ai.request.model as a meter attribute in streaming chat metrics, documents the new meter attributes in README, and updates tests to assert the attribute presence and value. No public APIs or control flow changed.

Changes

Cohort / File(s) Summary
Documentation
packages/opentelemetry-instrumentation-openai/README.md
Added “Meter Attributes” section documenting gen_ai.request.model and gen_ai.response.model.
Metric attribute tagging
packages/opentelemetry-instrumentation-openai/opentelemetry/instrumentation/openai/shared/chat_wrappers.py
Added shared attribute gen_ai.request.model in streaming response builders using request_kwargs.get("model").
Tests
packages/opentelemetry-instrumentation-openai/tests/metrics/test_openai_metrics.py
Added assertions verifying gen_ai.request.model == "gpt-3.5-turbo" across relevant metric data points.

Sequence Diagram(s)

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related issues

Suggested reviewers

  • nirga

Poem

A whisk of ears, a metric hops,
New tags bloom where tracing stops.
Request and response, model names align,
Carrots count tokens—everything’s fine.
I thump in joy, observability bright—
Tiny pawprints in your metric light. 🥕✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • 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
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Caution

Changes requested ❌

Reviewed everything up to d2607d7 in 1 minute and 50 seconds. Click for details.
  • Reviewed 74 lines of code in 3 files
  • Skipped 0 files when reviewing.
  • Skipped posting 2 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. packages/opentelemetry-instrumentation-openai/README.md:10
  • Draft comment:
    Good documentation update! The description of the new meter attribute is clear.
  • Reason this comment was not posted:
    Confidence changes required: 0% <= threshold 50% None
2. packages/opentelemetry-instrumentation-openai/tests/metrics/test_openai_metrics.py:50
  • Draft comment:
    Test assertions check that 'gen_ai.request.model' equals the expected model. Ensure the non-streaming instrumentation is updated accordingly.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% The comment is asking the author to ensure that the non-streaming instrumentation is updated accordingly. This is a vague request for confirmation or assurance, which violates the rule against asking the author to ensure something is tested or intended. It does not provide a specific suggestion or point out a specific issue.

Workflow ID: wflow_CTX4TqkqWp4J4vOr

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.


shared_attributes = {
SpanAttributes.LLM_RESPONSE_MODEL: complete_response.get("model") or None,
"gen_ai.request.model": request_kwargs.get("model") if request_kwargs else None,
Copy link
Contributor

Choose a reason for hiding this comment

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

New attribute 'gen_ai.request.model' is added for streaming responses. However, non-streaming completions (handled via _handle_response/_set_chat_metrics) do not include this attribute. Please update the synchronous path so that all meter data points include 'gen_ai.request.model' to ensure consistency with tests.

Copy link

@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: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/opentelemetry-instrumentation-openai/opentelemetry/instrumentation/openai/shared/chat_wrappers.py (2)

726-734: ChatStream path misses explicit gen_ai.request.model and risks AttributeError when request_kwargs is None

  • _shared_attributes() doesn’t attach gen_ai.request.model, so ChatStream (OpenAI v1 streaming) likely omits the new attribute.
  • Accessing self._request_kwargs.get(...) without a None/type guard can raise at runtime.

Apply:

 def _shared_attributes(self):
-    return metric_shared_attributes(
-        response_model=self._complete_response.get("model")
-        or self._request_kwargs.get("model")
-        or None,
-        operation="chat",
-        server_address=_get_openai_base_url(self._instance),
-        is_streaming=True,
-    )
+    resp_model = self._complete_response.get("model")
+    req_model = (
+        self._request_kwargs.get("model")
+        if isinstance(self._request_kwargs, dict)
+        else None
+    )
+    attrs = metric_shared_attributes(
+        response_model=resp_model or req_model or None,
+        operation="chat",
+        server_address=_get_openai_base_url(self._instance),
+        is_streaming=True,
+    )
+    # Ensure request model is always stamped on metrics
+    attrs["gen_ai.request.model"] = req_model
+    return attrs

1-1192: Add gen_ai.request.model to metric_shared_attributes
Non-streaming metrics (via metric_shared_attributes in shared/__init__.py) currently only emit system, response model, and operation name—so both regular and ChatStream-based v1 streaming metrics lack the request model. Mirror the manual "gen_ai.request.model": request_kwargs.get("model") added in _build_from_streaming_response (chat_wrappers.py lines 889–894) by updating metric_shared_attributes to include the request model.

🧹 Nitpick comments (5)
packages/opentelemetry-instrumentation-openai/README.md (1)

10-18: Clarify release version and nullability; tighten wording

  • Replace “vNEXT” with the concrete version at release time.
  • Note that gen_ai.request.model may be null when a request model isn’t provided.
  • Minor tighten: “This provides richer context...” → “These attributes provide richer context...”.

Apply:

-## Meter Attributes
-
-As of vNEXT, all meter data points now include both the response and request model names:
+## Meter Attributes
+
+As of vX.Y.Z, all meter data points include both the response and request model names:
@@
-* `gen_ai.request.model` — The model name specified in the request payload (e.g., "gpt-3.5-turbo").
+* `gen_ai.request.model` — The model name specified in the request payload (e.g., "gpt-3.5-turbo"). May be null if unspecified.
@@
-This provides richer context for metrics and observability.
+These attributes provide richer context for metrics and observability.
packages/opentelemetry-instrumentation-openai/opentelemetry/instrumentation/openai/shared/chat_wrappers.py (2)

889-896: Good addition; consider centralizing attribute building for consistency

The direct dict works; however, using metric_shared_attributes(...) and then overlaying gen_ai.request.model keeps attributes uniform (system, operation, etc.) with non-streaming paths.

Apply:

-    shared_attributes = {
-        SpanAttributes.LLM_RESPONSE_MODEL: complete_response.get("model") or None,
-        "gen_ai.request.model": request_kwargs.get("model") if request_kwargs else None,
-        "server.address": _get_openai_base_url(instance),
-        "stream": True,
-    }
+    shared_attributes = metric_shared_attributes(
+        response_model=complete_response.get("model") or None,
+        operation="chat",
+        server_address=_get_openai_base_url(instance),
+        is_streaming=True,
+    )
+    shared_attributes["gen_ai.request.model"] = (
+        request_kwargs.get("model") if isinstance(request_kwargs, dict) else None
+    )

961-967: Mirror the same centralization in async builder

Keep async and sync streaming builders aligned to avoid drift.

Apply:

-    shared_attributes = {
-        SpanAttributes.LLM_RESPONSE_MODEL: complete_response.get("model") or None,
-        "gen_ai.request.model": request_kwargs.get("model") if request_kwargs else None,
-        "server.address": _get_openai_base_url(instance),
-        "stream": True,
-    }
+    shared_attributes = metric_shared_attributes(
+        response_model=complete_response.get("model") or None,
+        operation="chat",
+        server_address=_get_openai_base_url(instance),
+        is_streaming=True,
+    )
+    shared_attributes["gen_ai.request.model"] = (
+        request_kwargs.get("model") if isinstance(request_kwargs, dict) else None
+    )
packages/opentelemetry-instrumentation-openai/tests/metrics/test_openai_metrics.py (2)

139-226: Add streaming assertions for gen_ai.request.model to cover the streaming metric path

Extend test_chat_streaming_metrics to assert the new attribute for stream=True as well (covers the non-v1 streaming builders; after the ChatStream fix it’ll exercise v1 too when applicable).

Apply:

@@ def test_chat_streaming_metrics(instrument_legacy, reader, deepseek_client):
-            for metric in sm.metrics:
+            for metric in sm.metrics:
                 if metric.name == Meters.LLM_TOKEN_USAGE:
                     found_token_metric = True
                     for data_point in metric.data.data_points:
                         assert data_point.attributes[SpanAttributes.LLM_TOKEN_TYPE] in [
                             "output",
                             "input",
                         ]
                         assert data_point.sum > 0
+                        # New: request model is stamped on streaming metrics
+                        assert data_point.attributes["gen_ai.request.model"] == "deepseek-chat"
@@
                 if metric.name == Meters.LLM_GENERATION_CHOICES:
                     found_choice_metric = True
                     for data_point in metric.data.data_points:
                         assert data_point.value >= 1
+                        assert data_point.attributes["gen_ai.request.model"] == "deepseek-chat"
@@
                 if metric.name == Meters.LLM_OPERATION_DURATION:
                     found_duration_metric = True
                     assert any(
                         data_point.count > 0 for data_point in metric.data.data_points
                     )
                     assert any(
                         data_point.sum > 0 for data_point in metric.data.data_points
                     )
+                    assert all(
+                        data_point.attributes["gen_ai.request.model"] == "deepseek-chat"
+                        for data_point in metric.data.data_points
+                    )

1-314: Define module‐local constant for request model attribute
The opentelemetry-semantic-conventions-ai package doesn’t expose a SpanAttributes constant for "gen_ai.request.model". Declare a constant in this test module (e.g.

REQUEST_MODEL_ATTR = "gen_ai.request.model"

) and use it instead of the raw string.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 50cd4f0 and d2607d7.

📒 Files selected for processing (3)
  • packages/opentelemetry-instrumentation-openai/README.md (1 hunks)
  • packages/opentelemetry-instrumentation-openai/opentelemetry/instrumentation/openai/shared/chat_wrappers.py (2 hunks)
  • packages/opentelemetry-instrumentation-openai/tests/metrics/test_openai_metrics.py (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Store API keys only in environment variables/secure vaults; never hardcode secrets in code
Use Flake8 for code linting and adhere to its rules

Files:

  • packages/opentelemetry-instrumentation-openai/opentelemetry/instrumentation/openai/shared/chat_wrappers.py
  • packages/opentelemetry-instrumentation-openai/tests/metrics/test_openai_metrics.py
🧬 Code graph analysis (1)
packages/opentelemetry-instrumentation-openai/tests/metrics/test_openai_metrics.py (1)
packages/opentelemetry-semantic-conventions-ai/opentelemetry/semconv_ai/__init__.py (1)
  • Meters (36-61)
🪛 Ruff (0.12.2)
packages/opentelemetry-instrumentation-openai/tests/metrics/test_openai_metrics.py

51-51: Use of assert detected

(S101)


56-56: Use of assert detected

(S101)


57-57: Use of assert detected

(S101)


58-58: Use of assert detected

(S101)


72-72: Use of assert detected

(S101)

🔇 Additional comments (3)
packages/opentelemetry-instrumentation-openai/tests/metrics/test_openai_metrics.py (3)

50-52: LGTM: asserts request model on token usage data points


58-58: LGTM: asserts request model on choices data points


72-75: LGTM: asserts request model on duration data points

Copy link
Member

@nirga nirga left a comment

Choose a reason for hiding this comment

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

Thanks @UltimatePlutoC - can you look into the failing CI?

@UltimatePlutoC
Copy link
Author

Thanks @UltimatePlutoC - can you look into the failing CI?

Sure, @nirga
Will work on it ASAP.

@CLAassistant
Copy link

CLAassistant commented Sep 12, 2025

CLA assistant check
All committers have signed the CLA.

@UltimatePlutoC
Copy link
Author

Having some trouble with the failing CI:

nx run opentelemetry-instrumentation-openai:test

Kindly requesting some assistance.

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.

🚀 Feature: Add gen_ai.request.model to data points attributes of meter
3 participants