3535 Error ,
3636 InputMessage ,
3737 LLMInvocation ,
38+ EmbeddingInvocation ,
3839 MessagePart ,
3940 OutputMessage ,
4041)
@@ -68,11 +69,35 @@ def _get_llm_common_attributes(
6869 }
6970
7071
72+ def _get_embedding_common_attributes (
73+ invocation : EmbeddingInvocation ,
74+ ) -> dict [str , Any ]:
75+ """Get common Embedding attributes shared by finish() and error() paths.
76+
77+ Returns a dictionary of attributes.
78+ """
79+ optional_attrs = (
80+ (server_attributes .SERVER_ADDRESS , invocation .server_address ),
81+ (server_attributes .SERVER_PORT , invocation .server_port ),
82+ )
83+
84+ return {
85+ GenAI .GEN_AI_OPERATION_NAME : invocation .operation_name ,
86+ GenAI .GEN_AI_PROVIDER_NAME : invocation .provider ,
87+ ** {key : value for key , value in optional_attrs if value is not None },
88+ }
89+
90+
7191def _get_llm_span_name (invocation : LLMInvocation ) -> str :
7292 """Get the span name for an LLM invocation."""
7393 return f"{ invocation .operation_name } { invocation .request_model } " .strip ()
7494
7595
96+ def _get_embedding_span_name (invocation : EmbeddingInvocation ) -> str :
97+ """Get the span name for an Embedding invocation."""
98+ return f"{ invocation .operation_name } { invocation .request_model } " .strip ()
99+
100+
76101def _get_llm_messages_attributes_for_span (
77102 input_messages : list [InputMessage ],
78103 output_messages : list [OutputMessage ],
@@ -192,6 +217,44 @@ def _maybe_emit_llm_event(
192217 logger .emit (event )
193218
194219
220+ def _maybe_emit_embedding_event (
221+ logger : Logger | None ,
222+ span : Span ,
223+ invocation : EmbeddingInvocation ,
224+ error : Error | None = None ,
225+ ) -> None :
226+ """Emit a gen_ai.client.inference.operation.details event to the logger.
227+
228+ This function creates a LogRecord event following the semantic convention
229+ for gen_ai.client.inference.operation.details as specified in the GenAI
230+ event semantic conventions.
231+
232+ For more details, see the semantic convention documentation:
233+ https://github.com/open-telemetry/semantic-conventions/blob/main/docs/gen-ai/gen-ai-events.md#event-eventgen_aiclientinferenceoperationdetails
234+ """
235+ if not is_experimental_mode () or not should_emit_event () or logger is None :
236+ return
237+
238+ # Build event attributes by reusing the attribute getter functions
239+ attributes : dict [str , Any ] = {}
240+ attributes .update (_get_embedding_common_attributes (invocation ))
241+ attributes .update (_get_embedding_request_attributes (invocation ))
242+ attributes .update (_get_embedding_response_attributes (invocation ))
243+
244+ # Add error.type if operation ended in error
245+ if error is not None :
246+ attributes [error_attributes .ERROR_TYPE ] = error .type .__qualname__
247+
248+ # Create and emit the event
249+ context = set_span_in_context (span , get_current ())
250+ event = LogRecord (
251+ event_name = "gen_ai.client.embedding.operation.details" ,
252+ attributes = attributes ,
253+ context = context ,
254+ )
255+ logger .emit (event )
256+
257+
195258def _apply_llm_finish_attributes (
196259 span : Span , invocation : LLMInvocation
197260) -> None :
@@ -218,6 +281,26 @@ def _apply_llm_finish_attributes(
218281 span .set_attributes (attributes )
219282
220283
284+ def _apply_embedding_finish_attributes (
285+ span : Span , invocation : EmbeddingInvocation
286+ ) -> None :
287+ """Apply attributes common to embedding finish() paths."""
288+ # Update span name
289+ span .update_name (_get_embedding_span_name (invocation ))
290+
291+ # Build all attributes by reusing the attribute getter functions
292+ attributes : dict [str , Any ] = {}
293+ attributes .update (_get_embedding_common_attributes (invocation ))
294+ attributes .update (_get_embedding_request_attributes (invocation ))
295+ attributes .update (_get_embedding_response_attributes (invocation ))
296+
297+ attributes .update (invocation .attributes )
298+
299+ # Set all attributes on the span
300+ if attributes :
301+ span .set_attributes (attributes )
302+
303+
221304def _apply_error_attributes (span : Span , error : Error ) -> None :
222305 """Apply status and error attributes common to error() paths."""
223306 span .set_status (Status (StatusCode .ERROR , error .message ))
@@ -244,6 +327,19 @@ def _get_llm_request_attributes(
244327 return {key : value for key , value in optional_attrs if value is not None }
245328
246329
330+ def _get_embedding_request_attributes (
331+ invocation : EmbeddingInvocation ,
332+ ) -> dict [str , Any ]:
333+ """Get GenAI request semantic convention attributes."""
334+ optional_attrs = (
335+ (GenAI .GEN_AI_REQUEST_MODEL , invocation .request_model ),
336+ (GenAI .GEN_AI_EMBEDDING_DIMENSION_COUNT , invocation .dimension_count ),
337+ (GenAI .GEN_AI_REQUEST_ENCODING_FORMATS , invocation .encoding_formats ),
338+ )
339+
340+ return {key : value for key , value in optional_attrs if value is not None }
341+
342+
247343def _get_llm_response_attributes (
248344 invocation : LLMInvocation ,
249345) -> dict [str , Any ]:
@@ -279,6 +375,17 @@ def _get_llm_response_attributes(
279375 return {key : value for key , value in optional_attrs if value is not None }
280376
281377
378+ def _get_embedding_response_attributes (
379+ invocation : EmbeddingInvocation ,
380+ ) -> dict [str , Any ]:
381+ """Get GenAI response semantic convention attributes."""
382+ optional_attrs = (
383+ (GenAI .GEN_AI_USAGE_INPUT_TOKENS , invocation .input_tokens ),
384+ )
385+
386+ return {key : value for key , value in optional_attrs if value is not None }
387+
388+
282389__all__ = [
283390 "_apply_llm_finish_attributes" ,
284391 "_apply_error_attributes" ,
@@ -287,4 +394,10 @@ def _get_llm_response_attributes(
287394 "_get_llm_response_attributes" ,
288395 "_get_llm_span_name" ,
289396 "_maybe_emit_llm_event" ,
397+ "_apply_embedding_finish_attributes" ,
398+ "_get_embedding_common_attributes" ,
399+ "_get_embedding_request_attributes" ,
400+ "_get_embedding_response_attributes" ,
401+ "_get_embedding_span_name" ,
402+ "_maybe_emit_embedding_event" ,
290403]
0 commit comments