3939)
4040from opentelemetry .semconv .attributes import error_attributes
4141
42+ from .allowlist_util import AllowList
4243from .custom_semconv import CUSTOM_LLM_REQUEST_PREFIX
4344from .dict_util import flatten_dict
4445from .flags import is_content_recording_enabled
@@ -140,7 +141,7 @@ def _to_dict(value: object):
140141
141142
142143def _add_request_options_to_span (
143- span , config : Optional [GenerateContentConfigOrDict ]
144+ span , config : Optional [GenerateContentConfigOrDict ], allow_list : AllowList
144145):
145146 if config is None :
146147 return
@@ -152,7 +153,9 @@ def _add_request_options_to_span(
152153 # Automatically derive attributes from the contents of the
153154 # config object. This ensures that all relevant parameters
154155 # are captured in the telemetry data (except for those
155- # that are excluded via "exclude_keys").
156+ # that are excluded via "exclude_keys"). Dynamic attributes (those
157+ # starting with "gcp.gen_ai." instead of simply "gen_ai.request.")
158+ # are filtered with the "allow_list" before inclusion in the span.
156159 attributes = flatten_dict (
157160 _to_dict (config ),
158161 # A custom prefix is used, because the names/structure of the
@@ -162,9 +165,6 @@ def _add_request_options_to_span(
162165 # System instruction can be overly long for a span attribute.
163166 # Additionally, it is recorded as an event (log), instead.
164167 "gcp.gen_ai.request.system_instruction" ,
165- # Headers could include sensitive information, therefore it is
166- # best that we not record these options.
167- "gcp.gen_ai.request.http_options.headers" ,
168168 ],
169169 # Although a custom prefix is used by default, some of the attributes
170170 # are captured in common, standard, Semantic Conventions. For the
@@ -184,7 +184,11 @@ def _add_request_options_to_span(
184184 "gcp.gen_ai.request.seed" : gen_ai_attributes .GEN_AI_REQUEST_SEED ,
185185 },
186186 )
187- span .set_attributes (attributes )
187+ for key , value in attributes .items ():
188+ if key .startswith (CUSTOM_LLM_REQUEST_PREFIX ) and not allow_list .allowed (key ):
189+ # The allowlist is used to control inclusion of the dynamic keys.
190+ continue
191+ span .set_attribute (key , value )
188192
189193
190194def _get_response_property (response : GenerateContentResponse , path : str ):
@@ -206,6 +210,7 @@ def __init__(
206210 models_object : Union [Models , AsyncModels ],
207211 otel_wrapper : OTelWrapper ,
208212 model : str ,
213+ generate_content_config_key_allowlist : Optional [AllowList ] = None ,
209214 ):
210215 self ._start_time = time .time_ns ()
211216 self ._otel_wrapper = otel_wrapper
@@ -218,6 +223,7 @@ def __init__(
218223 self ._content_recording_enabled = is_content_recording_enabled ()
219224 self ._response_index = 0
220225 self ._candidate_index = 0
226+ self ._generate_content_config_key_allowlist = generate_content_config_key_allowlist or AllowList ()
221227
222228 def start_span_as_current_span (
223229 self , model_name , function_name , end_on_exit = True
@@ -240,7 +246,7 @@ def process_request(
240246 config : Optional [GenerateContentConfigOrDict ],
241247 ):
242248 span = trace .get_current_span ()
243- _add_request_options_to_span (span , config )
249+ _add_request_options_to_span (span , config , self . _generate_content_config_key_allowlist )
244250 self ._maybe_log_system_instruction (config = config )
245251 self ._maybe_log_user_prompt (contents )
246252
@@ -501,7 +507,7 @@ def _record_duration_metric(self):
501507
502508
503509def _create_instrumented_generate_content (
504- snapshot : _MethodsSnapshot , otel_wrapper : OTelWrapper
510+ snapshot : _MethodsSnapshot , otel_wrapper : OTelWrapper , generate_content_config_key_allowlist : Optional [ AllowList ] = None
505511):
506512 wrapped_func = snapshot .generate_content
507513
@@ -515,7 +521,7 @@ def instrumented_generate_content(
515521 ** kwargs : Any ,
516522 ) -> GenerateContentResponse :
517523 helper = _GenerateContentInstrumentationHelper (
518- self , otel_wrapper , model
524+ self , otel_wrapper , model , generate_content_config_key_allowlist = generate_content_config_key_allowlist ,
519525 )
520526 with helper .start_span_as_current_span (
521527 model , "google.genai.Models.generate_content"
@@ -541,7 +547,7 @@ def instrumented_generate_content(
541547
542548
543549def _create_instrumented_generate_content_stream (
544- snapshot : _MethodsSnapshot , otel_wrapper : OTelWrapper
550+ snapshot : _MethodsSnapshot , otel_wrapper : OTelWrapper , generate_content_config_key_allowlist : Optional [ AllowList ] = None
545551):
546552 wrapped_func = snapshot .generate_content_stream
547553
@@ -555,7 +561,7 @@ def instrumented_generate_content_stream(
555561 ** kwargs : Any ,
556562 ) -> Iterator [GenerateContentResponse ]:
557563 helper = _GenerateContentInstrumentationHelper (
558- self , otel_wrapper , model
564+ self , otel_wrapper , model , generate_content_config_key_allowlist = generate_content_config_key_allowlist
559565 )
560566 with helper .start_span_as_current_span (
561567 model , "google.genai.Models.generate_content_stream"
@@ -581,7 +587,7 @@ def instrumented_generate_content_stream(
581587
582588
583589def _create_instrumented_async_generate_content (
584- snapshot : _MethodsSnapshot , otel_wrapper : OTelWrapper
590+ snapshot : _MethodsSnapshot , otel_wrapper : OTelWrapper , generate_content_config_key_allowlist : Optional [ AllowList ] = None
585591):
586592 wrapped_func = snapshot .async_generate_content
587593
@@ -595,7 +601,7 @@ async def instrumented_generate_content(
595601 ** kwargs : Any ,
596602 ) -> GenerateContentResponse :
597603 helper = _GenerateContentInstrumentationHelper (
598- self , otel_wrapper , model
604+ self , otel_wrapper , model , generate_content_config_key_allowlist = generate_content_config_key_allowlist ,
599605 )
600606 with helper .start_span_as_current_span (
601607 model , "google.genai.AsyncModels.generate_content"
@@ -622,7 +628,7 @@ async def instrumented_generate_content(
622628
623629# Disabling type checking because this is not yet implemented and tested fully.
624630def _create_instrumented_async_generate_content_stream ( # type: ignore
625- snapshot : _MethodsSnapshot , otel_wrapper : OTelWrapper
631+ snapshot : _MethodsSnapshot , otel_wrapper : OTelWrapper , generate_content_config_key_allowlist : Optional [ AllowList ] = None
626632):
627633 wrapped_func = snapshot .async_generate_content_stream
628634
@@ -636,7 +642,7 @@ async def instrumented_generate_content_stream(
636642 ** kwargs : Any ,
637643 ) -> Awaitable [AsyncIterator [GenerateContentResponse ]]: # type: ignore
638644 helper = _GenerateContentInstrumentationHelper (
639- self , otel_wrapper , model
645+ self , otel_wrapper , model , generate_content_config_key_allowlist = generate_content_config_key_allowlist
640646 )
641647 with helper .start_span_as_current_span (
642648 model ,
@@ -680,20 +686,22 @@ def uninstrument_generate_content(snapshot: object):
680686 snapshot .restore ()
681687
682688
683- def instrument_generate_content (otel_wrapper : OTelWrapper ) -> object :
689+ def instrument_generate_content (
690+ otel_wrapper : OTelWrapper ,
691+ generate_content_config_key_allowlist : Optional [AllowList ]= None ) -> object :
684692 snapshot = _MethodsSnapshot ()
685693 Models .generate_content = _create_instrumented_generate_content (
686- snapshot , otel_wrapper
694+ snapshot , otel_wrapper , generate_content_config_key_allowlist = generate_content_config_key_allowlist ,
687695 )
688696 Models .generate_content_stream = (
689- _create_instrumented_generate_content_stream (snapshot , otel_wrapper )
697+ _create_instrumented_generate_content_stream (snapshot , otel_wrapper , generate_content_config_key_allowlist = generate_content_config_key_allowlist )
690698 )
691699 AsyncModels .generate_content = _create_instrumented_async_generate_content (
692- snapshot , otel_wrapper
700+ snapshot , otel_wrapper , generate_content_config_key_allowlist = generate_content_config_key_allowlist
693701 )
694702 AsyncModels .generate_content_stream = (
695703 _create_instrumented_async_generate_content_stream (
696- snapshot , otel_wrapper
704+ snapshot , otel_wrapper , generate_content_config_key_allowlist = generate_content_config_key_allowlist ,
697705 )
698706 )
699707 return snapshot
0 commit comments