google-cloud-spanner 3.62.0__tar.gz → 3.63.0__tar.gz
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-3.62.0/google_cloud_spanner.egg-info → google_cloud_spanner-3.63.0}/PKG-INFO +1 -1
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/gapic_version.py +1 -1
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/gapic_version.py +1 -1
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/version.py +1 -1
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/__init__.py +3 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/_helpers.py +68 -3
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/_opentelemetry_tracing.py +2 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/batch.py +13 -10
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/client.py +42 -20
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/database.py +79 -11
- google_cloud_spanner-3.63.0/google/cloud/spanner_v1/exceptions.py +42 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/gapic_version.py +1 -1
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/metrics/metrics_capture.py +17 -7
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/metrics/metrics_interceptor.py +20 -24
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/metrics/spanner_metrics_tracer_factory.py +17 -2
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/pool.py +20 -16
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/request_id_header.py +10 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/session.py +51 -44
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/snapshot.py +26 -14
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/transaction.py +43 -33
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0/google_cloud_spanner.egg-info}/PKG-INFO +1 -1
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google_cloud_spanner.egg-info/SOURCES.txt +4 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/mockserver_tests/test_aborted_transaction.py +26 -13
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/mockserver_tests/test_dbapi_isolation_level.py +1 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/system/test_observability_options.py +17 -14
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/system/test_session_api.py +3 -0
- google_cloud_spanner-3.63.0/tests/unit/conftest.py +27 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/test__opentelemetry_tracing.py +8 -1
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/test_batch.py +27 -5
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/test_client.py +78 -10
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/test_database.py +20 -1
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/test_database_session_manager.py +8 -2
- google_cloud_spanner-3.63.0/tests/unit/test_exceptions.py +65 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/test_metrics.py +30 -10
- google_cloud_spanner-3.63.0/tests/unit/test_metrics_concurrency.py +94 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/test_metrics_interceptor.py +34 -42
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/test_pool.py +19 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/test_session.py +68 -12
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/test_snapshot.py +40 -3
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/test_spanner.py +27 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/test_transaction.py +18 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/LICENSE +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/MANIFEST.in +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/README.rst +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/__init__.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/gapic_metadata.json +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/py.typed +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/services/__init__.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/services/database_admin/__init__.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/services/database_admin/async_client.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/services/database_admin/client.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/services/database_admin/pagers.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/services/database_admin/transports/__init__.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/services/database_admin/transports/base.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/services/database_admin/transports/grpc.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/services/database_admin/transports/grpc_asyncio.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/services/database_admin/transports/rest.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/services/database_admin/transports/rest_base.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/types/__init__.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/types/backup.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/types/backup_schedule.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/types/common.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_database_v1/types/spanner_database_admin.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/__init__.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/gapic_metadata.json +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/py.typed +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/services/__init__.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/__init__.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/async_client.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/client.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/pagers.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/__init__.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/base.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/grpc.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/grpc_asyncio.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/rest.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/rest_base.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/types/__init__.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/types/common.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_admin_instance_v1/types/spanner_instance_admin.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/__init__.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/_helpers.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/batch_dml_executor.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/checksum.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/client_side_statement_executor.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/client_side_statement_parser.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/connection.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/cursor.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/exceptions.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/parse_utils.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/parsed_statement.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/parser.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/partition_helper.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/transaction_helper.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/types.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_dbapi/utils.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/backup.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/data_types.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/database_sessions_manager.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/gapic_metadata.json +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/instance.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/keyset.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/merged_result_set.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/metrics/constants.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/metrics/metrics_exporter.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/metrics/metrics_tracer.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/metrics/metrics_tracer_factory.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/param_types.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/py.typed +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/services/__init__.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/services/spanner/__init__.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/services/spanner/async_client.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/services/spanner/client.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/services/spanner/pagers.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/services/spanner/transports/__init__.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/services/spanner/transports/base.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/services/spanner/transports/grpc.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/services/spanner/transports/grpc_asyncio.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/services/spanner/transports/rest.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/services/spanner/transports/rest_base.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/streamed.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/table.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/testing/__init__.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/testing/database_test.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/testing/interceptors.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/testing/mock_database_admin.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/testing/mock_spanner.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/testing/spanner_database_admin_pb2_grpc.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/testing/spanner_pb2_grpc.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/types/__init__.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/types/change_stream.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/types/commit_response.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/types/keys.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/types/location.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/types/mutation.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/types/query_plan.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/types/result_set.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/types/spanner.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/types/transaction.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/types/type.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google_cloud_spanner.egg-info/dependency_links.txt +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google_cloud_spanner.egg-info/not-zip-safe +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google_cloud_spanner.egg-info/requires.txt +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google_cloud_spanner.egg-info/top_level.txt +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/setup.cfg +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/setup.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/__init__.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/_builders.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/_fixtures.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/_helpers.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/mockserver_tests/__init__.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/mockserver_tests/mock_server_test_base.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/mockserver_tests/test_basics.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/mockserver_tests/test_dbapi_autocommit.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/mockserver_tests/test_request_id_header.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/mockserver_tests/test_tags.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/system/__init__.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/system/_helpers.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/system/_sample_data.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/system/conftest.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/system/test_backup_api.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/system/test_database_api.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/system/test_dbapi.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/system/test_instance_api.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/system/test_metrics.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/system/test_streaming_chunking.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/system/test_table_api.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/system/testdata/descriptors.pb +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/system/testdata/singer.proto +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/system/testdata/singer_pb2.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/system/utils/__init__.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/system/utils/clear_streaming.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/system/utils/populate_streaming.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/system/utils/scrub_instances.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/system/utils/streaming_utils.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/__init__.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/gapic/__init__.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/gapic/spanner_admin_database_v1/__init__.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/gapic/spanner_admin_database_v1/test_database_admin.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/gapic/spanner_admin_instance_v1/__init__.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/gapic/spanner_admin_instance_v1/test_instance_admin.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/gapic/spanner_v1/__init__.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/gapic/spanner_v1/test_spanner.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/spanner_dbapi/__init__.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/spanner_dbapi/test__helpers.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/spanner_dbapi/test_batch_dml_executor.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/spanner_dbapi/test_checksum.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/spanner_dbapi/test_client_side_statement_executor.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/spanner_dbapi/test_connect.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/spanner_dbapi/test_connection.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/spanner_dbapi/test_cursor.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/spanner_dbapi/test_globals.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/spanner_dbapi/test_parse_utils.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/spanner_dbapi/test_parser.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/spanner_dbapi/test_transaction_helper.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/spanner_dbapi/test_types.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/spanner_dbapi/test_utils.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/streaming-read-acceptance-test.json +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/test__helpers.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/test_atomic_counter.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/test_backup.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/test_datatypes.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/test_instance.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/test_keyset.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/test_merged_result_set.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/test_metrics_capture.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/test_metrics_exporter.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/test_metrics_tracer.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/test_metrics_tracer_factory.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/test_packaging.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/test_param_types.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/test_spanner_metrics_tracer_factory.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/test_streamed.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/test_table.py +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/testdata/singer.proto +0 -0
- {google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/tests/unit/testdata/singer_pb2.py +0 -0
{google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/__init__.py
RENAMED
|
@@ -65,6 +65,7 @@ from .types.type import TypeAnnotationCode
|
|
|
65
65
|
from .types.type import TypeCode
|
|
66
66
|
from .data_types import JsonObject, Interval
|
|
67
67
|
from .transaction import BatchTransactionId, DefaultTransactionOptions
|
|
68
|
+
from .exceptions import wrap_with_request_id
|
|
68
69
|
|
|
69
70
|
from google.cloud.spanner_v1 import param_types
|
|
70
71
|
from google.cloud.spanner_v1.client import Client
|
|
@@ -88,6 +89,8 @@ __all__ = (
|
|
|
88
89
|
# google.cloud.spanner_v1
|
|
89
90
|
"__version__",
|
|
90
91
|
"param_types",
|
|
92
|
+
# google.cloud.spanner_v1.exceptions
|
|
93
|
+
"wrap_with_request_id",
|
|
91
94
|
# google.cloud.spanner_v1.client
|
|
92
95
|
"Client",
|
|
93
96
|
# google.cloud.spanner_v1.keyset
|
{google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/_helpers.py
RENAMED
|
@@ -22,6 +22,7 @@ import base64
|
|
|
22
22
|
import threading
|
|
23
23
|
import logging
|
|
24
24
|
import uuid
|
|
25
|
+
from contextlib import contextmanager
|
|
25
26
|
|
|
26
27
|
from google.protobuf.struct_pb2 import ListValue
|
|
27
28
|
from google.protobuf.struct_pb2 import Value
|
|
@@ -34,8 +35,12 @@ from google.cloud._helpers import _date_from_iso8601_date
|
|
|
34
35
|
from google.cloud.spanner_v1.types import ExecuteSqlRequest
|
|
35
36
|
from google.cloud.spanner_v1.types import TransactionOptions
|
|
36
37
|
from google.cloud.spanner_v1.data_types import JsonObject, Interval
|
|
37
|
-
from google.cloud.spanner_v1.request_id_header import
|
|
38
|
+
from google.cloud.spanner_v1.request_id_header import (
|
|
39
|
+
with_request_id,
|
|
40
|
+
with_request_id_metadata_only,
|
|
41
|
+
)
|
|
38
42
|
from google.cloud.spanner_v1.types import TypeCode
|
|
43
|
+
from google.cloud.spanner_v1.exceptions import wrap_with_request_id
|
|
39
44
|
|
|
40
45
|
from google.rpc.error_details_pb2 import RetryInfo
|
|
41
46
|
|
|
@@ -612,9 +617,11 @@ def _retry(
|
|
|
612
617
|
try:
|
|
613
618
|
return func()
|
|
614
619
|
except Exception as exc:
|
|
615
|
-
|
|
620
|
+
is_allowed = (
|
|
616
621
|
allowed_exceptions is None or exc.__class__ in allowed_exceptions
|
|
617
|
-
)
|
|
622
|
+
)
|
|
623
|
+
|
|
624
|
+
if is_allowed and retries < retry_count:
|
|
618
625
|
if (
|
|
619
626
|
allowed_exceptions is not None
|
|
620
627
|
and allowed_exceptions[exc.__class__] is not None
|
|
@@ -767,9 +774,67 @@ class AtomicCounter:
|
|
|
767
774
|
|
|
768
775
|
|
|
769
776
|
def _metadata_with_request_id(*args, **kwargs):
|
|
777
|
+
"""Return metadata with request ID header.
|
|
778
|
+
|
|
779
|
+
This function returns only the metadata list (not a tuple),
|
|
780
|
+
maintaining backward compatibility with existing code.
|
|
781
|
+
|
|
782
|
+
Args:
|
|
783
|
+
*args: Arguments to pass to with_request_id
|
|
784
|
+
**kwargs: Keyword arguments to pass to with_request_id
|
|
785
|
+
|
|
786
|
+
Returns:
|
|
787
|
+
list: gRPC metadata with request ID header
|
|
788
|
+
"""
|
|
789
|
+
return with_request_id_metadata_only(*args, **kwargs)
|
|
790
|
+
|
|
791
|
+
|
|
792
|
+
def _metadata_with_request_id_and_req_id(*args, **kwargs):
|
|
793
|
+
"""Return both metadata and request ID string.
|
|
794
|
+
|
|
795
|
+
This is used when we need to augment errors with the request ID.
|
|
796
|
+
|
|
797
|
+
Args:
|
|
798
|
+
*args: Arguments to pass to with_request_id
|
|
799
|
+
**kwargs: Keyword arguments to pass to with_request_id
|
|
800
|
+
|
|
801
|
+
Returns:
|
|
802
|
+
tuple: (metadata, request_id)
|
|
803
|
+
"""
|
|
770
804
|
return with_request_id(*args, **kwargs)
|
|
771
805
|
|
|
772
806
|
|
|
807
|
+
def _augment_error_with_request_id(error, request_id=None):
|
|
808
|
+
"""Augment an error with request ID information.
|
|
809
|
+
|
|
810
|
+
Args:
|
|
811
|
+
error: The error to augment (typically GoogleAPICallError)
|
|
812
|
+
request_id (str): The request ID to include
|
|
813
|
+
|
|
814
|
+
Returns:
|
|
815
|
+
The augmented error with request ID information
|
|
816
|
+
"""
|
|
817
|
+
return wrap_with_request_id(error, request_id)
|
|
818
|
+
|
|
819
|
+
|
|
820
|
+
@contextmanager
|
|
821
|
+
def _augment_errors_with_request_id(request_id):
|
|
822
|
+
"""Context manager to augment exceptions with request ID.
|
|
823
|
+
|
|
824
|
+
Args:
|
|
825
|
+
request_id (str): The request ID to include in exceptions
|
|
826
|
+
|
|
827
|
+
Yields:
|
|
828
|
+
None
|
|
829
|
+
"""
|
|
830
|
+
try:
|
|
831
|
+
yield
|
|
832
|
+
except Exception as exc:
|
|
833
|
+
augmented = _augment_error_with_request_id(exc, request_id)
|
|
834
|
+
# Use exception chaining to preserve the original exception
|
|
835
|
+
raise augmented from exc
|
|
836
|
+
|
|
837
|
+
|
|
773
838
|
def _merge_Transaction_Options(
|
|
774
839
|
defaultTransactionOptions: TransactionOptions,
|
|
775
840
|
mergeTransactionOptions: TransactionOptions,
|
|
@@ -36,6 +36,7 @@ from google.cloud.spanner_v1.metrics.metrics_capture import MetricsCapture
|
|
|
36
36
|
|
|
37
37
|
TRACER_NAME = "cloud.google.com/python/spanner"
|
|
38
38
|
TRACER_VERSION = gapic_version.__version__
|
|
39
|
+
GCP_RESOURCE_NAME_PREFIX = "//spanner.googleapis.com/"
|
|
39
40
|
extended_tracing_globally_disabled = (
|
|
40
41
|
os.getenv("SPANNER_ENABLE_EXTENDED_TRACING", "").lower() == "false"
|
|
41
42
|
)
|
|
@@ -106,6 +107,7 @@ def trace_call(
|
|
|
106
107
|
"gcp.client.service": "spanner",
|
|
107
108
|
"gcp.client.version": TRACER_VERSION,
|
|
108
109
|
"gcp.client.repo": "googleapis/python-spanner",
|
|
110
|
+
"gcp.resource.name": GCP_RESOURCE_NAME_PREFIX + db_name,
|
|
109
111
|
}
|
|
110
112
|
|
|
111
113
|
if extra_attributes:
|
{google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/batch.py
RENAMED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
# limitations under the License.
|
|
14
14
|
|
|
15
15
|
"""Context manager for Cloud Spanner batched writes."""
|
|
16
|
+
|
|
16
17
|
import functools
|
|
17
18
|
from typing import List, Optional
|
|
18
19
|
|
|
@@ -252,20 +253,22 @@ class Batch(_BatchBase):
|
|
|
252
253
|
max_commit_delay=max_commit_delay,
|
|
253
254
|
request_options=request_options,
|
|
254
255
|
)
|
|
256
|
+
# This code is retried due to ABORTED, hence nth_request
|
|
257
|
+
# should be increased. attempt can only be increased if
|
|
258
|
+
# we encounter UNAVAILABLE or INTERNAL.
|
|
259
|
+
call_metadata, error_augmenter = database.with_error_augmentation(
|
|
260
|
+
getattr(database, "_next_nth_request", 0),
|
|
261
|
+
1,
|
|
262
|
+
metadata,
|
|
263
|
+
span,
|
|
264
|
+
)
|
|
255
265
|
commit_method = functools.partial(
|
|
256
266
|
api.commit,
|
|
257
267
|
request=commit_request,
|
|
258
|
-
metadata=
|
|
259
|
-
# This code is retried due to ABORTED, hence nth_request
|
|
260
|
-
# should be increased. attempt can only be increased if
|
|
261
|
-
# we encounter UNAVAILABLE or INTERNAL.
|
|
262
|
-
getattr(database, "_next_nth_request", 0),
|
|
263
|
-
1,
|
|
264
|
-
metadata,
|
|
265
|
-
span,
|
|
266
|
-
),
|
|
268
|
+
metadata=call_metadata,
|
|
267
269
|
)
|
|
268
|
-
|
|
270
|
+
with error_augmenter:
|
|
271
|
+
return commit_method()
|
|
269
272
|
|
|
270
273
|
response = _retry_on_aborted_exception(
|
|
271
274
|
wrapped_method,
|
{google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/client.py
RENAMED
|
@@ -23,10 +23,12 @@ In the hierarchy of API concepts
|
|
|
23
23
|
* a :class:`~google.cloud.spanner_v1.instance.Instance` owns a
|
|
24
24
|
:class:`~google.cloud.spanner_v1.database.Database`
|
|
25
25
|
"""
|
|
26
|
+
|
|
26
27
|
import grpc
|
|
27
28
|
import os
|
|
28
29
|
import logging
|
|
29
30
|
import warnings
|
|
31
|
+
import threading
|
|
30
32
|
|
|
31
33
|
from google.api_core.gapic_v1 import client_info
|
|
32
34
|
from google.auth.credentials import AnonymousCredentials
|
|
@@ -99,11 +101,50 @@ def _get_spanner_optimizer_statistics_package():
|
|
|
99
101
|
|
|
100
102
|
log = logging.getLogger(__name__)
|
|
101
103
|
|
|
104
|
+
_metrics_monitor_initialized = False
|
|
105
|
+
_metrics_monitor_lock = threading.Lock()
|
|
106
|
+
|
|
102
107
|
|
|
103
108
|
def _get_spanner_enable_builtin_metrics_env():
|
|
104
109
|
return os.getenv(SPANNER_DISABLE_BUILTIN_METRICS_ENV_VAR) != "true"
|
|
105
110
|
|
|
106
111
|
|
|
112
|
+
def _initialize_metrics(project, credentials):
|
|
113
|
+
"""
|
|
114
|
+
Initializes the Spanner built-in metrics.
|
|
115
|
+
|
|
116
|
+
This function sets up the OpenTelemetry MeterProvider and the SpannerMetricsTracerFactory.
|
|
117
|
+
It uses a lock to ensure that initialization happens only once.
|
|
118
|
+
"""
|
|
119
|
+
global _metrics_monitor_initialized
|
|
120
|
+
if not _metrics_monitor_initialized:
|
|
121
|
+
with _metrics_monitor_lock:
|
|
122
|
+
if not _metrics_monitor_initialized:
|
|
123
|
+
meter_provider = metrics.NoOpMeterProvider()
|
|
124
|
+
try:
|
|
125
|
+
if not _get_spanner_emulator_host():
|
|
126
|
+
meter_provider = MeterProvider(
|
|
127
|
+
metric_readers=[
|
|
128
|
+
PeriodicExportingMetricReader(
|
|
129
|
+
CloudMonitoringMetricsExporter(
|
|
130
|
+
project_id=project,
|
|
131
|
+
credentials=credentials,
|
|
132
|
+
),
|
|
133
|
+
export_interval_millis=METRIC_EXPORT_INTERVAL_MS,
|
|
134
|
+
),
|
|
135
|
+
]
|
|
136
|
+
)
|
|
137
|
+
metrics.set_meter_provider(meter_provider)
|
|
138
|
+
SpannerMetricsTracerFactory()
|
|
139
|
+
_metrics_monitor_initialized = True
|
|
140
|
+
except Exception as e:
|
|
141
|
+
# log is already defined at module level
|
|
142
|
+
log.warning(
|
|
143
|
+
"Failed to initialize Spanner built-in metrics. Error: %s",
|
|
144
|
+
e,
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
|
|
107
148
|
class Client(ClientWithProject):
|
|
108
149
|
"""Client for interacting with Cloud Spanner API.
|
|
109
150
|
|
|
@@ -251,31 +292,12 @@ class Client(ClientWithProject):
|
|
|
251
292
|
"http://" in self._emulator_host or "https://" in self._emulator_host
|
|
252
293
|
):
|
|
253
294
|
warnings.warn(_EMULATOR_HOST_HTTP_SCHEME)
|
|
254
|
-
# Check flag to enable Spanner builtin metrics
|
|
255
295
|
if (
|
|
256
296
|
_get_spanner_enable_builtin_metrics_env()
|
|
257
297
|
and not disable_builtin_metrics
|
|
258
298
|
and HAS_GOOGLE_CLOUD_MONITORING_INSTALLED
|
|
259
299
|
):
|
|
260
|
-
|
|
261
|
-
try:
|
|
262
|
-
if not _get_spanner_emulator_host():
|
|
263
|
-
meter_provider = MeterProvider(
|
|
264
|
-
metric_readers=[
|
|
265
|
-
PeriodicExportingMetricReader(
|
|
266
|
-
CloudMonitoringMetricsExporter(
|
|
267
|
-
project_id=project, credentials=credentials
|
|
268
|
-
),
|
|
269
|
-
export_interval_millis=METRIC_EXPORT_INTERVAL_MS,
|
|
270
|
-
),
|
|
271
|
-
]
|
|
272
|
-
)
|
|
273
|
-
metrics.set_meter_provider(meter_provider)
|
|
274
|
-
SpannerMetricsTracerFactory()
|
|
275
|
-
except Exception as e:
|
|
276
|
-
log.warning(
|
|
277
|
-
"Failed to initialize Spanner built-in metrics. Error: %s", e
|
|
278
|
-
)
|
|
300
|
+
_initialize_metrics(project, credentials)
|
|
279
301
|
else:
|
|
280
302
|
SpannerMetricsTracerFactory(enabled=False)
|
|
281
303
|
|
{google_cloud_spanner-3.62.0 → google_cloud_spanner-3.63.0}/google/cloud/spanner_v1/database.py
RENAMED
|
@@ -25,7 +25,6 @@ import threading
|
|
|
25
25
|
|
|
26
26
|
import google.auth.credentials
|
|
27
27
|
from google.api_core.retry import Retry
|
|
28
|
-
from google.api_core.retry import if_exception_type
|
|
29
28
|
from google.cloud.exceptions import NotFound
|
|
30
29
|
from google.api_core.exceptions import Aborted
|
|
31
30
|
from google.api_core import gapic_v1
|
|
@@ -55,6 +54,8 @@ from google.cloud.spanner_v1._helpers import (
|
|
|
55
54
|
_metadata_with_prefix,
|
|
56
55
|
_metadata_with_leader_aware_routing,
|
|
57
56
|
_metadata_with_request_id,
|
|
57
|
+
_augment_errors_with_request_id,
|
|
58
|
+
_metadata_with_request_id_and_req_id,
|
|
58
59
|
)
|
|
59
60
|
from google.cloud.spanner_v1.batch import Batch
|
|
60
61
|
from google.cloud.spanner_v1.batch import MutationGroups
|
|
@@ -496,6 +497,66 @@ class Database(object):
|
|
|
496
497
|
span,
|
|
497
498
|
)
|
|
498
499
|
|
|
500
|
+
def metadata_and_request_id(
|
|
501
|
+
self, nth_request, nth_attempt, prior_metadata=[], span=None
|
|
502
|
+
):
|
|
503
|
+
"""Return metadata and request ID string.
|
|
504
|
+
|
|
505
|
+
This method returns both the gRPC metadata with request ID header
|
|
506
|
+
and the request ID string itself, which can be used to augment errors.
|
|
507
|
+
|
|
508
|
+
Args:
|
|
509
|
+
nth_request: The request sequence number
|
|
510
|
+
nth_attempt: The attempt number (for retries)
|
|
511
|
+
prior_metadata: Prior metadata to include
|
|
512
|
+
span: Optional span for tracing
|
|
513
|
+
|
|
514
|
+
Returns:
|
|
515
|
+
tuple: (metadata_list, request_id_string)
|
|
516
|
+
"""
|
|
517
|
+
if span is None:
|
|
518
|
+
span = get_current_span()
|
|
519
|
+
|
|
520
|
+
return _metadata_with_request_id_and_req_id(
|
|
521
|
+
self._nth_client_id,
|
|
522
|
+
self._channel_id,
|
|
523
|
+
nth_request,
|
|
524
|
+
nth_attempt,
|
|
525
|
+
prior_metadata,
|
|
526
|
+
span,
|
|
527
|
+
)
|
|
528
|
+
|
|
529
|
+
def with_error_augmentation(
|
|
530
|
+
self, nth_request, nth_attempt, prior_metadata=[], span=None
|
|
531
|
+
):
|
|
532
|
+
"""Context manager for gRPC calls with error augmentation.
|
|
533
|
+
|
|
534
|
+
This context manager provides both metadata with request ID and
|
|
535
|
+
automatically augments any exceptions with the request ID.
|
|
536
|
+
|
|
537
|
+
Args:
|
|
538
|
+
nth_request: The request sequence number
|
|
539
|
+
nth_attempt: The attempt number (for retries)
|
|
540
|
+
prior_metadata: Prior metadata to include
|
|
541
|
+
span: Optional span for tracing
|
|
542
|
+
|
|
543
|
+
Yields:
|
|
544
|
+
tuple: (metadata_list, context_manager)
|
|
545
|
+
"""
|
|
546
|
+
if span is None:
|
|
547
|
+
span = get_current_span()
|
|
548
|
+
|
|
549
|
+
metadata, request_id = _metadata_with_request_id_and_req_id(
|
|
550
|
+
self._nth_client_id,
|
|
551
|
+
self._channel_id,
|
|
552
|
+
nth_request,
|
|
553
|
+
nth_attempt,
|
|
554
|
+
prior_metadata,
|
|
555
|
+
span,
|
|
556
|
+
)
|
|
557
|
+
|
|
558
|
+
return metadata, _augment_errors_with_request_id(request_id)
|
|
559
|
+
|
|
499
560
|
def __eq__(self, other):
|
|
500
561
|
if not isinstance(other, self.__class__):
|
|
501
562
|
return NotImplemented
|
|
@@ -783,16 +844,18 @@ class Database(object):
|
|
|
783
844
|
|
|
784
845
|
try:
|
|
785
846
|
add_span_event(span, "Starting BeginTransaction")
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
metadata
|
|
790
|
-
|
|
791
|
-
1,
|
|
792
|
-
metadata,
|
|
793
|
-
span,
|
|
794
|
-
),
|
|
847
|
+
call_metadata, error_augmenter = self.with_error_augmentation(
|
|
848
|
+
self._next_nth_request,
|
|
849
|
+
1,
|
|
850
|
+
metadata,
|
|
851
|
+
span,
|
|
795
852
|
)
|
|
853
|
+
with error_augmenter:
|
|
854
|
+
txn = api.begin_transaction(
|
|
855
|
+
session=session.name,
|
|
856
|
+
options=txn_options,
|
|
857
|
+
metadata=call_metadata,
|
|
858
|
+
)
|
|
796
859
|
|
|
797
860
|
txn_selector = TransactionSelector(id=txn.id)
|
|
798
861
|
|
|
@@ -2060,5 +2123,10 @@ def _retry_on_aborted(func, retry_config):
|
|
|
2060
2123
|
:type retry_config: Retry
|
|
2061
2124
|
:param retry_config: retry object with the settings to be used
|
|
2062
2125
|
"""
|
|
2063
|
-
|
|
2126
|
+
|
|
2127
|
+
def _is_aborted(exc):
|
|
2128
|
+
"""Check if exception is Aborted."""
|
|
2129
|
+
return isinstance(exc, Aborted)
|
|
2130
|
+
|
|
2131
|
+
retry = retry_config.with_predicate(_is_aborted)
|
|
2064
2132
|
return retry(func)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Copyright 2026 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
|
+
"""Cloud Spanner exception utilities with request ID support."""
|
|
16
|
+
|
|
17
|
+
from google.api_core.exceptions import GoogleAPICallError
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def wrap_with_request_id(error, request_id=None):
|
|
21
|
+
"""Add request ID information to a GoogleAPICallError.
|
|
22
|
+
|
|
23
|
+
This function adds request_id as an attribute to the exception,
|
|
24
|
+
preserving the original exception type for exception handling compatibility.
|
|
25
|
+
The request_id is also appended to the error message so it appears in logs.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
error: The error to augment. If not a GoogleAPICallError, returns as-is
|
|
29
|
+
request_id (str): The request ID to include
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
The original error with request_id attribute added and message updated
|
|
33
|
+
(if GoogleAPICallError and request_id is provided), otherwise returns
|
|
34
|
+
the original error unchanged.
|
|
35
|
+
"""
|
|
36
|
+
if isinstance(error, GoogleAPICallError) and request_id:
|
|
37
|
+
# Add request_id as an attribute for programmatic access
|
|
38
|
+
error.request_id = request_id
|
|
39
|
+
# Modify the message to include request_id so it appears in logs
|
|
40
|
+
if hasattr(error, "message") and error.message:
|
|
41
|
+
error.message = f"{error.message}, request_id = {request_id}"
|
|
42
|
+
return error
|
|
@@ -20,6 +20,8 @@ are consistently recorded for Cloud Spanner operations, facilitating observabili
|
|
|
20
20
|
performance monitoring.
|
|
21
21
|
"""
|
|
22
22
|
|
|
23
|
+
from contextvars import Token
|
|
24
|
+
|
|
23
25
|
from .spanner_metrics_tracer_factory import SpannerMetricsTracerFactory
|
|
24
26
|
|
|
25
27
|
|
|
@@ -30,6 +32,9 @@ class MetricsCapture:
|
|
|
30
32
|
the start and completion of metrics tracing for a given operation.
|
|
31
33
|
"""
|
|
32
34
|
|
|
35
|
+
_token: Token
|
|
36
|
+
"""Token to reset the context variable after the operation completes."""
|
|
37
|
+
|
|
33
38
|
def __enter__(self):
|
|
34
39
|
"""Enter the runtime context related to this object.
|
|
35
40
|
|
|
@@ -45,11 +50,11 @@ class MetricsCapture:
|
|
|
45
50
|
return self
|
|
46
51
|
|
|
47
52
|
# Define a new metrics tracer for the new operation
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
)
|
|
51
|
-
if
|
|
52
|
-
|
|
53
|
+
# Set the context var and keep the token for reset
|
|
54
|
+
tracer = factory.create_metrics_tracer()
|
|
55
|
+
self._token = SpannerMetricsTracerFactory.set_current_tracer(tracer)
|
|
56
|
+
if tracer:
|
|
57
|
+
tracer.record_operation_start()
|
|
53
58
|
return self
|
|
54
59
|
|
|
55
60
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
@@ -70,6 +75,11 @@ class MetricsCapture:
|
|
|
70
75
|
if not SpannerMetricsTracerFactory().enabled:
|
|
71
76
|
return False
|
|
72
77
|
|
|
73
|
-
|
|
74
|
-
|
|
78
|
+
tracer = SpannerMetricsTracerFactory.get_current_tracer()
|
|
79
|
+
if tracer:
|
|
80
|
+
tracer.record_operation_completion()
|
|
81
|
+
|
|
82
|
+
# Reset the context var using the token
|
|
83
|
+
if getattr(self, "_token", None):
|
|
84
|
+
SpannerMetricsTracerFactory.reset_current_tracer(self._token)
|
|
75
85
|
return False # Propagate the exception if any
|
|
@@ -97,22 +97,17 @@ class MetricsInterceptor(ClientInterceptor):
|
|
|
97
97
|
Args:
|
|
98
98
|
resources (Dict[str, str]): A dictionary containing project, instance, and database information.
|
|
99
99
|
"""
|
|
100
|
-
|
|
100
|
+
tracer = SpannerMetricsTracerFactory.get_current_tracer()
|
|
101
|
+
if tracer is None:
|
|
101
102
|
return
|
|
102
103
|
|
|
103
104
|
if resources:
|
|
104
105
|
if "project" in resources:
|
|
105
|
-
|
|
106
|
-
resources["project"]
|
|
107
|
-
)
|
|
106
|
+
tracer.set_project(resources["project"])
|
|
108
107
|
if "instance" in resources:
|
|
109
|
-
|
|
110
|
-
resources["instance"]
|
|
111
|
-
)
|
|
108
|
+
tracer.set_instance(resources["instance"])
|
|
112
109
|
if "database" in resources:
|
|
113
|
-
|
|
114
|
-
resources["database"]
|
|
115
|
-
)
|
|
110
|
+
tracer.set_database(resources["database"])
|
|
116
111
|
|
|
117
112
|
def intercept(self, invoked_method, request_or_iterator, call_details):
|
|
118
113
|
"""Intercept gRPC calls to collect metrics.
|
|
@@ -126,31 +121,32 @@ class MetricsInterceptor(ClientInterceptor):
|
|
|
126
121
|
The RPC response
|
|
127
122
|
"""
|
|
128
123
|
factory = SpannerMetricsTracerFactory()
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
or not factory.enabled
|
|
132
|
-
):
|
|
124
|
+
tracer = SpannerMetricsTracerFactory.get_current_tracer()
|
|
125
|
+
if tracer is None or not factory.enabled:
|
|
133
126
|
return invoked_method(request_or_iterator, call_details)
|
|
134
127
|
|
|
135
128
|
# Setup Metric Tracer attributes from call details
|
|
136
|
-
## Extract
|
|
137
|
-
|
|
138
|
-
|
|
129
|
+
## Extract Project / Instance / Database from header information if not already set
|
|
130
|
+
if not (
|
|
131
|
+
tracer.client_attributes.get("project_id")
|
|
132
|
+
and tracer.client_attributes.get("instance_id")
|
|
133
|
+
and tracer.client_attributes.get("database")
|
|
134
|
+
):
|
|
135
|
+
resources = self._extract_resource_from_path(call_details.metadata)
|
|
136
|
+
self._set_metrics_tracer_attributes(resources)
|
|
139
137
|
|
|
140
138
|
## Format method to be be spanner.<method name>
|
|
141
139
|
method_name = self._remove_prefix(
|
|
142
140
|
call_details.method, SPANNER_METHOD_PREFIX
|
|
143
141
|
).replace("/", ".")
|
|
144
142
|
|
|
145
|
-
|
|
146
|
-
|
|
143
|
+
tracer.set_method(method_name)
|
|
144
|
+
tracer.record_attempt_start()
|
|
147
145
|
response = invoked_method(request_or_iterator, call_details)
|
|
148
|
-
|
|
146
|
+
tracer.record_attempt_completion()
|
|
149
147
|
|
|
150
148
|
# Process and send GFE metrics if enabled
|
|
151
|
-
if
|
|
149
|
+
if tracer.gfe_enabled:
|
|
152
150
|
metadata = response.initial_metadata()
|
|
153
|
-
|
|
154
|
-
metadata
|
|
155
|
-
)
|
|
151
|
+
tracer.record_gfe_metrics(metadata)
|
|
156
152
|
return response
|
|
@@ -19,6 +19,7 @@ from .metrics_tracer_factory import MetricsTracerFactory
|
|
|
19
19
|
import os
|
|
20
20
|
import logging
|
|
21
21
|
from .constants import SPANNER_SERVICE_NAME
|
|
22
|
+
import contextvars
|
|
22
23
|
|
|
23
24
|
try:
|
|
24
25
|
import mmh3
|
|
@@ -43,7 +44,9 @@ class SpannerMetricsTracerFactory(MetricsTracerFactory):
|
|
|
43
44
|
"""A factory for creating SpannerMetricsTracer instances."""
|
|
44
45
|
|
|
45
46
|
_metrics_tracer_factory: "SpannerMetricsTracerFactory" = None
|
|
46
|
-
|
|
47
|
+
_current_metrics_tracer_ctx = contextvars.ContextVar(
|
|
48
|
+
"current_metrics_tracer", default=None
|
|
49
|
+
)
|
|
47
50
|
|
|
48
51
|
def __new__(
|
|
49
52
|
cls, enabled: bool = True, gfe_enabled: bool = False
|
|
@@ -80,10 +83,22 @@ class SpannerMetricsTracerFactory(MetricsTracerFactory):
|
|
|
80
83
|
cls._metrics_tracer_factory.gfe_enabled = gfe_enabled
|
|
81
84
|
|
|
82
85
|
if cls._metrics_tracer_factory.enabled != enabled:
|
|
83
|
-
cls._metrics_tracer_factory.
|
|
86
|
+
cls._metrics_tracer_factory.enabled = enabled
|
|
84
87
|
|
|
85
88
|
return cls._metrics_tracer_factory
|
|
86
89
|
|
|
90
|
+
@staticmethod
|
|
91
|
+
def get_current_tracer() -> MetricsTracer:
|
|
92
|
+
return SpannerMetricsTracerFactory._current_metrics_tracer_ctx.get()
|
|
93
|
+
|
|
94
|
+
@staticmethod
|
|
95
|
+
def set_current_tracer(tracer: MetricsTracer) -> contextvars.Token:
|
|
96
|
+
return SpannerMetricsTracerFactory._current_metrics_tracer_ctx.set(tracer)
|
|
97
|
+
|
|
98
|
+
@staticmethod
|
|
99
|
+
def reset_current_tracer(token: contextvars.Token):
|
|
100
|
+
SpannerMetricsTracerFactory._current_metrics_tracer_ctx.reset(token)
|
|
101
|
+
|
|
87
102
|
@staticmethod
|
|
88
103
|
def _generate_client_uid() -> str:
|
|
89
104
|
"""Generate a client UID in the form of uuidv4@pid@hostname.
|