google-cloud-spanner 3.55.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. google/cloud/spanner.py +47 -0
  2. google/cloud/spanner_admin_database_v1/__init__.py +146 -0
  3. google/cloud/spanner_admin_database_v1/gapic_metadata.json +418 -0
  4. google/cloud/spanner_admin_database_v1/gapic_version.py +16 -0
  5. google/cloud/spanner_admin_database_v1/py.typed +2 -0
  6. google/cloud/spanner_admin_database_v1/services/__init__.py +15 -0
  7. google/cloud/spanner_admin_database_v1/services/database_admin/__init__.py +22 -0
  8. google/cloud/spanner_admin_database_v1/services/database_admin/async_client.py +4097 -0
  9. google/cloud/spanner_admin_database_v1/services/database_admin/client.py +4602 -0
  10. google/cloud/spanner_admin_database_v1/services/database_admin/pagers.py +989 -0
  11. google/cloud/spanner_admin_database_v1/services/database_admin/transports/__init__.py +38 -0
  12. google/cloud/spanner_admin_database_v1/services/database_admin/transports/base.py +820 -0
  13. google/cloud/spanner_admin_database_v1/services/database_admin/transports/grpc.py +1303 -0
  14. google/cloud/spanner_admin_database_v1/services/database_admin/transports/grpc_asyncio.py +1688 -0
  15. google/cloud/spanner_admin_database_v1/services/database_admin/transports/rest.py +6512 -0
  16. google/cloud/spanner_admin_database_v1/services/database_admin/transports/rest_base.py +1650 -0
  17. google/cloud/spanner_admin_database_v1/types/__init__.py +144 -0
  18. google/cloud/spanner_admin_database_v1/types/backup.py +1106 -0
  19. google/cloud/spanner_admin_database_v1/types/backup_schedule.py +369 -0
  20. google/cloud/spanner_admin_database_v1/types/common.py +180 -0
  21. google/cloud/spanner_admin_database_v1/types/spanner_database_admin.py +1303 -0
  22. google/cloud/spanner_admin_instance_v1/__init__.py +110 -0
  23. google/cloud/spanner_admin_instance_v1/gapic_metadata.json +343 -0
  24. google/cloud/spanner_admin_instance_v1/gapic_version.py +16 -0
  25. google/cloud/spanner_admin_instance_v1/py.typed +2 -0
  26. google/cloud/spanner_admin_instance_v1/services/__init__.py +15 -0
  27. google/cloud/spanner_admin_instance_v1/services/instance_admin/__init__.py +22 -0
  28. google/cloud/spanner_admin_instance_v1/services/instance_admin/async_client.py +3466 -0
  29. google/cloud/spanner_admin_instance_v1/services/instance_admin/client.py +3881 -0
  30. google/cloud/spanner_admin_instance_v1/services/instance_admin/pagers.py +856 -0
  31. google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/__init__.py +38 -0
  32. google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/base.py +545 -0
  33. google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/grpc.py +1347 -0
  34. google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/grpc_asyncio.py +1539 -0
  35. google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/rest.py +4834 -0
  36. google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/rest_base.py +1198 -0
  37. google/cloud/spanner_admin_instance_v1/types/__init__.py +104 -0
  38. google/cloud/spanner_admin_instance_v1/types/common.py +99 -0
  39. google/cloud/spanner_admin_instance_v1/types/spanner_instance_admin.py +2375 -0
  40. google/cloud/spanner_dbapi/__init__.py +93 -0
  41. google/cloud/spanner_dbapi/_helpers.py +113 -0
  42. google/cloud/spanner_dbapi/batch_dml_executor.py +135 -0
  43. google/cloud/spanner_dbapi/checksum.py +80 -0
  44. google/cloud/spanner_dbapi/client_side_statement_executor.py +140 -0
  45. google/cloud/spanner_dbapi/client_side_statement_parser.py +106 -0
  46. google/cloud/spanner_dbapi/connection.py +818 -0
  47. google/cloud/spanner_dbapi/cursor.py +609 -0
  48. google/cloud/spanner_dbapi/exceptions.py +172 -0
  49. google/cloud/spanner_dbapi/parse_utils.py +392 -0
  50. google/cloud/spanner_dbapi/parsed_statement.py +63 -0
  51. google/cloud/spanner_dbapi/parser.py +258 -0
  52. google/cloud/spanner_dbapi/partition_helper.py +41 -0
  53. google/cloud/spanner_dbapi/transaction_helper.py +294 -0
  54. google/cloud/spanner_dbapi/types.py +106 -0
  55. google/cloud/spanner_dbapi/utils.py +147 -0
  56. google/cloud/spanner_dbapi/version.py +20 -0
  57. google/cloud/spanner_v1/__init__.py +154 -0
  58. google/cloud/spanner_v1/_helpers.py +751 -0
  59. google/cloud/spanner_v1/_opentelemetry_tracing.py +165 -0
  60. google/cloud/spanner_v1/backup.py +397 -0
  61. google/cloud/spanner_v1/batch.py +433 -0
  62. google/cloud/spanner_v1/client.py +538 -0
  63. google/cloud/spanner_v1/data_types.py +350 -0
  64. google/cloud/spanner_v1/database.py +1968 -0
  65. google/cloud/spanner_v1/database_sessions_manager.py +249 -0
  66. google/cloud/spanner_v1/gapic_metadata.json +268 -0
  67. google/cloud/spanner_v1/gapic_version.py +16 -0
  68. google/cloud/spanner_v1/instance.py +735 -0
  69. google/cloud/spanner_v1/keyset.py +193 -0
  70. google/cloud/spanner_v1/merged_result_set.py +146 -0
  71. google/cloud/spanner_v1/metrics/constants.py +71 -0
  72. google/cloud/spanner_v1/metrics/metrics_capture.py +75 -0
  73. google/cloud/spanner_v1/metrics/metrics_exporter.py +384 -0
  74. google/cloud/spanner_v1/metrics/metrics_interceptor.py +156 -0
  75. google/cloud/spanner_v1/metrics/metrics_tracer.py +588 -0
  76. google/cloud/spanner_v1/metrics/metrics_tracer_factory.py +328 -0
  77. google/cloud/spanner_v1/metrics/spanner_metrics_tracer_factory.py +172 -0
  78. google/cloud/spanner_v1/param_types.py +110 -0
  79. google/cloud/spanner_v1/pool.py +813 -0
  80. google/cloud/spanner_v1/py.typed +2 -0
  81. google/cloud/spanner_v1/request_id_header.py +64 -0
  82. google/cloud/spanner_v1/services/__init__.py +15 -0
  83. google/cloud/spanner_v1/services/spanner/__init__.py +22 -0
  84. google/cloud/spanner_v1/services/spanner/async_client.py +2205 -0
  85. google/cloud/spanner_v1/services/spanner/client.py +2624 -0
  86. google/cloud/spanner_v1/services/spanner/pagers.py +196 -0
  87. google/cloud/spanner_v1/services/spanner/transports/__init__.py +38 -0
  88. google/cloud/spanner_v1/services/spanner/transports/base.py +520 -0
  89. google/cloud/spanner_v1/services/spanner/transports/grpc.py +911 -0
  90. google/cloud/spanner_v1/services/spanner/transports/grpc_asyncio.py +1144 -0
  91. google/cloud/spanner_v1/services/spanner/transports/rest.py +3468 -0
  92. google/cloud/spanner_v1/services/spanner/transports/rest_base.py +981 -0
  93. google/cloud/spanner_v1/session.py +631 -0
  94. google/cloud/spanner_v1/session_options.py +133 -0
  95. google/cloud/spanner_v1/snapshot.py +1057 -0
  96. google/cloud/spanner_v1/streamed.py +402 -0
  97. google/cloud/spanner_v1/table.py +181 -0
  98. google/cloud/spanner_v1/testing/__init__.py +0 -0
  99. google/cloud/spanner_v1/testing/database_test.py +121 -0
  100. google/cloud/spanner_v1/testing/interceptors.py +118 -0
  101. google/cloud/spanner_v1/testing/mock_database_admin.py +38 -0
  102. google/cloud/spanner_v1/testing/mock_spanner.py +261 -0
  103. google/cloud/spanner_v1/testing/spanner_database_admin_pb2_grpc.py +1267 -0
  104. google/cloud/spanner_v1/testing/spanner_pb2_grpc.py +882 -0
  105. google/cloud/spanner_v1/transaction.py +747 -0
  106. google/cloud/spanner_v1/types/__init__.py +118 -0
  107. google/cloud/spanner_v1/types/commit_response.py +94 -0
  108. google/cloud/spanner_v1/types/keys.py +248 -0
  109. google/cloud/spanner_v1/types/mutation.py +201 -0
  110. google/cloud/spanner_v1/types/query_plan.py +220 -0
  111. google/cloud/spanner_v1/types/result_set.py +379 -0
  112. google/cloud/spanner_v1/types/spanner.py +1815 -0
  113. google/cloud/spanner_v1/types/transaction.py +818 -0
  114. google/cloud/spanner_v1/types/type.py +288 -0
  115. google_cloud_spanner-3.55.0.dist-info/LICENSE +202 -0
  116. google_cloud_spanner-3.55.0.dist-info/METADATA +318 -0
  117. google_cloud_spanner-3.55.0.dist-info/RECORD +119 -0
  118. google_cloud_spanner-3.55.0.dist-info/WHEEL +5 -0
  119. google_cloud_spanner-3.55.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,588 @@
1
+ # Copyright 2025 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """
16
+ This module contains the MetricTracer class and its related helper classes.
17
+
18
+ The MetricTracer class is responsible for collecting and tracing metrics,
19
+ while the helper classes provide additional functionality and context for the metrics being traced.
20
+ """
21
+
22
+ from datetime import datetime
23
+ from typing import Dict
24
+ from grpc import StatusCode
25
+ from .constants import (
26
+ METRIC_LABEL_KEY_CLIENT_NAME,
27
+ METRIC_LABEL_KEY_CLIENT_UID,
28
+ METRIC_LABEL_KEY_DATABASE,
29
+ METRIC_LABEL_KEY_DIRECT_PATH_ENABLED,
30
+ METRIC_LABEL_KEY_METHOD,
31
+ METRIC_LABEL_KEY_STATUS,
32
+ MONITORED_RES_LABEL_KEY_CLIENT_HASH,
33
+ MONITORED_RES_LABEL_KEY_INSTANCE,
34
+ MONITORED_RES_LABEL_KEY_INSTANCE_CONFIG,
35
+ MONITORED_RES_LABEL_KEY_LOCATION,
36
+ MONITORED_RES_LABEL_KEY_PROJECT,
37
+ )
38
+
39
+ try:
40
+ from opentelemetry.metrics import Counter, Histogram
41
+
42
+ HAS_OPENTELEMETRY_INSTALLED = True
43
+ except ImportError: # pragma: NO COVER
44
+ HAS_OPENTELEMETRY_INSTALLED = False
45
+
46
+
47
+ class MetricAttemptTracer:
48
+ """
49
+ This class is designed to hold information related to a metric attempt.
50
+
51
+ It captures the start time of the attempt, whether the direct path was used, and the status of the attempt.
52
+ """
53
+
54
+ _start_time: datetime
55
+ direct_path_used: bool
56
+ status: str
57
+
58
+ def __init__(self) -> None:
59
+ """
60
+ Initialize a MetricAttemptTracer instance with default values.
61
+
62
+ This constructor sets the start time of the metric attempt to the current datetime, initializes the status as an empty string, and sets direct path used flag to False by default.
63
+ """
64
+ self._start_time = datetime.now()
65
+ self.status = ""
66
+ self.direct_path_used = False
67
+
68
+ @property
69
+ def start_time(self):
70
+ """Getter method for the start_time property.
71
+
72
+ This method returns the start time of the metric attempt.
73
+
74
+ Returns:
75
+ datetime: The start time of the metric attempt.
76
+ """
77
+ return self._start_time
78
+
79
+
80
+ class MetricOpTracer:
81
+ """
82
+ This class is designed to store and manage information related to metric operations.
83
+ It captures the method name, start time, attempt count, current attempt, status, and direct path enabled status of a metric operation.
84
+ """
85
+
86
+ _attempt_count: int
87
+ _start_time: datetime
88
+ _current_attempt: MetricAttemptTracer
89
+ status: str
90
+
91
+ def __init__(self, is_direct_path_enabled: bool = False):
92
+ """
93
+ Initialize a MetricOpTracer instance with the given parameters.
94
+
95
+ This constructor sets up a MetricOpTracer instance with the provided instrumentations for attempt latency,
96
+ attempt counter, operation latency and operation counter.
97
+
98
+ Args:
99
+ instrument_attempt_latency (Histogram): The instrumentation for measuring attempt latency.
100
+ instrument_attempt_counter (Counter): The instrumentation for counting attempts.
101
+ instrument_operation_latency (Histogram): The instrumentation for measuring operation latency.
102
+ instrument_operation_counter (Counter): The instrumentation for counting operations.
103
+ """
104
+ self._attempt_count = 0
105
+ self._start_time = datetime.now()
106
+ self._current_attempt = None
107
+ self.status = ""
108
+
109
+ @property
110
+ def attempt_count(self):
111
+ """
112
+ Getter method for the attempt_count property.
113
+
114
+ This method returns the current count of attempts made for the metric operation.
115
+
116
+ Returns:
117
+ int: The current count of attempts.
118
+ """
119
+ return self._attempt_count
120
+
121
+ @property
122
+ def current_attempt(self):
123
+ """
124
+ Getter method for the current_attempt property.
125
+
126
+ This method returns the current MetricAttemptTracer instance associated with the metric operation.
127
+
128
+ Returns:
129
+ MetricAttemptTracer: The current MetricAttemptTracer instance.
130
+ """
131
+ return self._current_attempt
132
+
133
+ @property
134
+ def start_time(self):
135
+ """
136
+ Getter method for the start_time property.
137
+
138
+ This method returns the start time of the metric operation.
139
+
140
+ Returns:
141
+ datetime: The start time of the metric operation.
142
+ """
143
+ return self._start_time
144
+
145
+ def increment_attempt_count(self):
146
+ """
147
+ Increments the attempt count by 1.
148
+
149
+ This method updates the attempt count by incrementing it by 1, indicating a new attempt has been made.
150
+ """
151
+ self._attempt_count += 1
152
+
153
+ def start(self):
154
+ """
155
+ Set the start time of the metric operation to the current time.
156
+
157
+ This method updates the start time of the metric operation to the current time, indicating the operation has started.
158
+ """
159
+ self._start_time = datetime.now()
160
+
161
+ def new_attempt(self):
162
+ """
163
+ Initialize a new MetricAttemptTracer instance for the current metric operation.
164
+
165
+ This method sets up a new MetricAttemptTracer instance, indicating a new attempt is being made within the metric operation.
166
+ """
167
+ self._current_attempt = MetricAttemptTracer()
168
+
169
+
170
+ class MetricsTracer:
171
+ """
172
+ This class computes generic metrics that can be observed in the lifecycle of an RPC operation.
173
+
174
+ The responsibility of recording metrics should delegate to MetricsRecorder, hence this
175
+ class should not have any knowledge about the observability framework used for metrics recording.
176
+ """
177
+
178
+ _client_attributes: Dict[str, str]
179
+ _instrument_attempt_counter: "Counter"
180
+ _instrument_attempt_latency: "Histogram"
181
+ _instrument_operation_counter: "Counter"
182
+ _instrument_operation_latency: "Histogram"
183
+ _instrument_gfe_latency: "Histogram"
184
+ _instrument_gfe_missing_header_count: "Counter"
185
+ current_op: MetricOpTracer
186
+ enabled: bool
187
+ gfe_enabled: bool
188
+ method: str
189
+
190
+ def __init__(
191
+ self,
192
+ enabled: bool,
193
+ instrument_attempt_latency: "Histogram",
194
+ instrument_attempt_counter: "Counter",
195
+ instrument_operation_latency: "Histogram",
196
+ instrument_operation_counter: "Counter",
197
+ client_attributes: Dict[str, str],
198
+ gfe_enabled: bool = False,
199
+ ):
200
+ """
201
+ Initialize a MetricsTracer instance with the given parameters.
202
+
203
+ This constructor sets up a MetricsTracer instance with the specified parameters, including the enabled status,
204
+ instruments for measuring and counting attempt and operation metrics, and client attributes. It prepares the
205
+ infrastructure needed for recording metrics related to RPC operations.
206
+
207
+ Args:
208
+ enabled (bool): Indicates if metrics tracing is enabled.
209
+ instrument_attempt_latency (Histogram): Instrument for measuring attempt latency.
210
+ instrument_attempt_counter (Counter): Instrument for counting attempts.
211
+ instrument_operation_latency (Histogram): Instrument for measuring operation latency.
212
+ instrument_operation_counter (Counter): Instrument for counting operations.
213
+ client_attributes (Dict[str, str]): Dictionary of client attributes used for metrics tracing.
214
+ gfe_enabled (bool, optional): Indicates if GFE metrics are enabled. Defaults to False.
215
+ """
216
+ self.current_op = MetricOpTracer()
217
+ self._client_attributes = client_attributes
218
+ self._instrument_attempt_latency = instrument_attempt_latency
219
+ self._instrument_attempt_counter = instrument_attempt_counter
220
+ self._instrument_operation_latency = instrument_operation_latency
221
+ self._instrument_operation_counter = instrument_operation_counter
222
+ self.enabled = enabled
223
+ self.gfe_enabled = gfe_enabled
224
+
225
+ @staticmethod
226
+ def _get_ms_time_diff(start: datetime, end: datetime) -> float:
227
+ """
228
+ Calculate the time difference in milliseconds between two datetime objects.
229
+
230
+ This method calculates the time difference between two datetime objects and returns the result in milliseconds.
231
+ This is useful for measuring the duration of operations or attempts for metrics tracing.
232
+ Note: total_seconds() returns a float value of seconds.
233
+
234
+ Args:
235
+ start (datetime): The start datetime.
236
+ end (datetime): The end datetime.
237
+
238
+ Returns:
239
+ float: The time difference in milliseconds.
240
+ """
241
+ time_delta = end - start
242
+ return time_delta.total_seconds() * 1000
243
+
244
+ @property
245
+ def client_attributes(self) -> Dict[str, str]:
246
+ """
247
+ Return a dictionary of client attributes used for metrics tracing.
248
+
249
+ This property returns a dictionary containing client attributes such as project, instance,
250
+ instance configuration, location, client hash, client UID, client name, and database.
251
+ These attributes are used to provide context to the metrics being traced.
252
+
253
+ Returns:
254
+ dict[str, str]: A dictionary of client attributes.
255
+ """
256
+ return self._client_attributes
257
+
258
+ @property
259
+ def instrument_attempt_counter(self) -> "Counter":
260
+ """
261
+ Return the instrument for counting attempts.
262
+
263
+ This property returns the Counter instrument used to count the number of attempts made during RPC operations.
264
+ This metric is useful for tracking the frequency of attempts and can help identify patterns or issues in the operation flow.
265
+
266
+ Returns:
267
+ Counter: The instrument for counting attempts.
268
+ """
269
+ return self._instrument_attempt_counter
270
+
271
+ @property
272
+ def instrument_attempt_latency(self) -> "Histogram":
273
+ """
274
+ Return the instrument for measuring attempt latency.
275
+
276
+ This property returns the Histogram instrument used to measure the latency of individual attempts.
277
+ This metric is useful for tracking the performance of attempts and can help identify bottlenecks or issues in the operation flow.
278
+
279
+ Returns:
280
+ Histogram: The instrument for measuring attempt latency.
281
+ """
282
+ return self._instrument_attempt_latency
283
+
284
+ @property
285
+ def instrument_operation_counter(self) -> "Counter":
286
+ """
287
+ Return the instrument for counting operations.
288
+
289
+ This property returns the Counter instrument used to count the number of operations made during RPC operations.
290
+ This metric is useful for tracking the frequency of operations and can help identify patterns or issues in the operation flow.
291
+
292
+ Returns:
293
+ Counter: The instrument for counting operations.
294
+ """
295
+ return self._instrument_operation_counter
296
+
297
+ @property
298
+ def instrument_operation_latency(self) -> "Histogram":
299
+ """
300
+ Return the instrument for measuring operation latency.
301
+
302
+ This property returns the Histogram instrument used to measure the latency of operations.
303
+ This metric is useful for tracking the performance of operations and can help identify bottlenecks or issues in the operation flow.
304
+
305
+ Returns:
306
+ Histogram: The instrument for measuring operation latency.
307
+ """
308
+ return self._instrument_operation_latency
309
+
310
+ def record_attempt_start(self) -> None:
311
+ """
312
+ Record the start of a new attempt within the current operation.
313
+
314
+ This method increments the attempt count for the current operation and marks the start of a new attempt.
315
+ It is used to track the number of attempts made during an operation and to identify the start of each attempt for metrics and tracing purposes.
316
+ """
317
+ self.current_op.increment_attempt_count()
318
+ self.current_op.new_attempt()
319
+
320
+ def record_attempt_completion(self, status: str = StatusCode.OK.name) -> None:
321
+ """
322
+ Record the completion of an attempt within the current operation.
323
+
324
+ This method updates the status of the current attempt to indicate its completion and records the latency of the attempt.
325
+ It calculates the elapsed time since the attempt started and uses this value to record the attempt latency metric.
326
+ This metric is useful for tracking the performance of individual attempts and can help identify bottlenecks or issues in the operation flow.
327
+
328
+ If metrics tracing is not enabled, this method does not perform any operations.
329
+ """
330
+ if not self.enabled or not HAS_OPENTELEMETRY_INSTALLED:
331
+ return
332
+ self.current_op.current_attempt.status = status
333
+
334
+ # Build Attributes
335
+ attempt_attributes = self._create_attempt_otel_attributes()
336
+
337
+ # Calculate elapsed time
338
+ attempt_latency_ms = self._get_ms_time_diff(
339
+ start=self.current_op.current_attempt.start_time, end=datetime.now()
340
+ )
341
+
342
+ # Record attempt latency
343
+ self.instrument_attempt_latency.record(
344
+ amount=attempt_latency_ms, attributes=attempt_attributes
345
+ )
346
+
347
+ def record_operation_start(self) -> None:
348
+ """
349
+ Record the start of a new operation.
350
+
351
+ This method marks the beginning of a new operation and initializes the operation's metrics tracking.
352
+ It is used to track the start time of an operation, which is essential for calculating operation latency and other metrics.
353
+ If metrics tracing is not enabled, this method does not perform any operations.
354
+ """
355
+ if not self.enabled or not HAS_OPENTELEMETRY_INSTALLED:
356
+ return
357
+ self.current_op.start()
358
+
359
+ def record_operation_completion(self) -> None:
360
+ """
361
+ Record the completion of an operation.
362
+
363
+ This method marks the end of an operation and updates the metrics accordingly.
364
+ It calculates the operation latency by measuring the time elapsed since the operation started and records this metric.
365
+ Additionally, it increments the operation count and records the attempt count for the operation.
366
+ If metrics tracing is not enabled, this method does not perform any operations.
367
+ """
368
+ if not self.enabled or not HAS_OPENTELEMETRY_INSTALLED:
369
+ return
370
+ end_time = datetime.now()
371
+ # Build Attributes
372
+ operation_attributes = self._create_operation_otel_attributes()
373
+ attempt_attributes = self._create_attempt_otel_attributes()
374
+
375
+ # Calculate elapsed time
376
+ operation_latency_ms = self._get_ms_time_diff(
377
+ start=self.current_op.start_time, end=end_time
378
+ )
379
+
380
+ # Increase operation count
381
+ self.instrument_operation_counter.add(amount=1, attributes=operation_attributes)
382
+
383
+ # Record operation latency
384
+ self.instrument_operation_latency.record(
385
+ amount=operation_latency_ms, attributes=operation_attributes
386
+ )
387
+
388
+ # Record Attempt Count
389
+ self.instrument_attempt_counter.add(
390
+ self.current_op.attempt_count, attributes=attempt_attributes
391
+ )
392
+
393
+ def record_gfe_latency(self, latency: int) -> None:
394
+ """
395
+ Records the GFE latency using the Histogram instrument.
396
+
397
+ Args:
398
+ latency (int): The latency duration to be recorded.
399
+ """
400
+ if not self.enabled or not HAS_OPENTELEMETRY_INSTALLED or not self.gfe_enabled:
401
+ return
402
+ self._instrument_gfe_latency.record(
403
+ amount=latency, attributes=self.client_attributes
404
+ )
405
+
406
+ def record_gfe_missing_header_count(self) -> None:
407
+ """
408
+ Increments the counter for missing GFE headers.
409
+ """
410
+ if not self.enabled or not HAS_OPENTELEMETRY_INSTALLED or not self.gfe_enabled:
411
+ return
412
+ self._instrument_gfe_missing_header_count.add(
413
+ amount=1, attributes=self.client_attributes
414
+ )
415
+
416
+ def _create_operation_otel_attributes(self) -> dict:
417
+ """
418
+ Create additional attributes for operation metrics tracing.
419
+
420
+ This method populates the client attributes dictionary with the operation status if metrics tracing is enabled.
421
+ It returns the updated client attributes dictionary.
422
+ """
423
+ if not self.enabled or not HAS_OPENTELEMETRY_INSTALLED:
424
+ return {}
425
+ attributes = self._client_attributes.copy()
426
+ attributes[METRIC_LABEL_KEY_STATUS] = self.current_op.status
427
+ return attributes
428
+
429
+ def _create_attempt_otel_attributes(self) -> dict:
430
+ """
431
+ Create additional attributes for attempt metrics tracing.
432
+
433
+ This method populates the attributes dictionary with the attempt status if metrics tracing is enabled and an attempt exists.
434
+ It returns the updated attributes dictionary.
435
+ """
436
+ if not self.enabled or not HAS_OPENTELEMETRY_INSTALLED:
437
+ return {}
438
+
439
+ attributes = self._client_attributes.copy()
440
+
441
+ # Short circuit out if we don't have an attempt
442
+ if self.current_op.current_attempt is None:
443
+ return attributes
444
+
445
+ attributes[METRIC_LABEL_KEY_STATUS] = self.current_op.current_attempt.status
446
+ return attributes
447
+
448
+ def set_project(self, project: str) -> "MetricsTracer":
449
+ """
450
+ Set the project attribute for metrics tracing.
451
+
452
+ This method updates the project attribute in the client attributes dictionary for metrics tracing purposes.
453
+ If the project attribute already has a value, this method does nothing and returns.
454
+
455
+ :param project: The project name to set.
456
+ :return: This instance of MetricsTracer for method chaining.
457
+ """
458
+ if MONITORED_RES_LABEL_KEY_PROJECT not in self._client_attributes:
459
+ self._client_attributes[MONITORED_RES_LABEL_KEY_PROJECT] = project
460
+ return self
461
+
462
+ def set_instance(self, instance: str) -> "MetricsTracer":
463
+ """
464
+ Set the instance attribute for metrics tracing.
465
+
466
+ This method updates the instance attribute in the client attributes dictionary for metrics tracing purposes.
467
+ If the instance attribute already has a value, this method does nothing and returns.
468
+
469
+ :param instance: The instance name to set.
470
+ :return: This instance of MetricsTracer for method chaining.
471
+ """
472
+ if MONITORED_RES_LABEL_KEY_INSTANCE not in self._client_attributes:
473
+ self._client_attributes[MONITORED_RES_LABEL_KEY_INSTANCE] = instance
474
+ return self
475
+
476
+ def set_instance_config(self, instance_config: str) -> "MetricsTracer":
477
+ """
478
+ Set the instance configuration attribute for metrics tracing.
479
+
480
+ This method updates the instance configuration attribute in the client attributes dictionary for metrics tracing purposes.
481
+ If the instance configuration attribute already has a value, this method does nothing and returns.
482
+
483
+ :param instance_config: The instance configuration name to set.
484
+ :return: This instance of MetricsTracer for method chaining.
485
+ """
486
+ if MONITORED_RES_LABEL_KEY_INSTANCE_CONFIG not in self._client_attributes:
487
+ self._client_attributes[
488
+ MONITORED_RES_LABEL_KEY_INSTANCE_CONFIG
489
+ ] = instance_config
490
+ return self
491
+
492
+ def set_location(self, location: str) -> "MetricsTracer":
493
+ """
494
+ Set the location attribute for metrics tracing.
495
+
496
+ This method updates the location attribute in the client attributes dictionary for metrics tracing purposes.
497
+ If the location attribute already has a value, this method does nothing and returns.
498
+
499
+ :param location: The location name to set.
500
+ :return: This instance of MetricsTracer for method chaining.
501
+ """
502
+ if MONITORED_RES_LABEL_KEY_LOCATION not in self._client_attributes:
503
+ self._client_attributes[MONITORED_RES_LABEL_KEY_LOCATION] = location
504
+ return self
505
+
506
+ def set_client_hash(self, hash: str) -> "MetricsTracer":
507
+ """
508
+ Set the client hash attribute for metrics tracing.
509
+
510
+ This method updates the client hash attribute in the client attributes dictionary for metrics tracing purposes.
511
+ If the client hash attribute already has a value, this method does nothing and returns.
512
+
513
+ :param hash: The client hash to set.
514
+ :return: This instance of MetricsTracer for method chaining.
515
+ """
516
+ if MONITORED_RES_LABEL_KEY_CLIENT_HASH not in self._client_attributes:
517
+ self._client_attributes[MONITORED_RES_LABEL_KEY_CLIENT_HASH] = hash
518
+ return self
519
+
520
+ def set_client_uid(self, client_uid: str) -> "MetricsTracer":
521
+ """
522
+ Set the client UID attribute for metrics tracing.
523
+
524
+ This method updates the client UID attribute in the client attributes dictionary for metrics tracing purposes.
525
+ If the client UID attribute already has a value, this method does nothing and returns.
526
+
527
+ :param client_uid: The client UID to set.
528
+ :return: This instance of MetricsTracer for method chaining.
529
+ """
530
+ if METRIC_LABEL_KEY_CLIENT_UID not in self._client_attributes:
531
+ self._client_attributes[METRIC_LABEL_KEY_CLIENT_UID] = client_uid
532
+ return self
533
+
534
+ def set_client_name(self, client_name: str) -> "MetricsTracer":
535
+ """
536
+ Set the client name attribute for metrics tracing.
537
+
538
+ This method updates the client name attribute in the client attributes dictionary for metrics tracing purposes.
539
+ If the client name attribute already has a value, this method does nothing and returns.
540
+
541
+ :param client_name: The client name to set.
542
+ :return: This instance of MetricsTracer for method chaining.
543
+ """
544
+ if METRIC_LABEL_KEY_CLIENT_NAME not in self._client_attributes:
545
+ self._client_attributes[METRIC_LABEL_KEY_CLIENT_NAME] = client_name
546
+ return self
547
+
548
+ def set_database(self, database: str) -> "MetricsTracer":
549
+ """
550
+ Set the database attribute for metrics tracing.
551
+
552
+ This method updates the database attribute in the client attributes dictionary for metrics tracing purposes.
553
+ If the database attribute already has a value, this method does nothing and returns.
554
+
555
+ :param database: The database name to set.
556
+ :return: This instance of MetricsTracer for method chaining.
557
+ """
558
+ if METRIC_LABEL_KEY_DATABASE not in self._client_attributes:
559
+ self._client_attributes[METRIC_LABEL_KEY_DATABASE] = database
560
+ return self
561
+
562
+ def set_method(self, method: str) -> "MetricsTracer":
563
+ """
564
+ Set the method attribute for metrics tracing.
565
+
566
+ This method updates the method attribute in the client attributes dictionary for metrics tracing purposes.
567
+ If the database attribute already has a value, this method does nothing and returns.
568
+
569
+ :param method: The method name to set.
570
+ :return: This instance of MetricsTracer for method chaining.
571
+ """
572
+ if METRIC_LABEL_KEY_METHOD not in self._client_attributes:
573
+ self.client_attributes[METRIC_LABEL_KEY_METHOD] = method
574
+ return self
575
+
576
+ def enable_direct_path(self, enable: bool = False) -> "MetricsTracer":
577
+ """
578
+ Enable or disable the direct path for metrics tracing.
579
+
580
+ This method updates the direct path enabled attribute in the client attributes dictionary for metrics tracing purposes.
581
+ If the direct path enabled attribute already has a value, this method does nothing and returns.
582
+
583
+ :param enable: Boolean indicating whether to enable the direct path.
584
+ :return: This instance of MetricsTracer for method chaining.
585
+ """
586
+ if METRIC_LABEL_KEY_DIRECT_PATH_ENABLED not in self._client_attributes:
587
+ self._client_attributes[METRIC_LABEL_KEY_DIRECT_PATH_ENABLED] = str(enable)
588
+ return self