17
17
18
18
class LLOHandler :
19
19
"""
20
- Utility class for handling Large Language Objects (LLO).
21
- This class identifies LLO attributes, emits them as log records, and filters
22
- them out from telemetry data.
20
+ Utility class for handling Large Language Objects (LLO) in OpenTelemetry spans.
21
+
22
+ LLOHandler performs three primary functions:
23
+ 1. Identifies Large Language Objects (LLO) content in spans
24
+ 2. Extracts and transforms these attributes into OpenTelemetry Gen AI Events
25
+ 3. Filters LLO from spans
23
26
"""
24
27
def __init__ (self , logger_provider : LoggerProvider ):
28
+ """
29
+ Initialize an LLOHandler with the specified logger provider.
30
+
31
+ Args:
32
+ logger_provider: The OpenTelemetry LoggerProvider used for emitting events.
33
+ Global LoggerProvider instance injected from our AwsOpenTelemetryConfigurator
34
+ """
25
35
self ._logger_provider = logger_provider
26
36
27
37
self ._event_logger_provider = EventLoggerProvider (logger_provider = self ._logger_provider )
@@ -35,9 +45,15 @@ def __init__(self, logger_provider: LoggerProvider):
35
45
36
46
def process_spans (self , spans : Sequence [ReadableSpan ]) -> List [ReadableSpan ]:
37
47
"""
38
- Perform LLO processing for each span:
48
+ Performs LLO processing for each span:
39
49
1. Emitting LLO attributes as Gen AI Events
40
50
2. Filtering out LLO attributes from the span
51
+
52
+ Args:
53
+ spans: A sequence of OpenTelemetry ReadableSpan objects to process
54
+
55
+ Returns:
56
+ List of processed spans with LLO attributes removed
41
57
"""
42
58
modified_spans = []
43
59
@@ -62,7 +78,15 @@ def process_spans(self, spans: Sequence[ReadableSpan]) -> List[ReadableSpan]:
62
78
63
79
def _emit_llo_attributes (self , span : ReadableSpan , attributes : Dict [str , Any ]) -> None :
64
80
"""
65
- Extract, transform, and emit LLO attributes as Gen AI Events
81
+ Collects the Gen AI Events for each LLO attribute in the span and emits them
82
+ using the event logger.
83
+
84
+ Args:
85
+ span: The source ReadableSpan that potentially contains LLO attributes
86
+ attributes: Dictionary of span attributes to process
87
+
88
+ Returns:
89
+ None: Events are emitted via the event logger
66
90
"""
67
91
all_events = []
68
92
all_events .extend (self ._extract_gen_ai_prompt_events (span , attributes ))
@@ -74,7 +98,15 @@ def _emit_llo_attributes(self, span: ReadableSpan, attributes: Dict[str, Any]) -
74
98
75
99
def _filter_attributes (self , attributes : Dict [str , Any ]) -> Dict [str , Any ]:
76
100
"""
77
- Filter out attributes that contain LLO from the span's attributes.
101
+ Filter out attributes that contain LLO from the span's attributes. This
102
+ method creates a new attributes dictionary that excludes any keys identified
103
+ as containing LLO data (based on the configured patterns).
104
+
105
+ Args:
106
+ attributes: Original dictionary of span attributes
107
+
108
+ Returns:
109
+ Dict[str, Any]: New dictionary with LLO attributes removed
78
110
"""
79
111
filtered_attributes = {}
80
112
@@ -87,7 +119,17 @@ def _filter_attributes(self, attributes: Dict[str, Any]) -> Dict[str, Any]:
87
119
88
120
def _is_llo_attribute (self , key : str ) -> bool :
89
121
"""
90
- Determine if a span attribute contains an LLO based on its key.
122
+ Determine if a span attribute contains an LLO based on its key name.
123
+
124
+ Checks if theattribute key matches any of the configured patterns:
125
+ 1. Exact math patterns (complete string equality)
126
+ 2. Regex match patterns (regular expression matching)
127
+
128
+ Args:
129
+ key: The attribute key to check
130
+
131
+ Returns:
132
+ bool: True if the key matches an LLO pattern, False otherwise
91
133
"""
92
134
return (
93
135
any (pattern == key for pattern in self ._exact_match_patterns ) or
@@ -98,14 +140,22 @@ def _is_llo_attribute(self, key: str) -> bool:
98
140
def _extract_gen_ai_prompt_events (self , span : ReadableSpan , attributes : Dict [str , Any ]) -> List [Event ]:
99
141
"""
100
142
Extract gen_ai prompt events from attributes. Each item `gen_ai.prompt.{n}.content`
101
- maps has an associated `gen_ai.prompt.{n}.role` that we map to an Event type.
143
+ maps has an associated `gen_ai.prompt.{n}.role` that determines the Event
144
+ type to be created.
102
145
103
146
`gen_ai.prompt.{n}.role`:
104
147
1. `system` -> `gen_ai.system.message` Event
105
148
2. `user` -> `gen_ai.user.message` Event
106
149
3. `assistant` -> `gen_ai.assistant.message` Event
107
- 4. `function` -> custom Event - TBD
108
- 5. `unknown` -> custom Event - TBD
150
+ 4. `function` -> `gen_ai.{gen_ai.system}.message` custom Event
151
+ 5. `unknown` -> `gen_ai.{gen_ai.system}.message` custom Event
152
+
153
+ Args:
154
+ span: The source ReadableSpan that potentially contains LLO attributes
155
+ attributes: Dictionary of span attributes to process
156
+
157
+ Returns:
158
+ List[Event]: List of OpenTelemetry Events created from prompt attributes
109
159
"""
110
160
events = []
111
161
span_ctx = span .context
@@ -180,6 +230,19 @@ def _get_gen_ai_event(
180
230
attributes ,
181
231
body
182
232
):
233
+ """
234
+ Create and return a Gen AI Event with the provided parameters.
235
+
236
+ Args:
237
+ name: The name/type of the event (e.g., gen_ai.system.message)
238
+ span_ctx: The span context to extract trace/span IDs from
239
+ timestamp: The timestamp for the event
240
+ attributes: Additional attributes to include with the event
241
+ body: The event body containing content and role information
242
+
243
+ Returns:
244
+ Event: A fully configured OpenTelemetry Gen AI Event object
245
+ """
183
246
return Event (
184
247
name = name ,
185
248
timestamp = timestamp ,
0 commit comments