@@ -57,6 +57,34 @@ def _apply_decorators(func, decorators):
5757 return func
5858
5959
60+ def _extract_metrics_header (metadata ):
61+ """Extract x-google-api-client header from metadata list.
62+
63+ Args:
64+ metadata (Sequence[Tuple[str, str]]): The metadata to extract from.
65+
66+ Returns:
67+ Tuple[List[Tuple[str, str]], List[str]]: A tuple containing:
68+ - A list of remaining metadata tuples.
69+ - A list of metrics header values found.
70+ """
71+ if not metadata :
72+ return [], []
73+
74+ for i , (key , val ) in enumerate (metadata ):
75+ if key == client_info .METRICS_METADATA_KEY :
76+ # Key located. Check the rest of the list for duplicate entries
77+ arbitrary_metadata = list (metadata [:i ])
78+ metric_values = [val ]
79+ for k , v in metadata [i + 1 :]:
80+ if k == client_info .METRICS_METADATA_KEY :
81+ metric_values .append (v )
82+ else :
83+ arbitrary_metadata .append ((k , v ))
84+ return arbitrary_metadata , metric_values
85+ # No key found
86+ return list (metadata ), []
87+
6088class _GapicCallable (object ):
6189 """Callable that applies retry, timeout, and metadata logic.
6290
@@ -91,17 +119,9 @@ def __init__(
91119 self ._timeout = timeout
92120 self ._compression = compression
93121 self ._metadata = metadata
94-
95- # Pre-extract the client metrics header from the initialized metadata.
96- # This avoids repeating this work on every single RPC request invocation.
97- self ._arbitrary_metadata = []
98- self ._metrics_values = ""
99- if metadata :
100- for key , val in metadata :
101- if key == client_info .METRICS_METADATA_KEY :
102- self ._metrics_values = val
103- else :
104- self ._arbitrary_metadata .append ((key , val ))
122+ # Pre-extract the x-goog-api-client header from the initialized metadata.
123+ self ._arbitrary_metadata , metric_values = _extract_metrics_header (metadata )
124+ self ._metrics_values = " " .join (metric_values ) if metric_values else ""
105125
106126 def __call__ (
107127 self , * args , timeout = DEFAULT , retry = DEFAULT , compression = DEFAULT , ** kwargs
@@ -127,23 +147,13 @@ def __call__(
127147 if self ._metadata is not None :
128148 metadata = kwargs .get ("metadata" )
129149 if not metadata :
130- # Fast path: in 99% of calls, the user did not pass any custom metadata,
131- # so we can directly assign the pre-extracted metadata and skip any merging overhead.
132150 if self ._metrics_values :
133151 kwargs ["metadata" ] = [(client_info .METRICS_METADATA_KEY , self ._metrics_values )] + self ._arbitrary_metadata
134152 else :
135153 kwargs ["metadata" ] = self ._arbitrary_metadata
136154 else :
137155 # Merge user-supplied metadata with library-supplied metadata.
138- # All keys in gRPC metadata are already lowercase.
139- metadata = list (metadata )
140- api_client_values = []
141- merged_metadata = []
142- for key , val in metadata :
143- if key == client_info .METRICS_METADATA_KEY :
144- api_client_values .append (val )
145- else :
146- merged_metadata .append ((key , val ))
156+ merged_metadata , api_client_values = _extract_metrics_header (metadata )
147157 if self ._metrics_values :
148158 api_client_values .append (self ._metrics_values )
149159 if api_client_values :
0 commit comments