Skip to content

Commit

Permalink
Merge branch 'main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
surbhigarg92 authored Oct 16, 2024
2 parents b8654e8 + b2e6762 commit 39c9393
Show file tree
Hide file tree
Showing 28 changed files with 836 additions and 115 deletions.
24 changes: 12 additions & 12 deletions .devcontainer/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
#
# pip-compile --generate-hashes requirements.in
#
argcomplete==3.4.0 \
--hash=sha256:69a79e083a716173e5532e0fa3bef45f793f4e61096cf52b5a42c0211c8b8aa5 \
--hash=sha256:c2abcdfe1be8ace47ba777d4fce319eb13bf8ad9dace8d085dcad6eded88057f
argcomplete==3.5.0 \
--hash=sha256:4349400469dccfb7950bb60334a680c58d88699bff6159df61251878dc6bf74b \
--hash=sha256:d4bcf3ff544f51e16e54228a7ac7f486ed70ebf2ecfe49a63a91171c76bf029b
# via nox
colorlog==6.8.2 \
--hash=sha256:3e3e079a41feb5a1b64f978b5ea4f46040a94f11f0e8bbb8261e3dbbeca64d44 \
Expand All @@ -16,9 +16,9 @@ distlib==0.3.8 \
--hash=sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784 \
--hash=sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64
# via virtualenv
filelock==3.15.4 \
--hash=sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb \
--hash=sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7
filelock==3.16.0 \
--hash=sha256:81de9eb8453c769b63369f87f11131a7ab04e367f8d97ad39dc230daa07e3bec \
--hash=sha256:f6ed4c963184f4c84dd5557ce8fece759a3724b37b80c6c4f20a2f63a4dc6609
# via virtualenv
nox==2024.4.15 \
--hash=sha256:6492236efa15a460ecb98e7b67562a28b70da006ab0be164e8821177577c0565 \
Expand All @@ -28,11 +28,11 @@ packaging==24.1 \
--hash=sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002 \
--hash=sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124
# via nox
platformdirs==4.2.2 \
--hash=sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee \
--hash=sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3
platformdirs==4.3.3 \
--hash=sha256:50a5450e2e84f44539718293cbb1da0a0885c9d14adf21b77bae4e66fc99d9b5 \
--hash=sha256:d4e0b7d8ec176b341fb03cb11ca12d0276faa8c485f9cd218f613840463fc2c0
# via virtualenv
virtualenv==20.26.3 \
--hash=sha256:4c43a2a236279d9ea36a0d76f98d84bd6ca94ac4e0f4a3b9d46d05e10fea542a \
--hash=sha256:8cc4a31139e796e9a7de2cd5cf2489de1217193116a8fd42328f1bd65f434589
virtualenv==20.26.4 \
--hash=sha256:48f2695d9809277003f30776d155615ffc11328e6a0a8c1f0ec80188d7874a55 \
--hash=sha256:c17f4e0f3e6036e9f26700446f85c76ab11df65ff6d8a9cbfad9f71aabfcf23c
# via nox
4 changes: 2 additions & 2 deletions .github/.OwlBot.lock.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@
# limitations under the License.
docker:
image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest
digest: sha256:52210e0e0559f5ea8c52be148b33504022e1faef4e95fbe4b32d68022af2fa7e
# created: 2024-07-08T19:25:35.862283192Z
digest: sha256:e8dcfd7cbfd8beac3a3ff8d3f3185287ea0625d859168cc80faccfc9a7a00455
# created: 2024-09-16T21:04:09.091105552Z
9 changes: 4 additions & 5 deletions .kokoro/docker/docs/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -72,19 +72,18 @@ RUN tar -xvf Python-3.10.14.tgz
RUN ./Python-3.10.14/configure --enable-optimizations
RUN make altinstall

RUN python3.10 -m venv /venv
ENV PATH /venv/bin:$PATH
ENV PATH /usr/local/bin/python3.10:$PATH

###################### Install pip
RUN wget -O /tmp/get-pip.py 'https://bootstrap.pypa.io/get-pip.py' \
&& python3 /tmp/get-pip.py \
&& python3.10 /tmp/get-pip.py \
&& rm /tmp/get-pip.py

# Test pip
RUN python3 -m pip
RUN python3.10 -m pip

# Install build requirements
COPY requirements.txt /requirements.txt
RUN python3 -m pip install --require-hashes -r requirements.txt
RUN python3.10 -m pip install --require-hashes -r requirements.txt

CMD ["python3.10"]
20 changes: 10 additions & 10 deletions .kokoro/publish-docs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,42 +21,42 @@ export PYTHONUNBUFFERED=1
export PATH="${HOME}/.local/bin:${PATH}"

# Install nox
python3 -m pip install --require-hashes -r .kokoro/requirements.txt
python3 -m nox --version
python3.10 -m pip install --require-hashes -r .kokoro/requirements.txt
python3.10 -m nox --version

# build docs
nox -s docs

# create metadata
python3 -m docuploader create-metadata \
python3.10 -m docuploader create-metadata \
--name=$(jq --raw-output '.name // empty' .repo-metadata.json) \
--version=$(python3 setup.py --version) \
--version=$(python3.10 setup.py --version) \
--language=$(jq --raw-output '.language // empty' .repo-metadata.json) \
--distribution-name=$(python3 setup.py --name) \
--distribution-name=$(python3.10 setup.py --name) \
--product-page=$(jq --raw-output '.product_documentation // empty' .repo-metadata.json) \
--github-repository=$(jq --raw-output '.repo // empty' .repo-metadata.json) \
--issue-tracker=$(jq --raw-output '.issue_tracker // empty' .repo-metadata.json)

cat docs.metadata

# upload docs
python3 -m docuploader upload docs/_build/html --metadata-file docs.metadata --staging-bucket "${STAGING_BUCKET}"
python3.10 -m docuploader upload docs/_build/html --metadata-file docs.metadata --staging-bucket "${STAGING_BUCKET}"


# docfx yaml files
nox -s docfx

# create metadata.
python3 -m docuploader create-metadata \
python3.10 -m docuploader create-metadata \
--name=$(jq --raw-output '.name // empty' .repo-metadata.json) \
--version=$(python3 setup.py --version) \
--version=$(python3.10 setup.py --version) \
--language=$(jq --raw-output '.language // empty' .repo-metadata.json) \
--distribution-name=$(python3 setup.py --name) \
--distribution-name=$(python3.10 setup.py --name) \
--product-page=$(jq --raw-output '.product_documentation // empty' .repo-metadata.json) \
--github-repository=$(jq --raw-output '.repo // empty' .repo-metadata.json) \
--issue-tracker=$(jq --raw-output '.issue_tracker // empty' .repo-metadata.json)

cat docs.metadata

# upload docs
python3 -m docuploader upload docs/_build/html/docfx_yaml --metadata-file docs.metadata --destination-prefix docfx --staging-bucket "${V2_STAGING_BUCKET}"
python3.10 -m docuploader upload docs/_build/html/docfx_yaml --metadata-file docs.metadata --destination-prefix docfx --staging-bucket "${V2_STAGING_BUCKET}"
2 changes: 1 addition & 1 deletion .kokoro/release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ python3 -m releasetool publish-reporter-script > /tmp/publisher-script; source /
export PYTHONUNBUFFERED=1

# Move into the package, build the distribution and upload.
TWINE_PASSWORD=$(cat "${KOKORO_KEYSTORE_DIR}/73713_google-cloud-pypi-token-keystore-1")
TWINE_PASSWORD=$(cat "${KOKORO_KEYSTORE_DIR}/73713_google-cloud-pypi-token-keystore-2")
cd github/python-spanner
python3 setup.py sdist bdist_wheel
twine upload --username __token__ --password "${TWINE_PASSWORD}" dist/*
2 changes: 1 addition & 1 deletion .kokoro/release/common.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ before_action {
fetch_keystore {
keystore_resource {
keystore_config_id: 73713
keyname: "google-cloud-pypi-token-keystore-1"
keyname: "google-cloud-pypi-token-keystore-2"
}
}
}
Expand Down
32 changes: 23 additions & 9 deletions docs/opentelemetry-tracing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,46 @@ To take advantage of these traces, we first need to install OpenTelemetry:

.. code-block:: sh
pip install opentelemetry-api opentelemetry-sdk opentelemetry-instrumentation
# [Optional] Installs the cloud monitoring exporter, however you can use any exporter of your choice
pip install opentelemetry-exporter-google-cloud
pip install opentelemetry-api opentelemetry-sdk
pip install opentelemetry-exporter-gcp-trace
We also need to tell OpenTelemetry which exporter to use. To export Spanner traces to `Cloud Tracing <https://cloud.google.com/trace>`_, add the following lines to your application:

.. code:: python
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.trace.sampling import ProbabilitySampler
from opentelemetry.sdk.trace.sampling import TraceIdRatioBased
from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter
# BatchExportSpanProcessor exports spans to Cloud Trace
# BatchSpanProcessor exports spans to Cloud Trace
# in a seperate thread to not block on the main thread
from opentelemetry.sdk.trace.export import BatchExportSpanProcessor
from opentelemetry.sdk.trace.export import BatchSpanProcessor
# Create and export one trace every 1000 requests
sampler = ProbabilitySampler(1/1000)
sampler = TraceIdRatioBased(1/1000)
# Use the default tracer provider
trace.set_tracer_provider(TracerProvider(sampler=sampler))
trace.get_tracer_provider().add_span_processor(
# Initialize the cloud tracing exporter
BatchExportSpanProcessor(CloudTraceSpanExporter())
BatchSpanProcessor(CloudTraceSpanExporter())
)
To get more fine-grained traces from gRPC, you can enable the gRPC instrumentation by the following

.. code-block:: sh
pip install opentelemetry-instrumentation opentelemetry-instrumentation-grpc
and then in your Python code, please add the following lines:

.. code:: python
from opentelemetry.instrumentation.grpc import GrpcInstrumentorClient
grpc_client_instrumentor = GrpcInstrumentorClient()
grpc_client_instrumentor.instrument()
Generated spanner traces should now be available on `Cloud Trace <https://console.cloud.google.com/traces>`_.

Tracing is most effective when many libraries are instrumented to provide insight over the entire lifespan of a request.
Expand Down
73 changes: 73 additions & 0 deletions examples/grpc_instrumentation_enabled.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# -*- coding: utf-8 -*-
# Copyright 2024 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License

import os
import time

import google.cloud.spanner as spanner
from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.sdk.trace.sampling import ALWAYS_ON
from opentelemetry import trace

# Enable the gRPC instrumentation if you'd like more introspection.
from opentelemetry.instrumentation.grpc import GrpcInstrumentorClient

grpc_client_instrumentor = GrpcInstrumentorClient()
grpc_client_instrumentor.instrument()


def main():
# Setup common variables that'll be used between Spanner and traces.
project_id = os.environ.get('SPANNER_PROJECT_ID', 'test-project')

# Setup OpenTelemetry, trace and Cloud Trace exporter.
tracer_provider = TracerProvider(sampler=ALWAYS_ON)
trace_exporter = CloudTraceSpanExporter(project_id=project_id)
tracer_provider.add_span_processor(BatchSpanProcessor(trace_exporter))
trace.set_tracer_provider(tracer_provider)
# Retrieve a tracer from the global tracer provider.
tracer = tracer_provider.get_tracer('MyApp')

# Setup the Cloud Spanner Client.
spanner_client = spanner.Client(project_id)

instance = spanner_client.instance('test-instance')
database = instance.database('test-db')

# Now run our queries
with tracer.start_as_current_span('QueryInformationSchema'):
with database.snapshot() as snapshot:
with tracer.start_as_current_span('InformationSchema'):
info_schema = snapshot.execute_sql(
'SELECT * FROM INFORMATION_SCHEMA.TABLES')
for row in info_schema:
print(row)

with tracer.start_as_current_span('ServerTimeQuery'):
with database.snapshot() as snapshot:
# Purposefully issue a bad SQL statement to examine exceptions
# that get recorded and a ERROR span status.
try:
data = snapshot.execute_sql('SELECT CURRENT_TIMESTAMPx()')
for row in data:
print(row)
except Exception as e:
pass


if __name__ == '__main__':
main()
66 changes: 66 additions & 0 deletions examples/trace.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# -*- coding: utf-8 -*-
# Copyright 2024 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License

import os
import time

import google.cloud.spanner as spanner
from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.sdk.trace.sampling import ALWAYS_ON
from opentelemetry import trace


def main():
# Setup common variables that'll be used between Spanner and traces.
project_id = os.environ.get('SPANNER_PROJECT_ID', 'test-project')

# Setup OpenTelemetry, trace and Cloud Trace exporter.
tracer_provider = TracerProvider(sampler=ALWAYS_ON)
trace_exporter = CloudTraceSpanExporter(project_id=project_id)
tracer_provider.add_span_processor(BatchSpanProcessor(trace_exporter))
trace.set_tracer_provider(tracer_provider)
# Retrieve a tracer from the global tracer provider.
tracer = tracer_provider.get_tracer('MyApp')

# Setup the Cloud Spanner Client.
spanner_client = spanner.Client(project_id)
instance = spanner_client.instance('test-instance')
database = instance.database('test-db')

# Now run our queries
with tracer.start_as_current_span('QueryInformationSchema'):
with database.snapshot() as snapshot:
with tracer.start_as_current_span('InformationSchema'):
info_schema = snapshot.execute_sql(
'SELECT * FROM INFORMATION_SCHEMA.TABLES')
for row in info_schema:
print(row)

with tracer.start_as_current_span('ServerTimeQuery'):
with database.snapshot() as snapshot:
# Purposefully issue a bad SQL statement to examine exceptions
# that get recorded and a ERROR span status.
try:
data = snapshot.execute_sql('SELECT CURRENT_TIMESTAMPx()')
for row in data:
print(row)
except Exception as e:
print(e)


if __name__ == '__main__':
main()
Loading

0 comments on commit 39c9393

Please sign in to comment.