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.
- google/cloud/spanner.py +47 -0
- google/cloud/spanner_admin_database_v1/__init__.py +146 -0
- google/cloud/spanner_admin_database_v1/gapic_metadata.json +418 -0
- google/cloud/spanner_admin_database_v1/gapic_version.py +16 -0
- google/cloud/spanner_admin_database_v1/py.typed +2 -0
- google/cloud/spanner_admin_database_v1/services/__init__.py +15 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/__init__.py +22 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/async_client.py +4097 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/client.py +4602 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/pagers.py +989 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/transports/__init__.py +38 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/transports/base.py +820 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/transports/grpc.py +1303 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/transports/grpc_asyncio.py +1688 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/transports/rest.py +6512 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/transports/rest_base.py +1650 -0
- google/cloud/spanner_admin_database_v1/types/__init__.py +144 -0
- google/cloud/spanner_admin_database_v1/types/backup.py +1106 -0
- google/cloud/spanner_admin_database_v1/types/backup_schedule.py +369 -0
- google/cloud/spanner_admin_database_v1/types/common.py +180 -0
- google/cloud/spanner_admin_database_v1/types/spanner_database_admin.py +1303 -0
- google/cloud/spanner_admin_instance_v1/__init__.py +110 -0
- google/cloud/spanner_admin_instance_v1/gapic_metadata.json +343 -0
- google/cloud/spanner_admin_instance_v1/gapic_version.py +16 -0
- google/cloud/spanner_admin_instance_v1/py.typed +2 -0
- google/cloud/spanner_admin_instance_v1/services/__init__.py +15 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/__init__.py +22 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/async_client.py +3466 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/client.py +3881 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/pagers.py +856 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/__init__.py +38 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/base.py +545 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/grpc.py +1347 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/grpc_asyncio.py +1539 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/rest.py +4834 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/rest_base.py +1198 -0
- google/cloud/spanner_admin_instance_v1/types/__init__.py +104 -0
- google/cloud/spanner_admin_instance_v1/types/common.py +99 -0
- google/cloud/spanner_admin_instance_v1/types/spanner_instance_admin.py +2375 -0
- google/cloud/spanner_dbapi/__init__.py +93 -0
- google/cloud/spanner_dbapi/_helpers.py +113 -0
- google/cloud/spanner_dbapi/batch_dml_executor.py +135 -0
- google/cloud/spanner_dbapi/checksum.py +80 -0
- google/cloud/spanner_dbapi/client_side_statement_executor.py +140 -0
- google/cloud/spanner_dbapi/client_side_statement_parser.py +106 -0
- google/cloud/spanner_dbapi/connection.py +818 -0
- google/cloud/spanner_dbapi/cursor.py +609 -0
- google/cloud/spanner_dbapi/exceptions.py +172 -0
- google/cloud/spanner_dbapi/parse_utils.py +392 -0
- google/cloud/spanner_dbapi/parsed_statement.py +63 -0
- google/cloud/spanner_dbapi/parser.py +258 -0
- google/cloud/spanner_dbapi/partition_helper.py +41 -0
- google/cloud/spanner_dbapi/transaction_helper.py +294 -0
- google/cloud/spanner_dbapi/types.py +106 -0
- google/cloud/spanner_dbapi/utils.py +147 -0
- google/cloud/spanner_dbapi/version.py +20 -0
- google/cloud/spanner_v1/__init__.py +154 -0
- google/cloud/spanner_v1/_helpers.py +751 -0
- google/cloud/spanner_v1/_opentelemetry_tracing.py +165 -0
- google/cloud/spanner_v1/backup.py +397 -0
- google/cloud/spanner_v1/batch.py +433 -0
- google/cloud/spanner_v1/client.py +538 -0
- google/cloud/spanner_v1/data_types.py +350 -0
- google/cloud/spanner_v1/database.py +1968 -0
- google/cloud/spanner_v1/database_sessions_manager.py +249 -0
- google/cloud/spanner_v1/gapic_metadata.json +268 -0
- google/cloud/spanner_v1/gapic_version.py +16 -0
- google/cloud/spanner_v1/instance.py +735 -0
- google/cloud/spanner_v1/keyset.py +193 -0
- google/cloud/spanner_v1/merged_result_set.py +146 -0
- google/cloud/spanner_v1/metrics/constants.py +71 -0
- google/cloud/spanner_v1/metrics/metrics_capture.py +75 -0
- google/cloud/spanner_v1/metrics/metrics_exporter.py +384 -0
- google/cloud/spanner_v1/metrics/metrics_interceptor.py +156 -0
- google/cloud/spanner_v1/metrics/metrics_tracer.py +588 -0
- google/cloud/spanner_v1/metrics/metrics_tracer_factory.py +328 -0
- google/cloud/spanner_v1/metrics/spanner_metrics_tracer_factory.py +172 -0
- google/cloud/spanner_v1/param_types.py +110 -0
- google/cloud/spanner_v1/pool.py +813 -0
- google/cloud/spanner_v1/py.typed +2 -0
- google/cloud/spanner_v1/request_id_header.py +64 -0
- google/cloud/spanner_v1/services/__init__.py +15 -0
- google/cloud/spanner_v1/services/spanner/__init__.py +22 -0
- google/cloud/spanner_v1/services/spanner/async_client.py +2205 -0
- google/cloud/spanner_v1/services/spanner/client.py +2624 -0
- google/cloud/spanner_v1/services/spanner/pagers.py +196 -0
- google/cloud/spanner_v1/services/spanner/transports/__init__.py +38 -0
- google/cloud/spanner_v1/services/spanner/transports/base.py +520 -0
- google/cloud/spanner_v1/services/spanner/transports/grpc.py +911 -0
- google/cloud/spanner_v1/services/spanner/transports/grpc_asyncio.py +1144 -0
- google/cloud/spanner_v1/services/spanner/transports/rest.py +3468 -0
- google/cloud/spanner_v1/services/spanner/transports/rest_base.py +981 -0
- google/cloud/spanner_v1/session.py +631 -0
- google/cloud/spanner_v1/session_options.py +133 -0
- google/cloud/spanner_v1/snapshot.py +1057 -0
- google/cloud/spanner_v1/streamed.py +402 -0
- google/cloud/spanner_v1/table.py +181 -0
- google/cloud/spanner_v1/testing/__init__.py +0 -0
- google/cloud/spanner_v1/testing/database_test.py +121 -0
- google/cloud/spanner_v1/testing/interceptors.py +118 -0
- google/cloud/spanner_v1/testing/mock_database_admin.py +38 -0
- google/cloud/spanner_v1/testing/mock_spanner.py +261 -0
- google/cloud/spanner_v1/testing/spanner_database_admin_pb2_grpc.py +1267 -0
- google/cloud/spanner_v1/testing/spanner_pb2_grpc.py +882 -0
- google/cloud/spanner_v1/transaction.py +747 -0
- google/cloud/spanner_v1/types/__init__.py +118 -0
- google/cloud/spanner_v1/types/commit_response.py +94 -0
- google/cloud/spanner_v1/types/keys.py +248 -0
- google/cloud/spanner_v1/types/mutation.py +201 -0
- google/cloud/spanner_v1/types/query_plan.py +220 -0
- google/cloud/spanner_v1/types/result_set.py +379 -0
- google/cloud/spanner_v1/types/spanner.py +1815 -0
- google/cloud/spanner_v1/types/transaction.py +818 -0
- google/cloud/spanner_v1/types/type.py +288 -0
- google_cloud_spanner-3.55.0.dist-info/LICENSE +202 -0
- google_cloud_spanner-3.55.0.dist-info/METADATA +318 -0
- google_cloud_spanner-3.55.0.dist-info/RECORD +119 -0
- google_cloud_spanner-3.55.0.dist-info/WHEEL +5 -0
- 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
|
+
)
|