Skip to content

Commit 6eacef2

Browse files
committed
copy session.id attribute to log event attributes if present
1 parent de6b6a9 commit 6eacef2

File tree

2 files changed

+93
-1
lines changed

2 files changed

+93
-1
lines changed

aws-opentelemetry-distro/src/amazon/opentelemetry/distro/llo_handler.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,14 +482,18 @@ def _emit_llo_attributes(
482482
if not event_body:
483483
return
484484

485-
# Create and emit the event
486485
timestamp = event_timestamp if event_timestamp is not None else span.end_time
487486
event_logger = self._event_logger_provider.get_event_logger(span.instrumentation_scope.name)
488487

488+
event_attributes = {}
489+
if span.attributes and "session.id" in span.attributes:
490+
event_attributes["session.id"] = span.attributes["session.id"]
491+
489492
event = Event(
490493
name=span.instrumentation_scope.name,
491494
timestamp=timestamp,
492495
body=event_body,
496+
attributes=event_attributes if event_attributes else None,
493497
trace_id=span.context.trace_id,
494498
span_id=span.context.span_id,
495499
trace_flags=span.context.trace_flags,

aws-opentelemetry-distro/tests/amazon/opentelemetry/distro/llo_handler/test_llo_handler_events.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,3 +561,91 @@ def test_emit_llo_attributes_openlit_style_events(self):
561561
self.assertEqual(len(output_messages), 1)
562562
self.assertEqual(output_messages[0]["content"], "Quantum computing is...")
563563
self.assertEqual(output_messages[0]["role"], "assistant")
564+
565+
def test_emit_llo_attributes_with_session_id(self):
566+
"""
567+
Verify session.id attribute from span is copied to event attributes when present.
568+
"""
569+
attributes = {
570+
"session.id": "test-session-123",
571+
"gen_ai.prompt": "Hello, AI",
572+
"gen_ai.completion": "Hello! How can I help you?",
573+
}
574+
575+
span = self._create_mock_span(attributes)
576+
span.end_time = 1234567899
577+
span.instrumentation_scope = MagicMock()
578+
span.instrumentation_scope.name = "test.scope"
579+
580+
self.llo_handler._emit_llo_attributes(span, attributes)
581+
582+
self.event_logger_mock.emit.assert_called_once()
583+
emitted_event = self.event_logger_mock.emit.call_args[0][0]
584+
585+
# Verify session.id was copied to event attributes
586+
self.assertIsNotNone(emitted_event.attributes)
587+
self.assertEqual(emitted_event.attributes.get("session.id"), "test-session-123")
588+
# Event class always adds event.name
589+
self.assertIn("event.name", emitted_event.attributes)
590+
591+
# Verify event body still contains LLO data
592+
event_body = emitted_event.body
593+
self.assertIn("input", event_body)
594+
self.assertIn("output", event_body)
595+
596+
def test_emit_llo_attributes_without_session_id(self):
597+
"""
598+
Verify event attributes do not contain session.id when not present in span attributes.
599+
"""
600+
attributes = {
601+
"gen_ai.prompt": "Hello, AI",
602+
"gen_ai.completion": "Hello! How can I help you?",
603+
}
604+
605+
span = self._create_mock_span(attributes)
606+
span.end_time = 1234567899
607+
span.instrumentation_scope = MagicMock()
608+
span.instrumentation_scope.name = "test.scope"
609+
610+
self.llo_handler._emit_llo_attributes(span, attributes)
611+
612+
self.event_logger_mock.emit.assert_called_once()
613+
emitted_event = self.event_logger_mock.emit.call_args[0][0]
614+
615+
# Verify session.id is not in event attributes
616+
self.assertIsNotNone(emitted_event.attributes)
617+
self.assertNotIn("session.id", emitted_event.attributes)
618+
# Event class always adds event.name
619+
self.assertIn("event.name", emitted_event.attributes)
620+
621+
def test_emit_llo_attributes_with_session_id_and_other_attributes(self):
622+
"""
623+
Verify only session.id is copied from span attributes when mixed with other attributes.
624+
"""
625+
attributes = {
626+
"session.id": "session-456",
627+
"user.id": "user-789",
628+
"gen_ai.prompt": "What's the weather?",
629+
"gen_ai.completion": "I can't check the weather.",
630+
"other.attribute": "some-value",
631+
}
632+
633+
span = self._create_mock_span(attributes)
634+
span.end_time = 1234567899
635+
span.instrumentation_scope = MagicMock()
636+
span.instrumentation_scope.name = "test.scope"
637+
638+
self.llo_handler._emit_llo_attributes(span, attributes)
639+
640+
self.event_logger_mock.emit.assert_called_once()
641+
emitted_event = self.event_logger_mock.emit.call_args[0][0]
642+
643+
# Verify only session.id was copied to event attributes (plus event.name from Event class)
644+
self.assertIsNotNone(emitted_event.attributes)
645+
self.assertEqual(emitted_event.attributes.get("session.id"), "session-456")
646+
self.assertIn("event.name", emitted_event.attributes)
647+
# Verify other span attributes were not copied
648+
self.assertNotIn("user.id", emitted_event.attributes)
649+
self.assertNotIn("other.attribute", emitted_event.attributes)
650+
self.assertNotIn("gen_ai.prompt", emitted_event.attributes)
651+
self.assertNotIn("gen_ai.completion", emitted_event.attributes)

0 commit comments

Comments
 (0)