diff --git a/instrumentation-genai/opentelemetry-instrumentation-google-genai/examples/manual/main.py b/instrumentation-genai/opentelemetry-instrumentation-google-genai/examples/manual/main.py index 5ba4f31c77..8b512dfd76 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-google-genai/examples/manual/main.py +++ b/instrumentation-genai/opentelemetry-instrumentation-google-genai/examples/manual/main.py @@ -22,8 +22,7 @@ import google.genai -# NOTE: OpenTelemetry Python Logs and Events APIs are in beta -from opentelemetry import _events as otel_events +# NOTE: OpenTelemetry Python Logs API is in beta from opentelemetry import _logs as otel_logs from opentelemetry import metrics as otel_metrics from opentelemetry import trace as otel_trace @@ -40,7 +39,6 @@ GoogleGenAiSdkInstrumentor, ) from opentelemetry.instrumentation.requests import RequestsInstrumentor -from opentelemetry.sdk._events import EventLoggerProvider from opentelemetry.sdk._logs import LoggerProvider from opentelemetry.sdk._logs.export import BatchLogRecordProcessor from opentelemetry.sdk.metrics import MeterProvider @@ -56,12 +54,11 @@ def setup_otel_tracing(): ) -def setup_otel_logs_and_events(): +def setup_otel_logs(): otel_logs.set_logger_provider(LoggerProvider()) otel_logs.get_logger_provider().add_log_record_processor( BatchLogRecordProcessor(OTLPLogExporter()) ) - otel_events.set_event_logger_provider(EventLoggerProvider()) def setup_otel_metrics(): @@ -77,7 +74,7 @@ def setup_otel_metrics(): def setup_opentelemetry(): setup_otel_tracing() - setup_otel_logs_and_events() + setup_otel_logs() setup_otel_metrics() diff --git a/instrumentation-genai/opentelemetry-instrumentation-google-genai/pyproject.toml b/instrumentation-genai/opentelemetry-instrumentation-google-genai/pyproject.toml index f4f91d1c90..7b5f585f5e 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-google-genai/pyproject.toml +++ b/instrumentation-genai/opentelemetry-instrumentation-google-genai/pyproject.toml @@ -37,7 +37,7 @@ classifiers = [ "Programming Language :: Python :: 3.12" ] dependencies = [ - "opentelemetry-api >=1.37, <2", + "opentelemetry-api ~=1.37", "opentelemetry-instrumentation >=0.52b1, <2", "opentelemetry-semantic-conventions >=0.52b1, <2" ] diff --git a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/CHANGELOG.md b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/CHANGELOG.md index a695620657..a88f700c36 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/CHANGELOG.md +++ b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Record prompt and completion events regardless of span sampling decision. ([#3226](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3226)) +- Migrate off the deprecated events API to use the logs API + ([#3625](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3628)) ## Version 2.1b0 (2025-01-18) diff --git a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/examples/manual/main.py b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/examples/manual/main.py index 8a1b57b181..815a98a1b7 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/examples/manual/main.py +++ b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/examples/manual/main.py @@ -3,8 +3,8 @@ from openai import OpenAI -# NOTE: OpenTelemetry Python Logs and Events APIs are in beta -from opentelemetry import _events, _logs, metrics, trace +# NOTE: OpenTelemetry Python Logs API is in beta +from opentelemetry import _logs, metrics, trace from opentelemetry.exporter.otlp.proto.grpc._log_exporter import ( OTLPLogExporter, ) @@ -15,7 +15,6 @@ OTLPSpanExporter, ) from opentelemetry.instrumentation.openai_v2 import OpenAIInstrumentor -from opentelemetry.sdk._events import EventLoggerProvider from opentelemetry.sdk._logs import LoggerProvider from opentelemetry.sdk._logs.export import BatchLogRecordProcessor from opentelemetry.sdk.metrics import MeterProvider @@ -29,12 +28,11 @@ BatchSpanProcessor(OTLPSpanExporter()) ) -# configure logging and events +# configure logging _logs.set_logger_provider(LoggerProvider()) _logs.get_logger_provider().add_log_record_processor( BatchLogRecordProcessor(OTLPLogExporter()) ) -_events.set_event_logger_provider(EventLoggerProvider()) # configure metrics metrics.set_meter_provider( diff --git a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/pyproject.toml b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/pyproject.toml index 5007bc6448..6190dd2175 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/pyproject.toml +++ b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/pyproject.toml @@ -25,9 +25,9 @@ classifiers = [ "Programming Language :: Python :: 3.13", ] dependencies = [ - "opentelemetry-api ~= 1.30", - "opentelemetry-instrumentation ~= 0.51b0", - "opentelemetry-semantic-conventions ~= 0.51b0" + "opentelemetry-api ~= 1.37", + "opentelemetry-instrumentation ~= 0.58b0", + "opentelemetry-semantic-conventions ~= 0.58b0" ] [project.optional-dependencies] diff --git a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/__init__.py b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/__init__.py index ab4b6f9d7b..1775b704cf 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/__init__.py +++ b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/__init__.py @@ -44,7 +44,7 @@ from wrapt import wrap_function_wrapper -from opentelemetry._events import get_event_logger +from opentelemetry._logs import get_logger from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.instrumentation.openai_v2.package import _instruments from opentelemetry.instrumentation.openai_v2.utils import is_content_enabled @@ -73,12 +73,12 @@ def _instrument(self, **kwargs): tracer_provider, schema_url=Schemas.V1_28_0.value, ) - event_logger_provider = kwargs.get("event_logger_provider") - event_logger = get_event_logger( + logger_provider = kwargs.get("logger_provider") + logger = get_logger( __name__, "", schema_url=Schemas.V1_28_0.value, - event_logger_provider=event_logger_provider, + logger_provider=logger_provider, ) meter_provider = kwargs.get("meter_provider") self._meter = get_meter( @@ -94,7 +94,7 @@ def _instrument(self, **kwargs): module="openai.resources.chat.completions", name="Completions.create", wrapper=chat_completions_create( - tracer, event_logger, instruments, is_content_enabled() + tracer, logger, instruments, is_content_enabled() ), ) @@ -102,7 +102,7 @@ def _instrument(self, **kwargs): module="openai.resources.chat.completions", name="AsyncCompletions.create", wrapper=async_chat_completions_create( - tracer, event_logger, instruments, is_content_enabled() + tracer, logger, instruments, is_content_enabled() ), ) diff --git a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/patch.py b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/patch.py index 072365abb7..fc7beb6e2c 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/patch.py +++ b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/patch.py @@ -18,7 +18,8 @@ from openai import Stream -from opentelemetry._events import Event, EventLogger +from opentelemetry._logs import Logger, LogRecord +from opentelemetry.context import get_current from opentelemetry.semconv._incubating.attributes import ( gen_ai_attributes as GenAIAttributes, ) @@ -26,6 +27,7 @@ server_attributes as ServerAttributes, ) from opentelemetry.trace import Span, SpanKind, Tracer +from opentelemetry.trace.propagation import set_span_in_context from .instruments import Instruments from .utils import ( @@ -40,7 +42,7 @@ def chat_completions_create( tracer: Tracer, - event_logger: EventLogger, + logger: Logger, instruments: Instruments, capture_content: bool, ): @@ -57,7 +59,7 @@ def traced_method(wrapped, instance, args, kwargs): end_on_exit=False, ) as span: for message in kwargs.get("messages", []): - event_logger.emit(message_to_event(message, capture_content)) + logger.emit(message_to_event(message, capture_content)) start = default_timer() result = None @@ -65,16 +67,14 @@ def traced_method(wrapped, instance, args, kwargs): try: result = wrapped(*args, **kwargs) if is_streaming(kwargs): - return StreamWrapper( - result, span, event_logger, capture_content - ) + return StreamWrapper(result, span, logger, capture_content) if span.is_recording(): _set_response_attributes( - span, result, event_logger, capture_content + span, result, logger, capture_content ) for choice in getattr(result, "choices", []): - event_logger.emit(choice_to_event(choice, capture_content)) + logger.emit(choice_to_event(choice, capture_content)) span.end() return result @@ -98,7 +98,7 @@ def traced_method(wrapped, instance, args, kwargs): def async_chat_completions_create( tracer: Tracer, - event_logger: EventLogger, + logger: Logger, instruments: Instruments, capture_content: bool, ): @@ -115,7 +115,7 @@ async def traced_method(wrapped, instance, args, kwargs): end_on_exit=False, ) as span: for message in kwargs.get("messages", []): - event_logger.emit(message_to_event(message, capture_content)) + logger.emit(message_to_event(message, capture_content)) start = default_timer() result = None @@ -123,16 +123,14 @@ async def traced_method(wrapped, instance, args, kwargs): try: result = await wrapped(*args, **kwargs) if is_streaming(kwargs): - return StreamWrapper( - result, span, event_logger, capture_content - ) + return StreamWrapper(result, span, logger, capture_content) if span.is_recording(): _set_response_attributes( - span, result, event_logger, capture_content + span, result, logger, capture_content ) for choice in getattr(result, "choices", []): - event_logger.emit(choice_to_event(choice, capture_content)) + logger.emit(choice_to_event(choice, capture_content)) span.end() return result @@ -221,7 +219,7 @@ def _record_metrics( def _set_response_attributes( - span, result, event_logger: EventLogger, capture_content: bool + span, result, logger: Logger, capture_content: bool ): set_span_attribute( span, GenAIAttributes.GEN_AI_RESPONSE_MODEL, result.model @@ -311,7 +309,7 @@ def __init__( self, stream: Stream, span: Span, - event_logger: EventLogger, + logger: Logger, capture_content: bool, ): self.stream = stream @@ -320,7 +318,7 @@ def __init__( self._span_started = False self.capture_content = capture_content - self.event_logger = event_logger + self.logger = logger self.setup() def setup(self): @@ -396,17 +394,13 @@ def cleanup(self): event_attributes = { GenAIAttributes.GEN_AI_SYSTEM: GenAIAttributes.GenAiSystemValues.OPENAI.value } - - # this span is not current, so we need to manually set the context on event - span_ctx = self.span.get_span_context() - self.event_logger.emit( - Event( - name="gen_ai.choice", + context = set_span_in_context(self.span, get_current()) + self.logger.emit( + LogRecord( + event_name="gen_ai.choice", attributes=event_attributes, body=body, - trace_id=span_ctx.trace_id, - span_id=span_ctx.span_id, - trace_flags=span_ctx.trace_flags, + context=context, ) ) diff --git a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/utils.py b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/utils.py index f8a837259e..7ff1cc509a 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/utils.py +++ b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/utils.py @@ -19,7 +19,7 @@ from httpx import URL from openai import NOT_GIVEN -from opentelemetry._events import Event +from opentelemetry._logs import LogRecord from opentelemetry.semconv._incubating.attributes import ( gen_ai_attributes as GenAIAttributes, ) @@ -123,8 +123,8 @@ def message_to_event(message, capture_content): if tool_call_id: body["id"] = tool_call_id - return Event( - name=f"gen_ai.{role}.message", + return LogRecord( + event_name=f"gen_ai.{role}.message", attributes=attributes, body=body if body else None, ) @@ -156,8 +156,8 @@ def choice_to_event(choice, capture_content): message["content"] = content body["message"] = message - return Event( - name="gen_ai.choice", + return LogRecord( + event_name="gen_ai.choice", attributes=attributes, body=body, ) diff --git a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/conftest.py b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/conftest.py index 87505046aa..83a4ba8c67 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/conftest.py +++ b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/conftest.py @@ -11,7 +11,6 @@ from opentelemetry.instrumentation.openai_v2.utils import ( OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT, ) -from opentelemetry.sdk._events import EventLoggerProvider from opentelemetry.sdk._logs import LoggerProvider from opentelemetry.sdk._logs.export import ( InMemoryLogExporter, @@ -56,13 +55,11 @@ def fixture_tracer_provider(span_exporter): return provider -@pytest.fixture(scope="function", name="event_logger_provider") -def fixture_event_logger_provider(log_exporter): +@pytest.fixture(scope="function", name="logger_provider") +def fixture_logger_provider(log_exporter): provider = LoggerProvider() provider.add_log_record_processor(SimpleLogRecordProcessor(log_exporter)) - event_logger_provider = EventLoggerProvider(provider) - - return event_logger_provider + return provider @pytest.fixture(scope="function", name="meter_provider") @@ -105,9 +102,7 @@ def vcr_config(): @pytest.fixture(scope="function") -def instrument_no_content( - tracer_provider, event_logger_provider, meter_provider -): +def instrument_no_content(tracer_provider, logger_provider, meter_provider): os.environ.update( {OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT: "False"} ) @@ -115,7 +110,7 @@ def instrument_no_content( instrumentor = OpenAIInstrumentor() instrumentor.instrument( tracer_provider=tracer_provider, - event_logger_provider=event_logger_provider, + logger_provider=logger_provider, meter_provider=meter_provider, ) @@ -125,16 +120,14 @@ def instrument_no_content( @pytest.fixture(scope="function") -def instrument_with_content( - tracer_provider, event_logger_provider, meter_provider -): +def instrument_with_content(tracer_provider, logger_provider, meter_provider): os.environ.update( {OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT: "True"} ) instrumentor = OpenAIInstrumentor() instrumentor.instrument( tracer_provider=tracer_provider, - event_logger_provider=event_logger_provider, + logger_provider=logger_provider, meter_provider=meter_provider, ) @@ -145,7 +138,7 @@ def instrument_with_content( @pytest.fixture(scope="function") def instrument_with_content_unsampled( - span_exporter, event_logger_provider, meter_provider + span_exporter, logger_provider, meter_provider ): os.environ.update( {OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT: "True"} @@ -157,7 +150,7 @@ def instrument_with_content_unsampled( instrumentor = OpenAIInstrumentor() instrumentor.instrument( tracer_provider=tracer_provider, - event_logger_provider=event_logger_provider, + logger_provider=logger_provider, meter_provider=meter_provider, ) diff --git a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/requirements.oldest.txt b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/requirements.oldest.txt index 6b46a6eaa4..774fd85ad5 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/requirements.oldest.txt +++ b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/requirements.oldest.txt @@ -26,8 +26,8 @@ pytest-vcr==1.0.2 pytest-asyncio==0.21.0 wrapt==1.16.0 opentelemetry-exporter-otlp-proto-http~=1.30 -opentelemetry-api==1.30 # when updating, also update in pyproject.toml -opentelemetry-sdk==1.30 # when updating, also update in pyproject.toml -opentelemetry-semantic-conventions==0.51b0 # when updating, also update in pyproject.toml +opentelemetry-api==1.37 # when updating, also update in pyproject.toml +opentelemetry-sdk==1.37 # when updating, also update in pyproject.toml +opentelemetry-semantic-conventions==0.58b0 # when updating, also update in pyproject.toml -e instrumentation-genai/opentelemetry-instrumentation-openai-v2 diff --git a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/test_async_chat_completions.py b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/test_async_chat_completions.py index 468caa232c..6a3d0b28d0 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/test_async_chat_completions.py +++ b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/test_async_chat_completions.py @@ -23,9 +23,6 @@ from opentelemetry.semconv._incubating.attributes import ( error_attributes as ErrorAttributes, ) -from opentelemetry.semconv._incubating.attributes import ( - event_attributes as EventAttributes, -) from opentelemetry.semconv._incubating.attributes import ( gen_ai_attributes as GenAIAttributes, ) @@ -797,7 +794,7 @@ async def async_chat_completion_multiple_tools_streaming( def assert_message_in_logs(log, event_name, expected_content, parent_span): - assert log.log_record.attributes[EventAttributes.EVENT_NAME] == event_name + assert log.log_record.event_name == event_name assert ( log.log_record.attributes[GenAIAttributes.GEN_AI_SYSTEM] == GenAIAttributes.GenAiSystemValues.OPENAI.value diff --git a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/test_chat_completions.py b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/test_chat_completions.py index 914d5b5b98..f849926e82 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/test_chat_completions.py +++ b/instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/test_chat_completions.py @@ -23,9 +23,6 @@ from opentelemetry.semconv._incubating.attributes import ( error_attributes as ErrorAttributes, ) -from opentelemetry.semconv._incubating.attributes import ( - event_attributes as EventAttributes, -) from opentelemetry.semconv._incubating.attributes import ( gen_ai_attributes as GenAIAttributes, ) @@ -812,7 +809,7 @@ def chat_completion_multiple_tools_streaming( def assert_message_in_logs(log, event_name, expected_content, parent_span): - assert log.log_record.attributes[EventAttributes.EVENT_NAME] == event_name + assert log.log_record.event_name == event_name assert ( log.log_record.attributes[GenAIAttributes.GEN_AI_SYSTEM] == GenAIAttributes.GenAiSystemValues.OPENAI.value diff --git a/instrumentation-genai/opentelemetry-instrumentation-vertexai/examples/manual/main.py b/instrumentation-genai/opentelemetry-instrumentation-vertexai/examples/manual/main.py index 5d329aad8b..bb50a666db 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-vertexai/examples/manual/main.py +++ b/instrumentation-genai/opentelemetry-instrumentation-vertexai/examples/manual/main.py @@ -3,7 +3,7 @@ from vertexai.generative_models import GenerativeModel # NOTE: OpenTelemetry Python Logs and Events APIs are in beta -from opentelemetry import _events, _logs, trace +from opentelemetry import _logs, trace from opentelemetry.exporter.otlp.proto.grpc._log_exporter import ( OTLPLogExporter, ) @@ -11,7 +11,6 @@ OTLPSpanExporter, ) from opentelemetry.instrumentation.vertexai import VertexAIInstrumentor -from opentelemetry.sdk._events import EventLoggerProvider from opentelemetry.sdk._logs import LoggerProvider from opentelemetry.sdk._logs.export import BatchLogRecordProcessor from opentelemetry.sdk.trace import TracerProvider @@ -28,7 +27,6 @@ _logs.get_logger_provider().add_log_record_processor( BatchLogRecordProcessor(OTLPLogExporter()) ) -_events.set_event_logger_provider(EventLoggerProvider()) # instrument VertexAI VertexAIInstrumentor().instrument() diff --git a/instrumentation-genai/opentelemetry-instrumentation-vertexai/pyproject.toml b/instrumentation-genai/opentelemetry-instrumentation-vertexai/pyproject.toml index ae7ee29073..3c00e8ef21 100644 --- a/instrumentation-genai/opentelemetry-instrumentation-vertexai/pyproject.toml +++ b/instrumentation-genai/opentelemetry-instrumentation-vertexai/pyproject.toml @@ -24,7 +24,7 @@ classifiers = [ "Programming Language :: Python :: 3.12", ] dependencies = [ - "opentelemetry-api >= 1.37", + "opentelemetry-api ~= 1.37", "opentelemetry-instrumentation ~= 0.58b0", # TODO https://github.com/open-telemetry/opentelemetry-python-contrib/issues/3786: restrict # version after the first release