Skip to content
This repository was archived by the owner on Jun 8, 2026. It is now read-only.

Commit 64aebe7

Browse files
authored
feat(spanner): make built-in metrics enabled by default (#1459)
Make built-in metrics enabled by default This change inverts the logic for enabling built-in OpenTelemetry metrics. Previously, metrics were disabled by default and could be enabled by setting `ENABLE_SPANNER_METRICS_ENV_VAR=true`. With this update, metrics are now enabled by default to provide better out-of-the-box observability for users. To disable metrics, users must now set the new environment variable: `SPANNER_DISABLE_BUILTIN_METRICS=true` The old `ENABLE_SPANNER_METRICS_ENV_VAR` is no longer used. Unit tests have been updated to reflect this new opt-out behavior. **BREAKING CHANGE**: Built-in metrics are now enabled by default. Users who previously did not set any environment variables will have metrics collection and export turned on automatically after upgrading. To restore the previous behavior and disable metrics, thry have to set the `SPANNER_DISABLE_BUILTIN_METRICS` environment variable to `true`.
1 parent 4bb4622 commit 64aebe7

4 files changed

Lines changed: 97 additions & 7 deletions

File tree

‎google/cloud/spanner_v1/client.py‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@
5252
fromgoogle.cloud.spanner_v1._helpersimport_metadata_with_prefix
5353
fromgoogle.cloud.spanner_v1.instanceimportInstance
5454
fromgoogle.cloud.spanner_v1.metrics.constantsimport (
55-
ENABLE_SPANNER_METRICS_ENV_VAR,
5655
METRIC_EXPORT_INTERVAL_MS,
5756
)
5857
fromgoogle.cloud.spanner_v1.metrics.spanner_metrics_tracer_factoryimport (
@@ -75,7 +74,7 @@
7574

7675
_CLIENT_INFO=client_info.ClientInfo(client_library_version=__version__)
7776
EMULATOR_ENV_VAR="SPANNER_EMULATOR_HOST"
78-
ENABLE_BUILTIN_METRICS_ENV_VAR="SPANNER_ENABLE_BUILTIN_METRICS"
77+
SPANNER_DISABLE_BUILTIN_METRICS_ENV_VAR="SPANNER_DISABLE_BUILTIN_METRICS"
7978
_EMULATOR_HOST_HTTP_SCHEME= (
8079
"%s contains a http scheme. When used with a scheme it may cause gRPC's "
8180
"DNS resolver to endlessly attempt to resolve. %s is intended to be used "
@@ -102,7 +101,7 @@ def _get_spanner_optimizer_statistics_package():
102101

103102

104103
def_get_spanner_enable_builtin_metrics():
105-
returnos.getenv(ENABLE_SPANNER_METRICS_ENV_VAR) =="true"
104+
returnos.getenv(SPANNER_DISABLE_BUILTIN_METRICS_ENV_VAR) !="true"
106105

107106

108107
classClient(ClientWithProject):

‎google/cloud/spanner_v1/metrics/constants.py‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
GOOGLE_CLOUD_REGION_KEY="cloud.region"
2121
GOOGLE_CLOUD_REGION_GLOBAL="global"
2222
SPANNER_METHOD_PREFIX="/google.spanner.v1."
23-
ENABLE_SPANNER_METRICS_ENV_VAR="SPANNER_ENABLE_BUILTIN_METRICS"
2423

2524
# Monitored resource labels
2625
MONITORED_RES_LABEL_KEY_PROJECT="project_id"

‎tests/system/test_metrics.py‎

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
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+
importos
16+
importmock
17+
importpytest
18+
19+
fromopentelemetry.sdk.metricsimportMeterProvider
20+
fromopentelemetry.sdk.metrics.exportimportInMemoryMetricReader
21+
22+
fromgoogle.cloud.spanner_v1importClient
23+
24+
# System tests are skipped if the environment variables are not set.
25+
PROJECT=os.environ.get("GOOGLE_CLOUD_PROJECT")
26+
INSTANCE_ID=os.environ.get("SPANNER_TEST_INSTANCE")
27+
DATABASE_ID="test_metrics_db_system"
28+
29+
30+
pytestmark=pytest.mark.skipif(
31+
notall([PROJECT, INSTANCE_ID]), reason="System test environment variables not set."
32+
)
33+
34+
35+
@pytest.fixture(scope="module")
36+
defmetrics_database():
37+
"""Create a database for the test."""
38+
client=Client(project=PROJECT)
39+
instance=client.instance(INSTANCE_ID)
40+
database=instance.database(DATABASE_ID)
41+
ifdatabase.exists(): # Clean up from previous failed run
42+
database.drop()
43+
op=database.create()
44+
op.result(timeout=300) # Wait for creation to complete
45+
yielddatabase
46+
ifdatabase.exists():
47+
database.drop()
48+
49+
50+
deftest_builtin_metrics_with_default_otel(metrics_database):
51+
"""
52+
Verifies that built-in metrics are collected by default when a
53+
transaction is executed.
54+
"""
55+
reader=InMemoryMetricReader()
56+
meter_provider=MeterProvider(metric_readers=[reader])
57+
58+
# Patch the client's metric setup to use our in-memory reader.
59+
withmock.patch(
60+
"google.cloud.spanner_v1.client.MeterProvider",
61+
return_value=meter_provider,
62+
):
63+
withmock.patch.dict(os.environ, {"SPANNER_DISABLE_BUILTIN_METRICS": "false"}):
64+
withmetrics_database.snapshot() assnapshot:
65+
list(snapshot.execute_sql("SELECT 1"))
66+
67+
metric_data=reader.get_metrics_data()
68+
69+
assertlen(metric_data.resource_metrics) >=1
70+
assertlen(metric_data.resource_metrics[0].scope_metrics) >=1
71+
72+
collected_metrics= {
73+
metric.name
74+
formetricinmetric_data.resource_metrics[0].scope_metrics[0].metrics
75+
}
76+
expected_metrics= {
77+
"spanner/operation_latencies",
78+
"spanner/attempt_latencies",
79+
"spanner/operation_count",
80+
"spanner/attempt_count",
81+
"spanner/gfe_latencies",
82+
}
83+
assertexpected_metrics.issubset(collected_metrics)
84+
85+
formetricinmetric_data.resource_metrics[0].scope_metrics[0].metrics:
86+
ifmetric.name=="spanner/operation_count":
87+
point=next(iter(metric.data.data_points))
88+
assertpoint.value==1
89+
assertpoint.attributes["method"] =="ExecuteSql"
90+
return
91+
92+
pytest.fail("Metric 'spanner/operation_count' not found.")

‎tests/unit/test_client.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
fromtests._buildersimportbuild_scoped_credentials
2323

2424

25+
@mock.patch.dict(os.environ, {"SPANNER_DISABLE_BUILTIN_METRICS": "true"})
2526
classTestClient(unittest.TestCase):
2627
PROJECT="PROJECT"
2728
PATH="projects/%s"% (PROJECT,)
@@ -161,8 +162,7 @@ def test_constructor_custom_client_info(self):
161162
creds=build_scoped_credentials()
162163
self._constructor_test_helper(expected_scopes, creds, client_info=client_info)
163164

164-
# Disable metrics to avoid google.auth.default calls from Metric Exporter
165-
@mock.patch.dict(os.environ, {"SPANNER_ENABLE_BUILTIN_METRICS": ""})
165+
# Metrics are disabled by default for tests in this class
166166
deftest_constructor_implicit_credentials(self):
167167
fromgoogle.cloud.spanner_v1importclientasMUT
168168

@@ -255,8 +255,8 @@ def test_constructor_w_directed_read_options(self):
255255
expected_scopes, creds, directed_read_options=self.DIRECTED_READ_OPTIONS
256256
)
257257

258-
@mock.patch.dict(os.environ, {"SPANNER_ENABLE_BUILTIN_METRICS": "true"})
259258
@mock.patch("google.cloud.spanner_v1.client.SpannerMetricsTracerFactory")
259+
@mock.patch.dict(os.environ, {"SPANNER_DISABLE_BUILTIN_METRICS": "false"})
260260
deftest_constructor_w_metrics_initialization_error(
261261
self, mock_spanner_metrics_factory
262262
):

0 commit comments

Comments
 (0)