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,328 @@
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
+ """Factory for creating MetricTracer instances, facilitating metrics collection and tracing."""
16
+
17
+ from google.cloud.spanner_v1.metrics.metrics_tracer import MetricsTracer
18
+
19
+ from google.cloud.spanner_v1.metrics.constants import (
20
+ METRIC_NAME_OPERATION_LATENCIES,
21
+ MONITORED_RES_LABEL_KEY_PROJECT,
22
+ METRIC_NAME_ATTEMPT_LATENCIES,
23
+ METRIC_NAME_OPERATION_COUNT,
24
+ METRIC_NAME_ATTEMPT_COUNT,
25
+ MONITORED_RES_LABEL_KEY_INSTANCE,
26
+ MONITORED_RES_LABEL_KEY_INSTANCE_CONFIG,
27
+ MONITORED_RES_LABEL_KEY_LOCATION,
28
+ MONITORED_RES_LABEL_KEY_CLIENT_HASH,
29
+ METRIC_LABEL_KEY_CLIENT_UID,
30
+ METRIC_LABEL_KEY_CLIENT_NAME,
31
+ METRIC_LABEL_KEY_DATABASE,
32
+ METRIC_LABEL_KEY_DIRECT_PATH_ENABLED,
33
+ BUILT_IN_METRICS_METER_NAME,
34
+ METRIC_NAME_GFE_LATENCY,
35
+ METRIC_NAME_GFE_MISSING_HEADER_COUNT,
36
+ )
37
+
38
+ from typing import Dict
39
+
40
+ try:
41
+ from opentelemetry.metrics import Counter, Histogram, get_meter_provider
42
+
43
+ HAS_OPENTELEMETRY_INSTALLED = True
44
+ except ImportError: # pragma: NO COVER
45
+ HAS_OPENTELEMETRY_INSTALLED = False
46
+
47
+ from google.cloud.spanner_v1 import __version__
48
+
49
+
50
+ class MetricsTracerFactory:
51
+ """Factory class for creating MetricTracer instances. This class facilitates the creation of MetricTracer objects, which are responsible for collecting and tracing metrics."""
52
+
53
+ enabled: bool
54
+ gfe_enabled: bool
55
+ _instrument_attempt_latency: "Histogram"
56
+ _instrument_attempt_counter: "Counter"
57
+ _instrument_operation_latency: "Histogram"
58
+ _instrument_operation_counter: "Counter"
59
+ _instrument_gfe_latency: "Histogram"
60
+ _instrument_gfe_missing_header_count: "Counter"
61
+ _client_attributes: Dict[str, str]
62
+
63
+ @property
64
+ def instrument_attempt_latency(self) -> "Histogram":
65
+ return self._instrument_attempt_latency
66
+
67
+ @property
68
+ def instrument_attempt_counter(self) -> "Counter":
69
+ return self._instrument_attempt_counter
70
+
71
+ @property
72
+ def instrument_operation_latency(self) -> "Histogram":
73
+ return self._instrument_operation_latency
74
+
75
+ @property
76
+ def instrument_operation_counter(self) -> "Counter":
77
+ return self._instrument_operation_counter
78
+
79
+ def __init__(self, enabled: bool, service_name: str):
80
+ """Initialize a MetricsTracerFactory instance with the given parameters.
81
+
82
+ This constructor initializes a MetricsTracerFactory instance with the provided service name, project, instance, instance configuration, location, client hash, client UID, client name, and database. It sets up the necessary metric instruments and client attributes for metrics tracing.
83
+
84
+ Args:
85
+ service_name (str): The name of the service for which metrics are being traced.
86
+ project (str): The project ID for the monitored resource.
87
+ """
88
+ self.enabled = enabled
89
+ self._create_metric_instruments(service_name)
90
+ self._client_attributes = {}
91
+
92
+ @property
93
+ def client_attributes(self) -> Dict[str, str]:
94
+ """Return a dictionary of client attributes used for metrics tracing.
95
+
96
+ This property returns a dictionary containing client attributes such as project, instance,
97
+ instance configuration, location, client hash, client UID, client name, and database.
98
+ These attributes are used to provide context to the metrics being traced.
99
+
100
+ Returns:
101
+ dict[str, str]: A dictionary of client attributes.
102
+ """
103
+ return self._client_attributes
104
+
105
+ def set_project(self, project: str) -> "MetricsTracerFactory":
106
+ """Set the project attribute for metrics tracing.
107
+
108
+ This method updates the client attributes dictionary with the provided project name.
109
+ The project name is used to identify the project for which metrics are being traced
110
+ and is passed to the created MetricsTracer.
111
+
112
+ Args:
113
+ project (str): The name of the project for metrics tracing.
114
+
115
+ Returns:
116
+ MetricsTracerFactory: The current instance of MetricsTracerFactory to enable method chaining.
117
+ """
118
+ self._client_attributes[MONITORED_RES_LABEL_KEY_PROJECT] = project
119
+ return self
120
+
121
+ def set_instance(self, instance: str) -> "MetricsTracerFactory":
122
+ """Set the instance attribute for metrics tracing.
123
+
124
+ This method updates the client attributes dictionary with the provided instance name.
125
+ The instance name is used to identify the instance for which metrics are being traced
126
+ and is passed to the created MetricsTracer.
127
+
128
+ Args:
129
+ instance (str): The name of the instance for metrics tracing.
130
+
131
+ Returns:
132
+ MetricsTracerFactory: The current instance of MetricsTracerFactory to enable method chaining.
133
+ """
134
+ self._client_attributes[MONITORED_RES_LABEL_KEY_INSTANCE] = instance
135
+ return self
136
+
137
+ def set_instance_config(self, instance_config: str) -> "MetricsTracerFactory":
138
+ """Sets the instance configuration attribute for metrics tracing.
139
+
140
+ This method updates the client attributes dictionary with the provided instance configuration.
141
+ The instance configuration is used to identify the configuration of the instance for which
142
+ metrics are being traced and is passed to the created MetricsTracer.
143
+
144
+ Args:
145
+ instance_config (str): The configuration of the instance for metrics tracing.
146
+
147
+ Returns:
148
+ MetricsTracerFactory: The current instance of MetricsTracerFactory to enable method chaining.
149
+ """
150
+ self._client_attributes[
151
+ MONITORED_RES_LABEL_KEY_INSTANCE_CONFIG
152
+ ] = instance_config
153
+ return self
154
+
155
+ def set_location(self, location: str) -> "MetricsTracerFactory":
156
+ """Set the location attribute for metrics tracing.
157
+
158
+ This method updates the client attributes dictionary with the provided location.
159
+ The location is used to identify the location for which metrics are being traced
160
+ and is passed to the created MetricsTracer.
161
+
162
+ Args:
163
+ location (str): The location for metrics tracing.
164
+
165
+ Returns:
166
+ MetricsTracerFactory: The current instance of MetricsTracerFactory to enable method chaining.
167
+ """
168
+ self._client_attributes[MONITORED_RES_LABEL_KEY_LOCATION] = location
169
+ return self
170
+
171
+ def set_client_hash(self, hash: str) -> "MetricsTracerFactory":
172
+ """Set the client hash attribute for metrics tracing.
173
+
174
+ This method updates the client attributes dictionary with the provided client hash.
175
+ The client hash is used to identify the client for which metrics are being traced
176
+ and is passed to the created MetricsTracer.
177
+
178
+ Args:
179
+ hash (str): The hash of the client for metrics tracing.
180
+
181
+ Returns:
182
+ MetricsTracerFactory: The current instance of MetricsTracerFactory to enable method chaining.
183
+ """
184
+ self._client_attributes[MONITORED_RES_LABEL_KEY_CLIENT_HASH] = hash
185
+ return self
186
+
187
+ def set_client_uid(self, client_uid: str) -> "MetricsTracerFactory":
188
+ """Set the client UID attribute for metrics tracing.
189
+
190
+ This method updates the client attributes dictionary with the provided client UID.
191
+ The client UID is used to identify the client for which metrics are being traced
192
+ and is passed to the created MetricsTracer.
193
+
194
+ Args:
195
+ client_uid (str): The UID of the client for metrics tracing.
196
+
197
+ Returns:
198
+ MetricsTracerFactory: The current instance of MetricsTracerFactory to enable method chaining.
199
+ """
200
+ self._client_attributes[METRIC_LABEL_KEY_CLIENT_UID] = client_uid
201
+ return self
202
+
203
+ def set_client_name(self, client_name: str) -> "MetricsTracerFactory":
204
+ """Set the client name attribute for metrics tracing.
205
+
206
+ This method updates the client attributes dictionary with the provided client name.
207
+ The client name is used to identify the client for which metrics are being traced
208
+ and is passed to the created MetricsTracer.
209
+
210
+ Args:
211
+ client_name (str): The name of the client for metrics tracing.
212
+
213
+ Returns:
214
+ MetricsTracerFactory: The current instance of MetricsTracerFactory to enable method chaining.
215
+ """
216
+ self._client_attributes[METRIC_LABEL_KEY_CLIENT_NAME] = client_name
217
+ return self
218
+
219
+ def set_database(self, database: str) -> "MetricsTracerFactory":
220
+ """Set the database attribute for metrics tracing.
221
+
222
+ This method updates the client attributes dictionary with the provided database name.
223
+ The database name is used to identify the database for which metrics are being traced
224
+ and is passed to the created MetricsTracer.
225
+
226
+ Args:
227
+ database (str): The name of the database for metrics tracing.
228
+
229
+ Returns:
230
+ MetricsTracerFactory: The current instance of MetricsTracerFactory to enable method chaining.
231
+ """
232
+ self._client_attributes[METRIC_LABEL_KEY_DATABASE] = database
233
+ return self
234
+
235
+ def enable_direct_path(self, enable: bool = False) -> "MetricsTracerFactory":
236
+ """Enable or disable the direct path for metrics tracing.
237
+
238
+ This method updates the client attributes dictionary with the provided enable status.
239
+ The direct path enabled status is used to determine whether to use the direct path for metrics tracing
240
+ and is passed to the created MetricsTracer.
241
+
242
+ Args:
243
+ enable (bool, optional): Whether to enable the direct path for metrics tracing. Defaults to False.
244
+
245
+ Returns:
246
+ MetricsTracerFactory: The current instance of MetricsTracerFactory to enable method chaining.
247
+ """
248
+ self._client_attributes[METRIC_LABEL_KEY_DIRECT_PATH_ENABLED] = enable
249
+ return self
250
+
251
+ def create_metrics_tracer(self) -> MetricsTracer:
252
+ """
253
+ Create and return a MetricsTracer instance with default settings and client attributes.
254
+
255
+ This method initializes a MetricsTracer instance with default settings for metrics tracing,
256
+ including metrics tracing enabled if OpenTelemetry is installed and the direct path disabled by default.
257
+ It also sets the client attributes based on the factory's configuration.
258
+
259
+ Returns:
260
+ MetricsTracer: A MetricsTracer instance with default settings and client attributes.
261
+ """
262
+ if not HAS_OPENTELEMETRY_INSTALLED:
263
+ return None
264
+
265
+ metrics_tracer = MetricsTracer(
266
+ enabled=self.enabled and HAS_OPENTELEMETRY_INSTALLED,
267
+ instrument_attempt_latency=self._instrument_attempt_latency,
268
+ instrument_attempt_counter=self._instrument_attempt_counter,
269
+ instrument_operation_latency=self._instrument_operation_latency,
270
+ instrument_operation_counter=self._instrument_operation_counter,
271
+ client_attributes=self._client_attributes.copy(),
272
+ )
273
+ return metrics_tracer
274
+
275
+ def _create_metric_instruments(self, service_name: str) -> None:
276
+ """
277
+ Creates and sets up metric instruments for the given service name.
278
+
279
+ This method initializes and configures metric instruments for attempt latency, attempt counter,
280
+ operation latency, and operation counter. These instruments are used to measure and track
281
+ metrics related to attempts and operations within the service.
282
+
283
+ Args:
284
+ service_name (str): The name of the service for which metric instruments are being created.
285
+ """
286
+ if not HAS_OPENTELEMETRY_INSTALLED: # pragma: NO COVER
287
+ return
288
+
289
+ meter_provider = get_meter_provider()
290
+ meter = meter_provider.get_meter(
291
+ name=BUILT_IN_METRICS_METER_NAME, version=__version__
292
+ )
293
+
294
+ self._instrument_attempt_latency = meter.create_histogram(
295
+ name=METRIC_NAME_ATTEMPT_LATENCIES,
296
+ unit="ms",
297
+ description="Time an individual attempt took.",
298
+ )
299
+
300
+ self._instrument_attempt_counter = meter.create_counter(
301
+ name=METRIC_NAME_ATTEMPT_COUNT,
302
+ unit="1",
303
+ description="Number of attempts.",
304
+ )
305
+
306
+ self._instrument_operation_latency = meter.create_histogram(
307
+ name=METRIC_NAME_OPERATION_LATENCIES,
308
+ unit="ms",
309
+ description="Total time until final operation success or failure, including retries and backoff.",
310
+ )
311
+
312
+ self._instrument_operation_counter = meter.create_counter(
313
+ name=METRIC_NAME_OPERATION_COUNT,
314
+ unit="1",
315
+ description="Number of operations.",
316
+ )
317
+
318
+ self._instrument_gfe_latency = meter.create_histogram(
319
+ name=METRIC_NAME_GFE_LATENCY,
320
+ unit="ms",
321
+ description="GFE Latency.",
322
+ )
323
+
324
+ self._instrument_gfe_missing_header_count = meter.create_counter(
325
+ name=METRIC_NAME_GFE_MISSING_HEADER_COUNT,
326
+ unit="1",
327
+ description="GFE missing header count.",
328
+ )
@@ -0,0 +1,172 @@
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 provides a singleton factory for creating SpannerMetricsTracer instances."""
17
+
18
+ from .metrics_tracer_factory import MetricsTracerFactory
19
+ import os
20
+ from .constants import (
21
+ SPANNER_SERVICE_NAME,
22
+ GOOGLE_CLOUD_REGION_KEY,
23
+ GOOGLE_CLOUD_REGION_GLOBAL,
24
+ )
25
+
26
+ try:
27
+ from opentelemetry.resourcedetector import gcp_resource_detector
28
+
29
+ # Overwrite the requests timeout for the detector.
30
+ # This is necessary as the client will wait the full timeout if the
31
+ # code is not run in a GCP environment, with the location endpoints available.
32
+ gcp_resource_detector._TIMEOUT_SEC = 0.2
33
+
34
+ import mmh3
35
+
36
+ # Override Resource detector logging to not warn when GCP resources are not detected
37
+ import logging
38
+
39
+ logging.getLogger("opentelemetry.resourcedetector.gcp_resource_detector").setLevel(
40
+ logging.ERROR
41
+ )
42
+
43
+ HAS_OPENTELEMETRY_INSTALLED = True
44
+ except ImportError: # pragma: NO COVER
45
+ HAS_OPENTELEMETRY_INSTALLED = False
46
+
47
+ from .metrics_tracer import MetricsTracer
48
+ from google.cloud.spanner_v1 import __version__
49
+ from uuid import uuid4
50
+
51
+
52
+ class SpannerMetricsTracerFactory(MetricsTracerFactory):
53
+ """A factory for creating SpannerMetricsTracer instances."""
54
+
55
+ _metrics_tracer_factory: "SpannerMetricsTracerFactory" = None
56
+ current_metrics_tracer: MetricsTracer = None
57
+
58
+ def __new__(
59
+ cls, enabled: bool = True, gfe_enabled: bool = False
60
+ ) -> "SpannerMetricsTracerFactory":
61
+ """
62
+ Create a new instance of SpannerMetricsTracerFactory if it doesn't already exist.
63
+
64
+ This method implements the singleton pattern for the SpannerMetricsTracerFactory class.
65
+ It initializes the factory with the necessary client attributes and configuration settings
66
+ if it hasn't been created yet.
67
+
68
+ Args:
69
+ enabled (bool): A flag indicating whether metrics tracing is enabled. Defaults to True.
70
+ gfe_enabled (bool): A flag indicating whether GFE metrics are enabled. Defaults to False.
71
+
72
+ Returns:
73
+ SpannerMetricsTracerFactory: The singleton instance of SpannerMetricsTracerFactory.
74
+ """
75
+ if cls._metrics_tracer_factory is None:
76
+ cls._metrics_tracer_factory = MetricsTracerFactory(
77
+ enabled, SPANNER_SERVICE_NAME
78
+ )
79
+ if not HAS_OPENTELEMETRY_INSTALLED:
80
+ return cls._metrics_tracer_factory
81
+
82
+ client_uid = cls._generate_client_uid()
83
+ cls._metrics_tracer_factory.set_client_uid(client_uid)
84
+ cls._metrics_tracer_factory.set_instance_config(cls._get_instance_config())
85
+ cls._metrics_tracer_factory.set_client_name(cls._get_client_name())
86
+ cls._metrics_tracer_factory.set_client_hash(
87
+ cls._generate_client_hash(client_uid)
88
+ )
89
+ cls._metrics_tracer_factory.set_location(cls._get_location())
90
+ cls._metrics_tracer_factory.gfe_enabled = gfe_enabled
91
+
92
+ if cls._metrics_tracer_factory.enabled != enabled:
93
+ cls._metrics_tracer_factory.enabeld = enabled
94
+
95
+ return cls._metrics_tracer_factory
96
+
97
+ @staticmethod
98
+ def _generate_client_uid() -> str:
99
+ """Generate a client UID in the form of uuidv4@pid@hostname.
100
+
101
+ This method generates a unique client identifier (UID) by combining a UUID version 4,
102
+ the process ID (PID), and the hostname. The PID is limited to the first 10 characters.
103
+
104
+ Returns:
105
+ str: A string representing the client UID in the format uuidv4@pid@hostname.
106
+ """
107
+ try:
108
+ hostname = os.uname()[1]
109
+ pid = str(os.getpid())[0:10] # Limit PID to 10 characters
110
+ uuid = uuid4()
111
+ return f"{uuid}@{pid}@{hostname}"
112
+ except Exception:
113
+ return ""
114
+
115
+ @staticmethod
116
+ def _get_instance_config() -> str:
117
+ """Get the instance configuration."""
118
+ # TODO: unknown until there's a good way to get it.
119
+ return "unknown"
120
+
121
+ @staticmethod
122
+ def _get_client_name() -> str:
123
+ """Get the client name."""
124
+ return f"{SPANNER_SERVICE_NAME}/{__version__}"
125
+
126
+ @staticmethod
127
+ def _generate_client_hash(client_uid: str) -> str:
128
+ """
129
+ Generate a 6-digit zero-padded lowercase hexadecimal hash using the 10 most significant bits of a 64-bit hash value.
130
+
131
+ The primary purpose of this function is to generate a hash value for the `client_hash`
132
+ resource label using `client_uid` metric field. The range of values is chosen to be small
133
+ enough to keep the cardinality of the Resource targets under control. Note: If at later time
134
+ the range needs to be increased, it can be done by increasing the value of `kPrefixLength` to
135
+ up to 24 bits without changing the format of the returned value.
136
+
137
+ Args:
138
+ client_uid (str): The client UID used to generate the hash.
139
+
140
+ Returns:
141
+ str: A 6-digit zero-padded lowercase hexadecimal hash.
142
+ """
143
+ if not client_uid:
144
+ return "000000"
145
+ hashed_client = mmh3.hash64(client_uid)
146
+
147
+ # Join the hashes back together since mmh3 splits into high and low 32bits
148
+ full_hash = (hashed_client[0] << 32) | (hashed_client[1] & 0xFFFFFFFF)
149
+ unsigned_hash = full_hash & 0xFFFFFFFFFFFFFFFF
150
+
151
+ k_prefix_length = 10
152
+ sig_figs = unsigned_hash >> (64 - k_prefix_length)
153
+
154
+ # Return as 6 digit zero padded hex string
155
+ return f"{sig_figs:06x}"
156
+
157
+ @staticmethod
158
+ def _get_location() -> str:
159
+ """Get the location of the resource.
160
+
161
+ Returns:
162
+ str: The location of the resource. If OpenTelemetry is not installed, returns a global region.
163
+ """
164
+ if not HAS_OPENTELEMETRY_INSTALLED:
165
+ return GOOGLE_CLOUD_REGION_GLOBAL
166
+ detector = gcp_resource_detector.GoogleCloudResourceDetector()
167
+ resources = detector.detect()
168
+
169
+ if GOOGLE_CLOUD_REGION_KEY not in resources.attributes:
170
+ return GOOGLE_CLOUD_REGION_GLOBAL
171
+ else:
172
+ return resources[GOOGLE_CLOUD_REGION_KEY]
@@ -0,0 +1,110 @@
1
+ # Copyright 2017 Google LLC All rights reserved.
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
+ """Types exported from this package."""
16
+
17
+ from google.cloud.spanner_v1 import Type
18
+ from google.cloud.spanner_v1 import TypeAnnotationCode
19
+ from google.cloud.spanner_v1 import TypeCode
20
+ from google.cloud.spanner_v1 import StructType
21
+ from google.protobuf.message import Message
22
+ from google.protobuf.internal.enum_type_wrapper import EnumTypeWrapper
23
+
24
+
25
+ # Scalar parameter types
26
+ STRING = Type(code=TypeCode.STRING)
27
+ BYTES = Type(code=TypeCode.BYTES)
28
+ BOOL = Type(code=TypeCode.BOOL)
29
+ INT64 = Type(code=TypeCode.INT64)
30
+ FLOAT64 = Type(code=TypeCode.FLOAT64)
31
+ FLOAT32 = Type(code=TypeCode.FLOAT32)
32
+ DATE = Type(code=TypeCode.DATE)
33
+ TIMESTAMP = Type(code=TypeCode.TIMESTAMP)
34
+ NUMERIC = Type(code=TypeCode.NUMERIC)
35
+ JSON = Type(code=TypeCode.JSON)
36
+ PG_NUMERIC = Type(code=TypeCode.NUMERIC, type_annotation=TypeAnnotationCode.PG_NUMERIC)
37
+ PG_JSONB = Type(code=TypeCode.JSON, type_annotation=TypeAnnotationCode.PG_JSONB)
38
+ PG_OID = Type(code=TypeCode.INT64, type_annotation=TypeAnnotationCode.PG_OID)
39
+ INTERVAL = Type(code=TypeCode.INTERVAL)
40
+
41
+
42
+ def Array(element_type):
43
+ """Construct an array parameter type description protobuf.
44
+
45
+ :type element_type: :class:`~google.cloud.spanner_v1.types.Type`
46
+ :param element_type: the type of elements of the array
47
+
48
+ :rtype: :class:`google.cloud.spanner_v1.types.Type`
49
+ :returns: the appropriate array-type protobuf
50
+ """
51
+ return Type(code=TypeCode.ARRAY, array_element_type=element_type)
52
+
53
+
54
+ def StructField(name, field_type):
55
+ """Construct a field description protobuf.
56
+
57
+ :type name: str
58
+ :param name: the name of the field
59
+
60
+ :type field_type: :class:`google.cloud.spanner_v1.types.Type`
61
+ :param field_type: the type of the field
62
+
63
+ :rtype: :class:`google.cloud.spanner_v1.types.StructType.Field`
64
+ :returns: the appropriate struct-field-type protobuf
65
+ """
66
+ return StructType.Field(name=name, type_=field_type)
67
+
68
+
69
+ def Struct(fields):
70
+ """Construct a struct parameter type description protobuf.
71
+
72
+ :type fields: list of :class:`google.cloud.spanner_v1.types.StructType.Field`
73
+ :param fields: the fields of the struct
74
+
75
+ :rtype: :class:`type_pb2.Type`
76
+ :returns: the appropriate struct-type protobuf
77
+ """
78
+ return Type(code=TypeCode.STRUCT, struct_type=StructType(fields=fields))
79
+
80
+
81
+ def ProtoMessage(proto_message_object):
82
+ """Construct a proto message type description protobuf.
83
+
84
+ :type proto_message_object: :class:`google.protobuf.message.Message`
85
+ :param proto_message_object: the proto message instance
86
+
87
+ :rtype: :class:`type_pb2.Type`
88
+ :returns: the appropriate proto-message-type protobuf
89
+ """
90
+ if not isinstance(proto_message_object, Message):
91
+ raise ValueError("Expected input object of type Proto Message.")
92
+ return Type(
93
+ code=TypeCode.PROTO, proto_type_fqn=proto_message_object.DESCRIPTOR.full_name
94
+ )
95
+
96
+
97
+ def ProtoEnum(proto_enum_object):
98
+ """Construct a proto enum type description protobuf.
99
+
100
+ :type proto_enum_object: :class:`google.protobuf.internal.enum_type_wrapper.EnumTypeWrapper`
101
+ :param proto_enum_object: the proto enum instance
102
+
103
+ :rtype: :class:`type_pb2.Type`
104
+ :returns: the appropriate proto-enum-type protobuf
105
+ """
106
+ if not isinstance(proto_enum_object, EnumTypeWrapper):
107
+ raise ValueError("Expected input object of type Proto Enum")
108
+ return Type(
109
+ code=TypeCode.ENUM, proto_type_fqn=proto_enum_object.DESCRIPTOR.full_name
110
+ )