Skip to content

feat(semantic-conventions-ai): move custom histogram to semantic-conventions-ai #3181

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -663,10 +663,18 @@ def _instrument(self, **kwargs):
tracer_provider = kwargs.get("tracer_provider")
tracer = get_tracer(__name__, __version__, tracer_provider)

# meter and counters are inited here
meter_provider = kwargs.get("meter_provider")

if meter_provider is None:
try:
from opentelemetry.semconv_ai import apply_genai_bucket_configuration
apply_genai_bucket_configuration()
except ImportError:
pass

meter = get_meter(__name__, __version__, meter_provider)

# meter and counters are inited here
if is_metrics_enabled():
(
token_histogram,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -575,10 +575,18 @@ def _instrument(self, **kwargs):
tracer_provider = kwargs.get("tracer_provider")
tracer = get_tracer(__name__, __version__, tracer_provider)

# meter and counters are inited here
meter_provider = kwargs.get("meter_provider")

if meter_provider is None:
try:
from opentelemetry.semconv_ai import apply_genai_bucket_configuration
apply_genai_bucket_configuration()
except ImportError:
pass

meter = get_meter(__name__, __version__, meter_provider)

# meter and counters are inited here
if is_metrics_enabled():
(
token_histogram,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ def _instrument(self, **kwargs):
tracer = get_tracer(__name__, __version__, tracer_provider)

meter_provider = kwargs.get("meter_provider")

if meter_provider is None:
try:
from opentelemetry.semconv_ai import apply_genai_bucket_configuration
apply_genai_bucket_configuration()
except ImportError:
pass

meter = get_meter(__name__, __version__, meter_provider)

if is_metrics_enabled():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -401,10 +401,18 @@ def _instrument(self, **kwargs):
tracer_provider = kwargs.get("tracer_provider")
tracer = get_tracer(__name__, __version__, tracer_provider)

# meter and counters are inited here
meter_provider = kwargs.get("meter_provider")

if meter_provider is None:
try:
from opentelemetry.semconv_ai import apply_genai_bucket_configuration
apply_genai_bucket_configuration()
except ImportError:
pass

meter = get_meter(__name__, __version__, meter_provider)

# meter and counters are inited here
if is_metrics_enabled():
(
token_histogram,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,15 @@ def _instrument(self, **kwargs):
tracer_provider = kwargs.get("tracer_provider")
tracer = get_tracer(__name__, __version__, tracer_provider)

# Add meter creation
meter_provider = kwargs.get("meter_provider")

if meter_provider is None:
try:
from opentelemetry.semconv_ai import apply_genai_bucket_configuration
apply_genai_bucket_configuration()
except ImportError:
pass

meter = get_meter(__name__, __version__, meter_provider)

# Create duration histogram
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,14 @@ def instrumentation_dependencies(self) -> Collection[str]:
def _instrument(self, **kwargs):
if is_metrics_enabled():
meter_provider = kwargs.get("meter_provider")

if meter_provider is None:
try:
from opentelemetry.semconv_ai import apply_genai_bucket_configuration
apply_genai_bucket_configuration()
except ImportError:
pass

meter = get_meter(__name__, __version__, meter_provider)

query_duration_metric = meter.create_histogram(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,14 @@ def _instrument(self, **kwargs):
tracer = get_tracer(__name__, __version__, tracer_provider)

meter_provider = kwargs.get("meter_provider")

if meter_provider is None:
try:
from opentelemetry.semconv_ai import apply_genai_bucket_configuration
apply_genai_bucket_configuration()
except ImportError:
pass

meter = get_meter(__name__, __version__, meter_provider)

if is_metrics_collection_enabled():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,14 @@ def _instrument(self, **kwargs):
tracer = get_tracer(__name__, __version__, tracer_provider)

meter_provider = kwargs.get("meter_provider")

if meter_provider is None:
try:
from opentelemetry.semconv_ai import apply_genai_bucket_configuration
apply_genai_bucket_configuration()
except ImportError:
pass

meter = get_meter(__name__, __version__, meter_provider)

if is_metrics_enabled():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ def _instrument(self, **kwargs):
tracer = get_tracer(__name__, __version__, tracer_provider)

meter_provider = kwargs.get("meter_provider")

if meter_provider is None:
try:
from opentelemetry.semconv_ai import apply_genai_bucket_configuration
apply_genai_bucket_configuration()
except ImportError:
pass

meter = get_meter(__name__, __version__, meter_provider)

if not Config.use_legacy_attributes:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,15 @@ def _instrument(self, **kwargs):
tracer_provider = kwargs.get("tracer_provider")
tracer = get_tracer(__name__, __version__, tracer_provider)

# meter and counters are inited here
meter_provider = kwargs.get("meter_provider")

if meter_provider is None:
try:
from opentelemetry.semconv_ai import apply_genai_bucket_configuration
apply_genai_bucket_configuration()
except ImportError:
pass

meter = get_meter(__name__, __version__, meter_provider)

if not Config.use_legacy_attributes:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,14 @@ def instrumentation_dependencies(self) -> Collection[str]:
def _instrument(self, **kwargs):
if is_metrics_enabled():
meter_provider = kwargs.get("meter_provider")

if meter_provider is None:
try:
from opentelemetry.semconv_ai import apply_genai_bucket_configuration
apply_genai_bucket_configuration()
except ImportError:
pass

meter = get_meter(__name__, __version__, meter_provider)

query_duration_metric = meter.create_histogram(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,14 @@ def _instrument(self, **kwargs):
tracer = get_tracer(__name__, __version__, tracer_provider)

meter_provider = kwargs.get("meter_provider")

if meter_provider is None:
try:
from opentelemetry.semconv_ai import apply_genai_bucket_configuration
apply_genai_bucket_configuration()
except ImportError:
pass

meter = get_meter(__name__, __version__, meter_provider)

if is_metrics_enabled():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -300,3 +300,192 @@ class TraceloopSpanKindValues(Enum):
AGENT = "agent"
TOOL = "tool"
UNKNOWN = "unknown"


class MetricBuckets:
"""Predefined histogram bucket boundaries for GenAI metrics."""

LLM_TOKEN_USAGE = [
1,
4,
16,
64,
256,
1024,
4096,
16384,
65536,
262144,
1048576,
4194304,
16777216,
67108864,
]

PINECONE_DB_QUERY_DURATION = [
0.01,
0.02,
0.04,
0.08,
0.16,
0.32,
0.64,
1.28,
2.56,
5.12,
10.24,
20.48,
40.96,
81.92,
]

PINECONE_DB_QUERY_SCORES = [
-1,
-0.875,
-0.75,
-0.625,
-0.5,
-0.375,
-0.25,
-0.125,
0,
0.125,
0.25,
0.375,
0.5,
0.625,
0.75,
0.875,
1,
]


class MetricViewsBuilder:
"""Builder for OpenTelemetry metric views with predefined buckets."""

@staticmethod
def get_llm_token_usage_view():
from opentelemetry.sdk.metrics.view import View, ExplicitBucketHistogramAggregation

return View(
instrument_name=Meters.LLM_TOKEN_USAGE,
aggregation=ExplicitBucketHistogramAggregation(
MetricBuckets.LLM_TOKEN_USAGE
),
)

@staticmethod
def get_pinecone_query_duration_view():
from opentelemetry.sdk.metrics.view import View, ExplicitBucketHistogramAggregation

return View(
instrument_name=Meters.PINECONE_DB_QUERY_DURATION,
aggregation=ExplicitBucketHistogramAggregation(
MetricBuckets.PINECONE_DB_QUERY_DURATION
),
)

@staticmethod
def get_pinecone_query_scores_view():
from opentelemetry.sdk.metrics.view import View, ExplicitBucketHistogramAggregation

return View(
instrument_name=Meters.PINECONE_DB_QUERY_SCORES,
aggregation=ExplicitBucketHistogramAggregation(
MetricBuckets.PINECONE_DB_QUERY_SCORES
),
)

@staticmethod
def get_llm_operation_duration_view():
from opentelemetry.sdk.metrics.view import View

return View(
instrument_name=Meters.LLM_OPERATION_DURATION,
)
Comment on lines +400 to +405
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

LLM operation duration view lacks explicit aggregation configuration.

Unlike other views, this method doesn't specify an ExplicitBucketHistogramAggregation, which means it will use the default histogram buckets. This inconsistency might lead to suboptimal bucket boundaries for duration metrics.

Add explicit bucket configuration for consistency:

 @staticmethod
 def get_llm_operation_duration_view():
-    from opentelemetry.sdk.metrics.view import View
+    from opentelemetry.sdk.metrics.view import View, ExplicitBucketHistogramAggregation
 
     return View(
         instrument_name=Meters.LLM_OPERATION_DURATION,
+        aggregation=ExplicitBucketHistogramAggregation(
+            MetricBuckets.PINECONE_DB_QUERY_DURATION  # or define LLM_OPERATION_DURATION buckets
+        ),
     )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def get_llm_operation_duration_view():
from opentelemetry.sdk.metrics.view import View
return View(
instrument_name=Meters.LLM_OPERATION_DURATION,
)
@staticmethod
def get_llm_operation_duration_view():
- from opentelemetry.sdk.metrics.view import View
+ from opentelemetry.sdk.metrics.view import View, ExplicitBucketHistogramAggregation
- return View(
- instrument_name=Meters.LLM_OPERATION_DURATION,
- )
+ return View(
+ instrument_name=Meters.LLM_OPERATION_DURATION,
+ aggregation=ExplicitBucketHistogramAggregation(
+ MetricBuckets.PINECONE_DB_QUERY_DURATION # or define LLM_OPERATION_DURATION buckets
+ ),
+ )
🤖 Prompt for AI Agents
In
packages/opentelemetry-semantic-conventions-ai/opentelemetry/semconv_ai/__init__.py
around lines 400 to 405, the get_llm_operation_duration_view function returns a
View without specifying an ExplicitBucketHistogramAggregation, causing it to use
default histogram buckets. To fix this, import
ExplicitBucketHistogramAggregation and add an explicit aggregation parameter
with appropriate bucket boundaries to the View constructor, ensuring consistent
and optimal histogram bucket configuration for duration metrics.


@staticmethod
def get_db_query_duration_view():
from opentelemetry.sdk.metrics.view import View, ExplicitBucketHistogramAggregation

return View(
instrument_name=Meters.DB_QUERY_DURATION,
aggregation=ExplicitBucketHistogramAggregation(
MetricBuckets.PINECONE_DB_QUERY_DURATION
),
)
Comment on lines +413 to +416
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Reusing Pinecone duration buckets for generic DB queries may not be appropriate.

The DB_QUERY_DURATION view uses PINECONE_DB_QUERY_DURATION buckets, but different database systems may have vastly different performance characteristics. Consider defining separate buckets or using more generic duration buckets.

Consider adding generic database duration buckets:

 class MetricBuckets:
     # ... existing buckets ...
+    
+    DB_QUERY_DURATION = [
+        0.001, 0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 
+        0.75, 1.0, 2.5, 5.0, 7.5, 10.0, 30.0, 60.0
+    ]

Then update the view:

 aggregation=ExplicitBucketHistogramAggregation(
-    MetricBuckets.PINECONE_DB_QUERY_DURATION
+    MetricBuckets.DB_QUERY_DURATION
 ),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
aggregation=ExplicitBucketHistogramAggregation(
MetricBuckets.PINECONE_DB_QUERY_DURATION
),
)
# in packages/opentelemetry-semantic-conventions-ai/opentelemetry/semconv_ai/__init__.py
class MetricBuckets:
# ... existing buckets ...
# generic database query duration buckets
DB_QUERY_DURATION = [
0.001, 0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5,
0.75, 1.0, 2.5, 5.0, 7.5, 10.0, 30.0, 60.0
]
Suggested change
aggregation=ExplicitBucketHistogramAggregation(
MetricBuckets.PINECONE_DB_QUERY_DURATION
),
)
# later in the same file, update the view definition:
aggregation=ExplicitBucketHistogramAggregation(
MetricBuckets.DB_QUERY_DURATION
),
🤖 Prompt for AI Agents
In
packages/opentelemetry-semantic-conventions-ai/opentelemetry/semconv_ai/__init__.py
around lines 413 to 416, the DB_QUERY_DURATION view is using
PINECONE_DB_QUERY_DURATION buckets which are specific to Pinecone and may not
suit other databases. Define a new set of generic database duration buckets that
better represent typical DB query durations across various systems, then update
the aggregation in the view to use these new generic buckets instead of the
Pinecone-specific ones.


@staticmethod
def get_db_search_distance_view():
from opentelemetry.sdk.metrics.view import View, ExplicitBucketHistogramAggregation

return View(
instrument_name=Meters.DB_SEARCH_DISTANCE,
aggregation=ExplicitBucketHistogramAggregation(
MetricBuckets.PINECONE_DB_QUERY_SCORES
),
)
Comment on lines +424 to +427
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Reusing score buckets for distance metrics may be semantically incorrect.

Distance metrics often have different ranges and semantics than similarity scores. For example, Euclidean distance is typically non-negative and unbounded, while cosine similarity is bounded [-1, 1].

Consider defining separate buckets for distance metrics:

 class MetricBuckets:
     # ... existing buckets ...
+    
+    DB_SEARCH_DISTANCE = [
+        0, 0.1, 0.25, 0.5, 0.75, 1.0, 1.5, 2.0, 3.0, 5.0, 10.0, 25.0, 50.0, 100.0
+    ]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
aggregation=ExplicitBucketHistogramAggregation(
MetricBuckets.PINECONE_DB_QUERY_SCORES
),
)
class MetricBuckets:
# ... existing buckets ...
DB_SEARCH_DISTANCE = [
0, 0.1, 0.25, 0.5, 0.75, 1.0, 1.5, 2.0, 3.0, 5.0, 10.0, 25.0, 50.0, 100.0
]
🤖 Prompt for AI Agents
In
packages/opentelemetry-semantic-conventions-ai/opentelemetry/semconv_ai/__init__.py
around lines 424 to 427, the code reuses score buckets designed for similarity
scores in distance metric aggregations, which is semantically incorrect due to
differing value ranges. Define and use a separate set of metric buckets
specifically tailored for distance metrics, ensuring the bucket ranges align
with the expected value domain of the distance metric being measured.


@staticmethod
def get_all_genai_views():
return [
MetricViewsBuilder.get_llm_token_usage_view(),
MetricViewsBuilder.get_pinecone_query_duration_view(),
MetricViewsBuilder.get_pinecone_query_scores_view(),
MetricViewsBuilder.get_llm_operation_duration_view(),
MetricViewsBuilder.get_db_query_duration_view(),
MetricViewsBuilder.get_db_search_distance_view(),
]


def apply_genai_bucket_configuration():
"""Apply GenAI bucket configuration to the global MeterProvider."""
try:
from opentelemetry import metrics
from opentelemetry.sdk.metrics import MeterProvider

current_provider = metrics.get_meter_provider()

if hasattr(current_provider, '_genai_buckets_applied'):
return
Comment on lines +449 to +450
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Thread safety concern with provider modification.

The flag _genai_buckets_applied is checked and set without synchronization, which could lead to race conditions in multi-threaded applications where multiple threads might simultaneously call this function.

Add thread synchronization:

+import threading
+
+_config_lock = threading.Lock()
+
 def apply_genai_bucket_configuration():
     """Apply GenAI bucket configuration to the global MeterProvider."""
+    with _config_lock:
         try:
             # ... rest of the function
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if hasattr(current_provider, '_genai_buckets_applied'):
return
import threading
_config_lock = threading.Lock()
def apply_genai_bucket_configuration():
"""Apply GenAI bucket configuration to the global MeterProvider."""
with _config_lock:
try:
if hasattr(current_provider, '_genai_buckets_applied'):
return
# ... rest of the function
🤖 Prompt for AI Agents
In
packages/opentelemetry-semantic-conventions-ai/opentelemetry/semconv_ai/__init__.py
around lines 449 to 450, the check and setting of the _genai_buckets_applied
flag on current_provider is not thread-safe, risking race conditions. To fix
this, introduce a threading lock to synchronize access to this flag, ensuring
that only one thread can check and set it at a time. Use a global or
module-level lock object and acquire it before checking or setting the flag,
then release it afterward.


genai_views = MetricViewsBuilder.get_all_genai_views()
provider_type = str(type(current_provider))

if ('NoOp' in provider_type or 'Proxy' in provider_type or
not hasattr(current_provider, '__module__') or
current_provider.__class__.__name__ == 'ProxyMeterProvider'):
new_provider = MeterProvider(views=genai_views)
new_provider._genai_buckets_applied = True
metrics.set_meter_provider(new_provider)
Comment on lines +455 to +460
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Provider detection logic may be fragile.

The string-based detection using 'NoOp' in provider_type and 'Proxy' in provider_type is brittle and could break with OpenTelemetry SDK updates or custom provider implementations.

Use more robust type checking:

-        if ('NoOp' in provider_type or 'Proxy' in provider_type or
-                not hasattr(current_provider, '__module__') or
-                current_provider.__class__.__name__ == 'ProxyMeterProvider'):
+        from opentelemetry.metrics import NoOpMeterProvider
+        from opentelemetry.metrics._internal import ProxyMeterProvider
+        
+        if (isinstance(current_provider, (NoOpMeterProvider, ProxyMeterProvider)) or
+                not hasattr(current_provider, '_all_metric_readers')):
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if ('NoOp' in provider_type or 'Proxy' in provider_type or
not hasattr(current_provider, '__module__') or
current_provider.__class__.__name__ == 'ProxyMeterProvider'):
new_provider = MeterProvider(views=genai_views)
new_provider._genai_buckets_applied = True
metrics.set_meter_provider(new_provider)
from opentelemetry.metrics import NoOpMeterProvider
from opentelemetry.metrics._internal import ProxyMeterProvider
if (isinstance(current_provider, (NoOpMeterProvider, ProxyMeterProvider)) or
not hasattr(current_provider, '_all_metric_readers')):
new_provider = MeterProvider(views=genai_views)
new_provider._genai_buckets_applied = True
metrics.set_meter_provider(new_provider)
🤖 Prompt for AI Agents
In
packages/opentelemetry-semantic-conventions-ai/opentelemetry/semconv_ai/__init__.py
around lines 455 to 460, the current provider detection uses fragile string
checks like 'NoOp' in provider_type and 'Proxy' in provider_type. Replace these
with robust type checking by importing and using the actual NoOpMeterProvider
and ProxyMeterProvider classes from the OpenTelemetry SDK and checking if
current_provider is an instance of these classes using isinstance(). This will
make the detection more reliable against SDK changes or custom implementations.


else:
existing_readers = []

if hasattr(current_provider, '_all_metric_readers'):
old_readers = list(getattr(current_provider, '_all_metric_readers', []))

for old_reader in old_readers:
try:
if hasattr(old_reader, '_exporter') and hasattr(old_reader, '_export_interval_millis'):
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
new_reader = PeriodicExportingMetricReader(
exporter=old_reader._exporter,
export_interval_millis=old_reader._export_interval_millis
)
existing_readers.append(new_reader)
except Exception:
pass
Comment on lines +477 to +478
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Silent exception handling may hide important errors.

The bare except Exception: pass blocks suppress all exceptions, which could hide configuration errors, import issues, or other problems that should be logged or handled appropriately.

Add proper error handling and logging:

+import logging
+
+logger = logging.getLogger(__name__)
+
                     except Exception as e:
-                        pass
+                        logger.debug(f"Failed to recreate metric reader: {e}")
+                        continue

Apply similar changes to other exception blocks.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
packages/opentelemetry-semantic-conventions-ai/opentelemetry/semconv_ai/__init__.py
around lines 477 to 478, the bare except Exception: pass block silently
suppresses all exceptions, potentially hiding important errors. Modify this
block to catch the exception, log the error details using an appropriate logger
or print statement, and handle the error properly instead of passing silently.
Apply similar error handling and logging improvements to other bare except
blocks in the file.

try:
new_provider = MeterProvider(
views=genai_views,
metric_readers=existing_readers
)
new_provider._genai_buckets_applied = True

import opentelemetry.metrics._internal as metrics_internal
metrics_internal._METER_PROVIDER = new_provider
Comment on lines +486 to +487
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Direct manipulation of internal OpenTelemetry state is risky.

Directly setting metrics_internal._METER_PROVIDER bypasses the official API and could break with future OpenTelemetry versions or cause unexpected behavior.

Use the official API instead:

-                import opentelemetry.metrics._internal as metrics_internal
-                metrics_internal._METER_PROVIDER = new_provider
+                metrics.set_meter_provider(new_provider)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import opentelemetry.metrics._internal as metrics_internal
metrics_internal._METER_PROVIDER = new_provider
@@ -486,2 +486,1 @@
- import opentelemetry.metrics._internal as metrics_internal
- metrics_internal._METER_PROVIDER = new_provider
+ metrics.set_meter_provider(new_provider)
🤖 Prompt for AI Agents
In
packages/opentelemetry-semantic-conventions-ai/opentelemetry/semconv_ai/__init__.py
at lines 486-487, avoid directly setting the internal variable
metrics_internal._METER_PROVIDER as it bypasses the official API and risks
future compatibility. Instead, replace this direct assignment with calls to the
official OpenTelemetry API for setting or updating the meter provider, ensuring
you use the supported methods to configure the meter provider safely.

except Exception:
current_provider._genai_buckets_applied = True
except (ImportError, Exception):
pass
Loading