├── .dockerignore ├── .flake8 ├── .github ├── CODEOWNERS ├── header-checker-lint.yml ├── snippet-bot.yml └── workflows │ ├── ci.yaml │ └── codeql-analysis.yml ├── .gitignore ├── .isort.cfg ├── .pylintrc ├── .readthedocs.yml ├── LICENSE ├── README.md ├── SECURITY.md ├── cloudbuild-e2e-cloud-functions-gen2.yaml ├── cloudbuild-e2e-cloud-run.yaml ├── cloudbuild-e2e-gae-standard.yaml ├── cloudbuild-e2e-gae.yaml ├── cloudbuild-e2e-gce.yaml ├── cloudbuild-e2e-gke.yaml ├── cloudbuild-e2e-image.yaml ├── cloudbuild-e2e-local.yaml ├── dev-constraints.txt ├── docs-requirements.txt ├── docs ├── Makefile ├── _static │ └── .gitkeep ├── _templates │ ├── custom-class-template.rst │ └── custom-module-template.rst ├── apireference.rst ├── cloud_monitoring │ └── cloud_monitoring.rst ├── cloud_trace │ ├── cloud_trace.rst │ └── cloud_trace_propagator.rst ├── code-of-conduct.md ├── conf.py ├── contributing.md ├── examples │ ├── cloud_monitoring │ │ ├── README.rst │ │ ├── basic_metrics.py │ │ ├── requirements.in │ │ └── requirements.txt │ ├── cloud_resource_detector │ │ ├── README.rst │ │ ├── requirements.in │ │ ├── requirements.txt │ │ ├── resource_detector_metrics.py │ │ └── resource_detector_trace.py │ ├── cloud_trace_exporter │ │ ├── README.rst │ │ ├── advanced_trace.py │ │ ├── basic_trace.py │ │ ├── requirements.in │ │ └── requirements.txt │ ├── cloud_trace_propagator │ │ ├── README.rst │ │ ├── client.py │ │ ├── requirements.in │ │ ├── requirements.txt │ │ └── server.py │ ├── flask_e2e │ │ ├── README.rst │ │ ├── client.py │ │ ├── gcm_latency.png │ │ ├── gct_result.png │ │ ├── metrics_explorer.png │ │ ├── requirements.in │ │ ├── requirements.txt │ │ └── server.py │ └── prometheus_exemplars │ │ ├── README.rst │ │ ├── docker-compose.yaml │ │ ├── heatmap.png │ │ ├── hey.dockerfile │ │ ├── otel-collector-config.yaml │ │ ├── requirements.in │ │ ├── requirements.txt │ │ ├── select_metric.png │ │ ├── server.dockerfile │ │ ├── server.py │ │ └── trace_details.png ├── index.rst ├── make.bat └── releasing.md ├── e2e-test-server ├── Dockerfile ├── constraints.txt ├── e2e_test_server │ ├── constants.py │ ├── scenarios.py │ ├── server.py │ └── types.py ├── main.py ├── requirements-dockerfile.txt ├── requirements-shared.txt ├── requirements.txt └── wait-for-image.sh ├── get_mock_server.sh ├── opentelemetry-exporter-gcp-logging ├── CHANGELOG.md ├── LICENSE ├── MANIFEST.in ├── README.rst ├── mypy.ini ├── setup.cfg ├── setup.py ├── src │ └── opentelemetry │ │ └── exporter │ │ └── cloud_logging │ │ ├── __init__.py │ │ ├── environment_variables.py │ │ └── version.py └── tests │ ├── __snapshots__ │ └── test_cloud_logging │ │ ├── test_convert_non_json_dict_bytes.json │ │ ├── test_convert_otlp_dict_body.json │ │ ├── test_convert_otlp_various_different_types_in_attrs_and_bytes_body.json │ │ ├── test_convert_various_types_of_bodies[bool].json │ │ └── test_convert_various_types_of_bodies[str].json │ ├── conftest.py │ ├── fixtures │ ├── cloud_logging_fake.py │ └── snapshot_logging_calls.py │ └── test_cloud_logging.py ├── opentelemetry-exporter-gcp-monitoring ├── CHANGELOG.md ├── LICENSE ├── MANIFEST.in ├── README.rst ├── mypy.ini ├── setup.cfg ├── setup.py ├── src │ └── opentelemetry │ │ ├── exporter │ │ └── cloud_monitoring │ │ │ ├── __init__.py │ │ │ ├── environment_variables.py │ │ │ └── version.py │ │ └── py.typed └── tests │ ├── __snapshots__ │ └── test_cloud_monitoring │ │ ├── test_counter[float].json │ │ ├── test_counter[int].json │ │ ├── test_histogram_default_buckets.json │ │ ├── test_histogram_single_bucket.json │ │ ├── test_invalid_label_keys.json │ │ ├── test_observable_counter[float].json │ │ ├── test_observable_counter[int].json │ │ ├── test_observable_gauge[float].json │ │ ├── test_observable_gauge[int].json │ │ ├── test_observable_updowncounter[float].json │ │ ├── test_observable_updowncounter[int].json │ │ ├── test_up_down_counter[float].json │ │ ├── test_up_down_counter[int].json │ │ └── test_with_resource.json │ ├── conftest.py │ ├── fixtures │ ├── gcmfake.py │ └── snapshot_gcmcalls.py │ ├── test_cloud_monitoring.py │ ├── test_cloud_monitoring_auto_instrument.py │ ├── test_normalize_label_key.py │ └── test_user_agent.py ├── opentelemetry-exporter-gcp-trace ├── CHANGELOG.md ├── LICENSE ├── MANIFEST.in ├── README.rst ├── mypy.ini ├── setup.cfg ├── setup.py ├── src │ └── opentelemetry │ │ ├── exporter │ │ └── cloud_trace │ │ │ ├── __init__.py │ │ │ ├── environment_variables.py │ │ │ └── version.py │ │ └── py.typed └── tests │ ├── test_cloud_trace_auto_instrument.py │ ├── test_cloud_trace_exporter.py │ └── test_integration_cloud_trace_exporter.py ├── opentelemetry-propagator-gcp ├── CHANGELOG.md ├── LICENSE ├── MANIFEST.in ├── README.rst ├── mypy.ini ├── setup.cfg ├── setup.py ├── src │ └── opentelemetry │ │ ├── propagators │ │ └── cloud_trace_propagator │ │ │ ├── __init__.py │ │ │ └── version.py │ │ └── py.typed └── tests │ ├── test_cloud_trace_propagator.py │ └── test_cloud_trace_propagator_auto_instrument.py ├── opentelemetry-resourcedetector-gcp ├── CHANGELOG.md ├── LICENSE ├── MANIFEST.in ├── README.rst ├── mypy.ini ├── setup.cfg ├── setup.py ├── src │ └── opentelemetry │ │ ├── py.typed │ │ └── resourcedetector │ │ └── gcp_resource_detector │ │ ├── __init__.py │ │ ├── _constants.py │ │ ├── _detector.py │ │ ├── _faas.py │ │ ├── _gae.py │ │ ├── _gce.py │ │ ├── _gke.py │ │ ├── _mapping.py │ │ ├── _metadata.py │ │ └── version.py └── tests │ ├── __snapshots__ │ ├── test_detector.ambr │ └── test_mapping.ambr │ ├── conftest.py │ ├── test_detector.py │ ├── test_faas.py │ ├── test_gae.py │ ├── test_gce.py │ ├── test_gcp_resource_detector.py │ ├── test_gke.py │ └── test_mapping.py ├── pyproject.toml ├── release.py ├── samples ├── instrumentation-quickstart │ ├── .dockerignore │ ├── Dockerfile │ ├── README.md │ ├── app.py │ ├── cloudbuild-integration.yaml │ ├── docker-compose.cloudbuild.yaml │ ├── docker-compose.creds.yaml │ ├── docker-compose.yaml │ ├── gcp_logging.py │ ├── integrationtest │ │ ├── go.mod │ │ ├── go.sum │ │ └── quickstart_test.go │ ├── otel-collector-config.yaml │ ├── pyproject.toml │ ├── setup_opentelemetry.py │ └── uv.lock ├── langgraph-sql-agent │ ├── .python-version │ ├── README.md │ ├── agent.py │ ├── main.py │ ├── patched_vertexai.py │ ├── pyproject.toml │ ├── requirements.txt │ ├── utils.py │ └── uv.lock ├── otlpmetric │ ├── README.md │ ├── example.py │ └── requirements.txt └── otlptrace │ ├── README.md │ ├── example_grpc.py │ ├── example_http.py │ └── requirements.txt ├── test-common ├── MANIFEST.in ├── setup.cfg ├── setup.py └── src │ └── test_common │ ├── __init__.py │ └── base_exporter_integration_test.py └── tox.ini /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | docs/ 3 | .tox 4 | **/venv/ 5 | .mypy_cache/ 6 | **/__pycache__/ 7 | e2e-test-server/wheels/ 8 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = 3 | E501 # line too long, defer to black 4 | F401 # unused import, defer to pylint 5 | W503 # allow line breaks before binary ops 6 | W504 # allow line breaks after binary ops 7 | E203 # allow whitespace before ':' (https://github.com/psf/black#slices) 8 | exclude = 9 | .git 10 | .tox 11 | CVS 12 | .venv*/ 13 | *venv*/ 14 | target 15 | __pycache__ 16 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Copyright 2023 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 | # https://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 | # Global owners 16 | * @GoogleCloudPlatform/opentelemetry-ops 17 | -------------------------------------------------------------------------------- /.github/header-checker-lint.yml: -------------------------------------------------------------------------------- 1 | allowedLicenses: 2 | - Apache-2.0 3 | allowedCopyrightHolders: 4 | - Google LLC 5 | - The OpenTelemetry Authors 6 | sourceFileExtensions: 7 | - py 8 | - sh 9 | -------------------------------------------------------------------------------- /.github/snippet-bot.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleCloudPlatform/opentelemetry-operations-python/54cb8a6db1f707ecc639e11c0a0d808deca6ac9e/.github/snippet-bot.yml -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: [main] 4 | pull_request: 5 | name: ci 6 | env: 7 | # Bump this to invalidate all caches 8 | cache-version: 1 9 | 10 | jobs: 11 | test: 12 | runs-on: ubuntu-22.04 13 | strategy: 14 | matrix: 15 | py: 16 | - { version: "3.8", tox: "38" } 17 | - { version: "3.9", tox: "39" } 18 | - { version: "3.10", tox: "310" } 19 | - { version: "3.11", tox: "311" } 20 | - { version: "3.12", tox: "312" } 21 | - { version: "3.13", tox: "313" } 22 | env: 23 | run-matrix-combo: ${{ matrix.py.version }} 24 | 25 | name: Test ${{ matrix.py.version }} 26 | steps: 27 | - uses: actions/checkout@v3 28 | - name: Set up Python ${{ matrix.py.version }} 29 | uses: actions/setup-python@v4 30 | with: 31 | python-version: ${{ matrix.py.version }} 32 | - uses: actions/cache@v3 33 | with: 34 | path: ~/.cache/pip 35 | key: ${{ env.cache-version }}-${{ env.run-matrix-combo }}-pip-${{ hashFiles('tox.ini', 'dev-constraints.txt') }} 36 | restore-keys: | 37 | ${{ env.cache-version }}-${{ env.run-matrix-combo }}-pip 38 | - name: Install tox 39 | run: pip install -U tox 40 | - name: Run tox test factors for python ${{ matrix.py.version }} 41 | run: > 42 | tox 43 | --skip-missing-interpreters=true 44 | -f py${{ matrix.py.tox }}-ci 45 | 46 | lint: 47 | runs-on: ubuntu-22.04 48 | strategy: 49 | matrix: 50 | target: [lint-ci, docs-ci, mypy-ci] 51 | py: 52 | - { version: "3.10" } 53 | 54 | env: 55 | run-matrix-combo: ${{ matrix.py.version }}-${{ matrix.target }} 56 | 57 | name: ${{ matrix.target }} 58 | steps: 59 | - uses: actions/checkout@v3 60 | - name: Set up Python ${{ matrix.py.version }} 61 | uses: actions/setup-python@v4 62 | with: 63 | python-version: ${{ matrix.py.version }} 64 | - uses: actions/cache@v3 65 | with: 66 | path: ~/.cache/pip 67 | key: ${{ env.cache-version }}-${{ env.run-matrix-combo }}-pip-${{ hashFiles('tox.ini', 'dev-constraints.txt') }} 68 | restore-keys: | 69 | ${{ env.cache-version }}-${{ env.run-matrix-combo }}-pip 70 | - name: Install tox 71 | run: pip install -U tox 72 | - name: Run tox factors ${{ matrix.target }} 73 | run: tox -f ${{ matrix.target }} 74 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL Analysis" 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | # ┌───────────── minute (0 - 59) 7 | # │ ┌───────────── hour (0 - 23) 8 | # │ │ ┌───────────── day of the month (1 - 31) 9 | # │ │ │ ┌───────────── month (1 - 12 or JAN-DEC) 10 | # │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT) 11 | # │ │ │ │ │ 12 | # │ │ │ │ │ 13 | # │ │ │ │ │ 14 | # * * * * * 15 | - cron: '30 1 * * *' 16 | push: 17 | branches: [ main ] 18 | pull_request: 19 | 20 | jobs: 21 | CodeQL-Build: 22 | runs-on: ubuntu-latest 23 | 24 | steps: 25 | - name: Checkout repository 26 | uses: actions/checkout@v4 27 | 28 | # Initializes the CodeQL tools for scanning. 29 | - name: Initialize CodeQL 30 | uses: github/codeql-action/init@v2 31 | with: 32 | languages: python 33 | 34 | - name: Autobuild 35 | uses: github/codeql-action/autobuild@v2 36 | 37 | - name: Perform CodeQL Analysis 38 | uses: github/codeql-action/analyze@v2 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Outputting junit xmls to here 55 | .test-results/ 56 | 57 | # Translations 58 | *.mo 59 | *.pot 60 | 61 | # Django stuff: 62 | *.log 63 | local_settings.py 64 | db.sqlite3 65 | db.sqlite3-journal 66 | 67 | # Flask stuff: 68 | instance/ 69 | .webassets-cache 70 | 71 | # Scrapy stuff: 72 | .scrapy 73 | 74 | # Sphinx documentation 75 | docs/_build/ 76 | 77 | # PyBuilder 78 | .pybuilder/ 79 | target/ 80 | 81 | # Jupyter Notebook 82 | .ipynb_checkpoints 83 | 84 | # IPython 85 | profile_default/ 86 | ipython_config.py 87 | 88 | # pyenv 89 | # For a library or package, you might want to ignore these files since the code is 90 | # intended to run in multiple environments; otherwise, check them in: 91 | # .python-version 92 | 93 | # pipenv 94 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 95 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 96 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 97 | # install all needed dependencies. 98 | #Pipfile.lock 99 | 100 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 101 | __pypackages__/ 102 | 103 | # Celery stuff 104 | celerybeat-schedule 105 | celerybeat.pid 106 | 107 | # SageMath parsed files 108 | *.sage.py 109 | 110 | # Environments 111 | .env 112 | .venv 113 | env/ 114 | venv/ 115 | ENV/ 116 | env.bak/ 117 | venv.bak/ 118 | myproject/ 119 | 120 | # Spyder project settings 121 | .spyderproject 122 | .spyproject 123 | 124 | # Rope project settings 125 | .ropeproject 126 | 127 | # mkdocs documentation 128 | /site 129 | 130 | # mypy 131 | .mypy_cache/ 132 | .dmypy.json 133 | dmypy.json 134 | 135 | # Pyre type checker 136 | .pyre/ 137 | 138 | # pytype static type analyzer 139 | .pytype/ 140 | 141 | # Cython debug symbols 142 | cython_debug/ 143 | 144 | .vscode/ 145 | 146 | # Sphinx 147 | _build/ 148 | _autosummary/ 149 | -------------------------------------------------------------------------------- /.isort.cfg: -------------------------------------------------------------------------------- 1 | [settings] 2 | profile=black 3 | line_length=79 4 | multi_line_output=3 5 | skip=target 6 | skip_glob=**/gen/*,**/venv/*,**/proto/*,.tox 7 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | # Read the Docs configuration file 2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 3 | version: 2 4 | 5 | sphinx: 6 | configuration: docs/conf.py 7 | 8 | build: 9 | os: ubuntu-22.04 10 | tools: 11 | python: "3.10" 12 | 13 | python: 14 | install: 15 | - requirements: docs-requirements.txt 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Open-Telemetry Operations Exporters for Python 2 | 3 | [![Documentation Status](https://readthedocs.org/projects/google-cloud-opentelemetry/badge/?version=latest)](https://google-cloud-opentelemetry.readthedocs.io/en/latest/?badge=latest) 4 | 5 | 6 | This repo provides OpenTelemetry Python exporters, propagators, and resource detectors 7 | for Google Cloud Platform. 8 | 9 | To get started with instrumentation in Google Cloud, see [Generate traces and metrics with 10 | Python](https://cloud.google.com/stackdriver/docs/instrumentation/setup/python). 11 | 12 | ## Documentation 13 | 14 | To learn more about instrumentation and observability, including opinionated recommendations 15 | for Google Cloud Observability, visit [Instrumentation and 16 | observability](https://cloud.google.com/stackdriver/docs/instrumentation/overview). 17 | 18 | API docs and additional examples are available at 19 | 20 | ## Installation 21 | 22 | All packages are [available on PyPI](https://pypi.org/user/google_opentelemetry/) for installation with `pip`. 23 | 24 | ## Contributing 25 | 26 | See the [contributing guide](docs/contributing.md). 27 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | We support only the last minor version of each supported major release: bug fixes are released either as part of the next minor version or as an on-demand patch version. Independent of which version is next, all patch versions are cumulative, meaning that they represent the state of our main branch at the moment of the release. For instance, if the latest version is 0.10.0, bug fixes are released either as part of 0.11.0 or 0.10.1. 6 | 7 | Major releases are supported for 12 months after a new major version is released: https://opensource.google/documentation/policies/library-breaking-change. 8 | 9 | Security fixes are given priority and might be enough to cause a new version to be released. 10 | 11 | ## Reporting a Vulnerability 12 | 13 | In order for the vulnerability reports to reach maintainers as soon as possible, please use the `Report a vulnerability` button on the `Security` tab in the respective GitHub repository. It creates a private communication channel between the reporter and the maintainers. 14 | 15 | -------------------------------------------------------------------------------- /cloudbuild-e2e-cloud-functions-gen2.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2024 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 | # https://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 | steps: 16 | # Build function source zip with vendored wheels of packages in this monorepo 17 | - name: python:3.11-slim 18 | id: build 19 | script: | 20 | set -xe 21 | apt-get update 22 | apt-get install -y zip 23 | 24 | cd e2e-test-server/ 25 | # package monorepo libraries into wheels in local wheels/ directory 26 | pip wheel \ 27 | --no-deps \ 28 | --wheel-dir wheels \ 29 | ../opentelemetry-exporter-gcp-trace/ \ 30 | ../opentelemetry-resourcedetector-gcp/ \ 31 | ../opentelemetry-propagator-gcp 32 | 33 | zip -qr function-source.zip . 34 | 35 | # Run the test 36 | - name: $_TEST_RUNNER_IMAGE 37 | id: run-tests-cloud-run 38 | dir: / 39 | env: ["PROJECT_ID=$PROJECT_ID"] 40 | args: 41 | - cloud-functions-gen2 42 | - --functionsource=/workspace/e2e-test-server/function-source.zip 43 | - --runtime=python311 44 | - --entrypoint=cloud_functions_handler 45 | 46 | logsBucket: gs://opentelemetry-ops-e2e-cloud-build-logs 47 | substitutions: 48 | _TEST_RUNNER_IMAGE: us-central1-docker.pkg.dev/${PROJECT_ID}/e2e-testing/opentelemetry-operations-e2e-testing:0.20.1 49 | -------------------------------------------------------------------------------- /cloudbuild-e2e-cloud-run.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 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 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License. 13 | 14 | steps: 15 | # Wait for the image to exist 16 | - name: "docker" 17 | id: wait-for-image 18 | entrypoint: "sh" 19 | timeout: 3m 20 | env: ["_TEST_SERVER_IMAGE=${_TEST_SERVER_IMAGE}"] 21 | args: 22 | - e2e-test-server/wait-for-image.sh 23 | 24 | # Run the test 25 | - name: $_TEST_RUNNER_IMAGE 26 | id: run-tests-cloud-run 27 | dir: / 28 | env: ["PROJECT_ID=$PROJECT_ID"] 29 | args: 30 | - cloud-run 31 | - --image=$_TEST_SERVER_IMAGE 32 | 33 | logsBucket: gs://opentelemetry-ops-e2e-cloud-build-logs 34 | substitutions: 35 | _TEST_RUNNER_IMAGE: us-central1-docker.pkg.dev/${PROJECT_ID}/e2e-testing/opentelemetry-operations-e2e-testing:0.20.1 36 | _TEST_SERVER_IMAGE: us-central1-docker.pkg.dev/${PROJECT_ID}/e2e-testing/opentelemetry-operations-python-e2e-test-server:${SHORT_SHA} 37 | -------------------------------------------------------------------------------- /cloudbuild-e2e-gae-standard.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2024 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 | # https://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 | steps: 16 | # Build function source zip with vendored wheels of packages in this monorepo 17 | - name: python:3.11-slim 18 | id: build 19 | script: | 20 | set -xe 21 | apt-get update 22 | apt-get install -y zip 23 | 24 | cd e2e-test-server/ 25 | # package monorepo libraries into wheels in local wheels/ directory 26 | pip wheel \ 27 | --no-deps \ 28 | --wheel-dir wheels \ 29 | ../opentelemetry-exporter-gcp-trace/ \ 30 | ../opentelemetry-resourcedetector-gcp/ \ 31 | ../opentelemetry-propagator-gcp 32 | 33 | zip -qr appsource.zip . 34 | 35 | # Run the test 36 | - name: $_TEST_RUNNER_IMAGE 37 | id: run-tests-gae-standard 38 | dir: / 39 | env: ["PROJECT_ID=$PROJECT_ID"] 40 | args: 41 | - gae-standard 42 | - --runtime=python311 43 | - --entrypoint=python main.py 44 | - --appsource=/workspace/e2e-test-server/appsource.zip 45 | 46 | logsBucket: gs://opentelemetry-ops-e2e-cloud-build-logs 47 | substitutions: 48 | _TEST_RUNNER_IMAGE: us-central1-docker.pkg.dev/${PROJECT_ID}/e2e-testing/opentelemetry-operations-e2e-testing:0.20.1 49 | -------------------------------------------------------------------------------- /cloudbuild-e2e-gae.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2024 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 | # https://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 | steps: 16 | # Wait for the image to exist 17 | - name: "docker" 18 | id: wait-for-image 19 | entrypoint: "sh" 20 | timeout: 10m 21 | env: ["_TEST_SERVER_IMAGE=${_TEST_SERVER_IMAGE}"] 22 | args: 23 | - e2e-test-server/wait-for-image.sh 24 | 25 | # Run the test 26 | - name: $_TEST_RUNNER_IMAGE 27 | id: run-tests-gae 28 | dir: / 29 | env: ["PROJECT_ID=$PROJECT_ID"] 30 | args: 31 | - gae 32 | - --image=$_TEST_SERVER_IMAGE 33 | - --runtime=python 34 | 35 | logsBucket: gs://opentelemetry-ops-e2e-cloud-build-logs 36 | timeout: 20m 37 | substitutions: 38 | _TEST_RUNNER_IMAGE: us-central1-docker.pkg.dev/${PROJECT_ID}/e2e-testing/opentelemetry-operations-e2e-testing:0.20.1 39 | _TEST_SERVER_IMAGE: us-central1-docker.pkg.dev/${PROJECT_ID}/e2e-testing/opentelemetry-operations-python-e2e-test-server:${SHORT_SHA} 40 | -------------------------------------------------------------------------------- /cloudbuild-e2e-gce.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 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 | steps: 16 | # Wait for the image to exist 17 | - name: "docker" 18 | id: wait-for-image 19 | entrypoint: "sh" 20 | timeout: 3m 21 | env: ["_TEST_SERVER_IMAGE=${_TEST_SERVER_IMAGE}"] 22 | args: 23 | - e2e-test-server/wait-for-image.sh 24 | 25 | # Run the test 26 | - name: $_TEST_RUNNER_IMAGE 27 | id: run-tests-gce 28 | dir: / 29 | env: ["PROJECT_ID=$PROJECT_ID"] 30 | args: 31 | - gce 32 | - --image=$_TEST_SERVER_IMAGE 33 | - --health-check-timeout=5m 34 | 35 | logsBucket: gs://opentelemetry-ops-e2e-cloud-build-logs 36 | substitutions: 37 | _TEST_RUNNER_IMAGE: us-central1-docker.pkg.dev/${PROJECT_ID}/e2e-testing/opentelemetry-operations-e2e-testing:0.20.1 38 | _TEST_SERVER_IMAGE: us-central1-docker.pkg.dev/${PROJECT_ID}/e2e-testing/opentelemetry-operations-python-e2e-test-server:${SHORT_SHA} 39 | -------------------------------------------------------------------------------- /cloudbuild-e2e-gke.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 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 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License. 13 | 14 | steps: 15 | # Wait for the image to exist 16 | - name: "docker" 17 | id: wait-for-image 18 | entrypoint: "sh" 19 | timeout: 3m 20 | env: ["_TEST_SERVER_IMAGE=${_TEST_SERVER_IMAGE}"] 21 | args: 22 | - e2e-test-server/wait-for-image.sh 23 | 24 | # Run the test 25 | - name: $_TEST_RUNNER_IMAGE 26 | id: run-tests-gke 27 | dir: / 28 | env: ["PROJECT_ID=$PROJECT_ID"] 29 | args: 30 | - gke 31 | - --image=$_TEST_SERVER_IMAGE 32 | 33 | logsBucket: gs://opentelemetry-ops-e2e-cloud-build-logs 34 | substitutions: 35 | _TEST_RUNNER_IMAGE: us-central1-docker.pkg.dev/${PROJECT_ID}/e2e-testing/opentelemetry-operations-e2e-testing:0.20.1 36 | _TEST_SERVER_IMAGE: us-central1-docker.pkg.dev/${PROJECT_ID}/e2e-testing/opentelemetry-operations-python-e2e-test-server:${SHORT_SHA} 37 | -------------------------------------------------------------------------------- /cloudbuild-e2e-image.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 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 | steps: 16 | - name: docker 17 | entrypoint: "sh" 18 | args: 19 | - -c 20 | - | 21 | if docker manifest inspect ${_TEST_SERVER_IMAGE} > /dev/null; then 22 | echo "Image already exists, will skip building" 23 | exit 24 | fi 25 | 26 | docker build --tag=${_TEST_SERVER_IMAGE} --file=e2e-test-server/Dockerfile . 27 | docker push ${_TEST_SERVER_IMAGE} 28 | 29 | logsBucket: gs://opentelemetry-ops-e2e-cloud-build-logs 30 | substitutions: 31 | _TEST_SERVER_IMAGE: us-central1-docker.pkg.dev/${PROJECT_ID}/e2e-testing/opentelemetry-operations-python-e2e-test-server:${SHORT_SHA} 32 | -------------------------------------------------------------------------------- /cloudbuild-e2e-local.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 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 | steps: 16 | # Wait for the image to exist 17 | - name: "docker" 18 | id: wait-for-image 19 | entrypoint: "sh" 20 | timeout: 3m 21 | env: ["_TEST_SERVER_IMAGE=${_TEST_SERVER_IMAGE}"] 22 | args: 23 | - e2e-test-server/wait-for-image.sh 24 | 25 | - name: "docker" 26 | id: pull-image 27 | args: 28 | - pull 29 | - $_TEST_SERVER_IMAGE 30 | 31 | # Run the test 32 | - name: $_TEST_RUNNER_IMAGE 33 | id: run-tests-local 34 | dir: / 35 | env: ["PROJECT_ID=$PROJECT_ID"] 36 | args: 37 | - local 38 | - --image=$_TEST_SERVER_IMAGE 39 | - --network=cloudbuild 40 | 41 | logsBucket: gs://opentelemetry-ops-e2e-cloud-build-logs 42 | substitutions: 43 | _TEST_RUNNER_IMAGE: us-central1-docker.pkg.dev/${PROJECT_ID}/e2e-testing/opentelemetry-operations-e2e-testing:0.20.1 44 | _TEST_SERVER_IMAGE: us-central1-docker.pkg.dev/${PROJECT_ID}/e2e-testing/opentelemetry-operations-python-e2e-test-server:${SHORT_SHA} 45 | -------------------------------------------------------------------------------- /dev-constraints.txt: -------------------------------------------------------------------------------- 1 | black==22.3.0 2 | flake8==3.9.2 3 | # 3rd party package until https://github.com/googleapis/python-api-common-protos/issues/135 is 4 | # fixed 5 | googleapis-common-protos-stubs==2.1.0 6 | isort==5.8.0 7 | mypy-extensions==0.4.3 8 | mypy==0.982 9 | pylint==2.8.3 10 | Sphinx==7.2.6 11 | syrupy==3.0.4 12 | types-protobuf==3.20.4.2 13 | types-requests==2.28.11.2 14 | types-setuptools==65.5.0.2 15 | types-urllib3==1.26.25.1 16 | setuptools==69.5.1 17 | 18 | # pinned for snapshot tests. this should be bumped regularly and snapshots updated by running 19 | # tox -f py311-test -- --snapshot-update 20 | opentelemetry-api==1.30.0 21 | opentelemetry-sdk==1.30.0 22 | -------------------------------------------------------------------------------- /docs-requirements.txt: -------------------------------------------------------------------------------- 1 | -c dev-constraints.txt 2 | Sphinx 3 | sphinx-autodoc-typehints 4 | -e ./opentelemetry-exporter-gcp-trace 5 | -e ./opentelemetry-exporter-gcp-monitoring 6 | -e ./opentelemetry-propagator-gcp 7 | -e ./opentelemetry-resourcedetector-gcp 8 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/_static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleCloudPlatform/opentelemetry-operations-python/54cb8a6db1f707ecc639e11c0a0d808deca6ac9e/docs/_static/.gitkeep -------------------------------------------------------------------------------- /docs/_templates/custom-class-template.rst: -------------------------------------------------------------------------------- 1 | {{ fullname | escape | underline}} 2 | 3 | .. currentmodule:: {{ module }} 4 | 5 | .. autoclass:: {{ objname }} 6 | :members: 7 | :show-inheritance: 8 | :inherited-members: 9 | :special-members: __call__, __add__, __mul__ 10 | 11 | {% block methods %} 12 | {% if methods %} 13 | .. rubric:: {{ _('Methods') }} 14 | 15 | .. autosummary:: 16 | :nosignatures: 17 | {% for item in methods %} 18 | {%- if not item.startswith('_') %} 19 | ~{{ name }}.{{ item }} 20 | {%- endif -%} 21 | {%- endfor %} 22 | {% endif %} 23 | {% endblock %} 24 | 25 | {% block attributes %} 26 | {% if attributes %} 27 | .. rubric:: {{ _('Attributes') }} 28 | 29 | .. autosummary:: 30 | {% for item in attributes %} 31 | ~{{ name }}.{{ item }} 32 | {%- endfor %} 33 | {% endif %} 34 | {% endblock %} 35 | -------------------------------------------------------------------------------- /docs/_templates/custom-module-template.rst: -------------------------------------------------------------------------------- 1 | {{ fullname | escape | underline}} 2 | 3 | .. automodule:: {{ fullname }} 4 | 5 | {% block attributes %} 6 | {% if attributes %} 7 | .. rubric:: Module attributes 8 | 9 | .. autosummary:: 10 | :toctree: 11 | {% for item in attributes %} 12 | {{ item }} 13 | {%- endfor %} 14 | {% endif %} 15 | {% endblock %} 16 | 17 | {% block functions %} 18 | {% if functions %} 19 | .. rubric:: {{ _('Functions') }} 20 | 21 | .. autosummary:: 22 | :toctree: 23 | :nosignatures: 24 | {% for item in functions %} 25 | {{ item }} 26 | {%- endfor %} 27 | {% endif %} 28 | {% endblock %} 29 | 30 | {% block classes %} 31 | {% if classes %} 32 | .. rubric:: {{ _('Classes') }} 33 | 34 | .. autosummary:: 35 | :toctree: 36 | :template: custom-class-template.rst 37 | :nosignatures: 38 | {% for item in classes %} 39 | {{ item }} 40 | {%- endfor %} 41 | {% endif %} 42 | {% endblock %} 43 | 44 | {% block exceptions %} 45 | {% if exceptions %} 46 | .. rubric:: {{ _('Exceptions') }} 47 | 48 | .. autosummary:: 49 | :toctree: 50 | {% for item in exceptions %} 51 | {{ item }} 52 | {%- endfor %} 53 | {% endif %} 54 | {% endblock %} 55 | 56 | {% block modules %} 57 | {% if modules %} 58 | .. autosummary:: 59 | :toctree: 60 | :template: custom-module-template.rst 61 | :recursive: 62 | {% for item in modules %} 63 | {{ item }} 64 | {%- endfor %} 65 | {% endif %} 66 | {% endblock %} 67 | -------------------------------------------------------------------------------- /docs/apireference.rst: -------------------------------------------------------------------------------- 1 | API Reference 2 | ============= 3 | 4 | .. 5 | The above .. prevents the autosummary table from rendering in the 6 | document, but still causes the recursive generation of autodoc stub files. 7 | 8 | .. autosummary:: 9 | :toctree: _autosummary 10 | :caption: API Reference 11 | :template: custom-module-template.rst 12 | :recursive: 13 | 14 | opentelemetry.exporter 15 | opentelemetry.propagators.cloud_trace_propagator 16 | opentelemetry.resourcedetector 17 | 18 | 19 | .. toctree:: 20 | :maxdepth: 5 21 | :caption: API Reference 22 | :name: apireference 23 | 24 | _autosummary/opentelemetry.exporter 25 | _autosummary/opentelemetry.propagators.cloud_trace_propagator 26 | _autosummary/opentelemetry.resourcedetector 27 | -------------------------------------------------------------------------------- /docs/cloud_monitoring/cloud_monitoring.rst: -------------------------------------------------------------------------------- 1 | OpenTelemetry Cloud Monitoring Exporter 2 | ======================================= 3 | 4 | .. image:: https://badge.fury.io/py/opentelemetry-exporter-gcp-monitoring.svg 5 | :target: https://badge.fury.io/py/opentelemetry-exporter-gcp-monitoring 6 | 7 | .. automodule:: opentelemetry.exporter.cloud_monitoring 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | :noindex: 12 | -------------------------------------------------------------------------------- /docs/cloud_trace/cloud_trace.rst: -------------------------------------------------------------------------------- 1 | OpenTelemetry Cloud Trace Exporter 2 | ================================== 3 | 4 | .. image:: https://badge.fury.io/py/opentelemetry-exporter-gcp-trace.svg 5 | :target: https://badge.fury.io/py/opentelemetry-exporter-gcp-trace 6 | 7 | .. automodule:: opentelemetry.exporter.cloud_trace 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | :noindex: 12 | -------------------------------------------------------------------------------- /docs/cloud_trace/cloud_trace_propagator.rst: -------------------------------------------------------------------------------- 1 | OpenTelemetry Cloud Trace Propagator 2 | ================================== 3 | 4 | .. image:: https://badge.fury.io/py/opentelemetry-propagator-gcp.svg 5 | :target: https://badge.fury.io/py/opentelemetry-propagator-gcp 6 | 7 | .. automodule:: opentelemetry.propagators.cloud_trace_propagator 8 | :members: 9 | :undoc-members: 10 | :show-inheritance: 11 | :noindex: 12 | -------------------------------------------------------------------------------- /docs/examples/cloud_monitoring/README.rst: -------------------------------------------------------------------------------- 1 | Cloud Monitoring Exporter Example 2 | ================================= 3 | 4 | These examples show how to use OpenTelemetry to send metrics data to Cloud Monitoring. 5 | 6 | 7 | Basic Example 8 | ------------- 9 | 10 | To use this exporter you first need to: 11 | 12 | * `Create a Google Cloud project `_. 13 | * Set up `Application Default Credentials 14 | `_ by `installing 15 | gcloud `_ and running ``gcloud auth 16 | application-default login``. 17 | 18 | * Installation 19 | 20 | .. code-block:: sh 21 | 22 | pip install opentelemetry-exporter-gcp-monitoring \ 23 | opentelemetry-api \ 24 | opentelemetry-sdk 25 | 26 | * Run example code 27 | 28 | .. literalinclude:: basic_metrics.py 29 | :language: python 30 | :lines: 1- 31 | 32 | Viewing Output 33 | -------------------------- 34 | 35 | After running the example: 36 | 37 | * Go to the `Cloud Monitoring Metrics Explorer page `_. 38 | * In "Select a Metric" enter "workload.googleapis.com/request_counter". 39 | * You can filter by labels and change the graphical output here as well. 40 | 41 | Troubleshooting 42 | -------------------------- 43 | 44 | ``One or more points were written more frequently than the maximum sampling period configured for the metric`` 45 | ############################################################################################################## 46 | 47 | Currently, Cloud Monitoring allows one write every 5 seconds for any unique tuple (metric_name, metric_label_value_1, metric_label_value_2, ...). The exporter should rate limit on its own but issues arise if: 48 | 49 | * You are restarting the server more than once every 5 seconds. 50 | * You have a multiple exporters (possibly on different threads) writing to the same tuple. 51 | 52 | For both cases, you can pass ``add_unique_identifier=True`` to the CloudMonitoringMetricsExporter constructor. This adds a UUID label_value, making the tuple unique again. For the first case, you can also choose to just wait longer than 5 seconds between restarts. 53 | -------------------------------------------------------------------------------- /docs/examples/cloud_monitoring/basic_metrics.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright 2021 The OpenTelemetry Authors 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | import time 17 | 18 | from opentelemetry import metrics 19 | from opentelemetry.exporter.cloud_monitoring import ( 20 | CloudMonitoringMetricsExporter, 21 | ) 22 | from opentelemetry.sdk.metrics import MeterProvider 23 | from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader 24 | from opentelemetry.sdk.resources import Resource 25 | 26 | metrics.set_meter_provider( 27 | MeterProvider( 28 | metric_readers=[ 29 | PeriodicExportingMetricReader( 30 | CloudMonitoringMetricsExporter(), export_interval_millis=5000 31 | ) 32 | ], 33 | resource=Resource.create( 34 | { 35 | "service.name": "basic_metrics", 36 | "service.namespace": "examples", 37 | "service.instance.id": "instance123", 38 | } 39 | ), 40 | ) 41 | ) 42 | meter = metrics.get_meter(__name__) 43 | 44 | # Creates metric workload.googleapis.com/request_counter with monitored resource generic_task 45 | requests_counter = meter.create_counter( 46 | name="request_counter", 47 | description="number of requests", 48 | unit="1", 49 | ) 50 | 51 | staging_labels = {"environment": "staging"} 52 | 53 | for i in range(20): 54 | requests_counter.add(25, staging_labels) 55 | time.sleep(5) 56 | -------------------------------------------------------------------------------- /docs/examples/cloud_monitoring/requirements.in: -------------------------------------------------------------------------------- 1 | -e ../../../opentelemetry-exporter-gcp-monitoring 2 | -e ../../../opentelemetry-resourcedetector-gcp 3 | opentelemetry-api 4 | opentelemetry-sdk 5 | -------------------------------------------------------------------------------- /docs/examples/cloud_monitoring/requirements.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.11 3 | # by the following command: 4 | # 5 | # pip-compile --output-file=requirements.txt requirements.in 6 | # 7 | -e file:///usr/local/google/home/aaronabbott/repo/opentelemetry-operations-python/opentelemetry-exporter-gcp-monitoring 8 | # via -r requirements.in 9 | -e file:///usr/local/google/home/aaronabbott/repo/opentelemetry-operations-python/opentelemetry-resourcedetector-gcp 10 | # via 11 | # -r requirements.in 12 | # opentelemetry-exporter-gcp-monitoring 13 | cachetools==5.4.0 14 | # via google-auth 15 | certifi==2024.7.4 16 | # via requests 17 | charset-normalizer==3.3.2 18 | # via requests 19 | deprecated==1.2.14 20 | # via opentelemetry-api 21 | google-api-core[grpc]==2.19.1 22 | # via google-cloud-monitoring 23 | google-auth==2.32.0 24 | # via 25 | # google-api-core 26 | # google-cloud-monitoring 27 | google-cloud-monitoring==2.22.1 28 | # via opentelemetry-exporter-gcp-monitoring 29 | googleapis-common-protos==1.63.2 30 | # via 31 | # google-api-core 32 | # grpcio-status 33 | grpcio==1.64.1 34 | # via 35 | # google-api-core 36 | # grpcio-status 37 | grpcio-status==1.64.1 38 | # via google-api-core 39 | idna==3.7 40 | # via requests 41 | importlib-metadata==7.1.0 42 | # via opentelemetry-api 43 | opentelemetry-api==1.25.0 44 | # via 45 | # -r requirements.in 46 | # opentelemetry-exporter-gcp-monitoring 47 | # opentelemetry-resourcedetector-gcp 48 | # opentelemetry-sdk 49 | # opentelemetry-semantic-conventions 50 | opentelemetry-sdk==1.25.0 51 | # via 52 | # -r requirements.in 53 | # opentelemetry-exporter-gcp-monitoring 54 | # opentelemetry-resourcedetector-gcp 55 | opentelemetry-semantic-conventions==0.46b0 56 | # via opentelemetry-sdk 57 | proto-plus==1.24.0 58 | # via 59 | # google-api-core 60 | # google-cloud-monitoring 61 | protobuf==5.27.2 62 | # via 63 | # google-api-core 64 | # google-cloud-monitoring 65 | # googleapis-common-protos 66 | # grpcio-status 67 | # proto-plus 68 | pyasn1==0.6.0 69 | # via 70 | # pyasn1-modules 71 | # rsa 72 | pyasn1-modules==0.4.0 73 | # via google-auth 74 | requests==2.32.3 75 | # via 76 | # google-api-core 77 | # opentelemetry-resourcedetector-gcp 78 | rsa==4.9 79 | # via google-auth 80 | typing-extensions==4.12.2 81 | # via 82 | # opentelemetry-resourcedetector-gcp 83 | # opentelemetry-sdk 84 | urllib3==2.2.2 85 | # via requests 86 | wrapt==1.16.0 87 | # via deprecated 88 | zipp==3.19.2 89 | # via importlib-metadata 90 | -------------------------------------------------------------------------------- /docs/examples/cloud_resource_detector/requirements.in: -------------------------------------------------------------------------------- 1 | -e ../../../opentelemetry-exporter-gcp-monitoring 2 | -e ../../../opentelemetry-exporter-gcp-trace 3 | -e ../../../opentelemetry-resourcedetector-gcp 4 | opentelemetry-api 5 | opentelemetry-sdk 6 | -------------------------------------------------------------------------------- /docs/examples/cloud_resource_detector/resource_detector_metrics.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright 2021 The OpenTelemetry Authors 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | import time 17 | 18 | from opentelemetry import metrics 19 | from opentelemetry.exporter.cloud_monitoring import ( 20 | CloudMonitoringMetricsExporter, 21 | ) 22 | from opentelemetry.sdk.metrics import MeterProvider 23 | from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader 24 | from opentelemetry.sdk.resources import get_aggregated_resources 25 | from opentelemetry.resourcedetector.gcp_resource_detector import ( 26 | GoogleCloudResourceDetector, 27 | ) 28 | 29 | resource = get_aggregated_resources( 30 | [GoogleCloudResourceDetector(raise_on_error=True)] 31 | ) 32 | 33 | meter_provider = MeterProvider( 34 | resource=resource, 35 | metric_readers=[ 36 | PeriodicExportingMetricReader( 37 | CloudMonitoringMetricsExporter(), export_interval_millis=5000 38 | ) 39 | ], 40 | ) 41 | metrics.set_meter_provider(meter_provider) 42 | meter = metrics.get_meter(__name__) 43 | 44 | requests_counter = meter.create_counter( 45 | name="request_counter_with_resource", 46 | description="number of requests", 47 | unit="1", 48 | ) 49 | 50 | staging_labels = {"environment": "staging"} 51 | 52 | for i in range(20): 53 | requests_counter.add(25, staging_labels) 54 | time.sleep(10) 55 | -------------------------------------------------------------------------------- /docs/examples/cloud_resource_detector/resource_detector_trace.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright 2021 The OpenTelemetry Authors 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | from opentelemetry import trace 17 | from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter 18 | from opentelemetry.sdk.resources import get_aggregated_resources 19 | from opentelemetry.sdk.trace import TracerProvider 20 | from opentelemetry.sdk.trace.export import BatchSpanProcessor 21 | from opentelemetry.resourcedetector.gcp_resource_detector import ( 22 | GoogleCloudResourceDetector, 23 | ) 24 | 25 | resource = get_aggregated_resources( 26 | [GoogleCloudResourceDetector(raise_on_error=True)] 27 | ) 28 | 29 | # Pass the detected resources to the provider, which will in turn pass it to all 30 | # created spans 31 | trace.set_tracer_provider(TracerProvider(resource=resource)) 32 | 33 | # Cloud Trace exporter will automatically format these resources and export 34 | cloud_trace_exporter = CloudTraceSpanExporter( 35 | # send all resource attributes 36 | resource_regex=r".*" 37 | ) 38 | trace.get_tracer_provider().add_span_processor( 39 | BatchSpanProcessor(cloud_trace_exporter) 40 | ) 41 | tracer = trace.get_tracer(__name__) 42 | with tracer.start_as_current_span("foo"): 43 | print("Hello world!") 44 | -------------------------------------------------------------------------------- /docs/examples/cloud_trace_exporter/basic_trace.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 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 | from opentelemetry import trace 16 | from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter 17 | from opentelemetry.sdk.trace import TracerProvider 18 | from opentelemetry.sdk.trace.export import BatchSpanProcessor 19 | 20 | trace.set_tracer_provider(TracerProvider()) 21 | 22 | cloud_trace_exporter = CloudTraceSpanExporter() 23 | trace.get_tracer_provider().add_span_processor( 24 | BatchSpanProcessor(cloud_trace_exporter) 25 | ) 26 | tracer = trace.get_tracer(__name__) 27 | with tracer.start_as_current_span("foo"): 28 | print("Hello world!") 29 | -------------------------------------------------------------------------------- /docs/examples/cloud_trace_exporter/requirements.in: -------------------------------------------------------------------------------- 1 | -e ../../../opentelemetry-exporter-gcp-trace 2 | -e ../../../opentelemetry-resourcedetector-gcp 3 | opentelemetry-api 4 | opentelemetry-sdk 5 | -------------------------------------------------------------------------------- /docs/examples/cloud_trace_exporter/requirements.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.11 3 | # by the following command: 4 | # 5 | # pip-compile --output-file=requirements.txt requirements.in 6 | # 7 | -e file:///usr/local/google/home/aaronabbott/repo/opentelemetry-operations-python/opentelemetry-exporter-gcp-trace 8 | # via -r requirements.in 9 | -e file:///usr/local/google/home/aaronabbott/repo/opentelemetry-operations-python/opentelemetry-resourcedetector-gcp 10 | # via 11 | # -r requirements.in 12 | # opentelemetry-exporter-gcp-trace 13 | cachetools==5.4.0 14 | # via google-auth 15 | certifi==2024.7.4 16 | # via requests 17 | charset-normalizer==3.3.2 18 | # via requests 19 | deprecated==1.2.14 20 | # via opentelemetry-api 21 | google-api-core[grpc]==2.19.1 22 | # via google-cloud-trace 23 | google-auth==2.32.0 24 | # via 25 | # google-api-core 26 | # google-cloud-trace 27 | google-cloud-trace==1.13.4 28 | # via opentelemetry-exporter-gcp-trace 29 | googleapis-common-protos==1.63.2 30 | # via 31 | # google-api-core 32 | # grpcio-status 33 | grpcio==1.64.1 34 | # via 35 | # google-api-core 36 | # grpcio-status 37 | grpcio-status==1.64.1 38 | # via google-api-core 39 | idna==3.7 40 | # via requests 41 | importlib-metadata==7.1.0 42 | # via opentelemetry-api 43 | opentelemetry-api==1.25.0 44 | # via 45 | # -r requirements.in 46 | # opentelemetry-exporter-gcp-trace 47 | # opentelemetry-resourcedetector-gcp 48 | # opentelemetry-sdk 49 | # opentelemetry-semantic-conventions 50 | opentelemetry-sdk==1.25.0 51 | # via 52 | # -r requirements.in 53 | # opentelemetry-exporter-gcp-trace 54 | # opentelemetry-resourcedetector-gcp 55 | opentelemetry-semantic-conventions==0.46b0 56 | # via opentelemetry-sdk 57 | proto-plus==1.24.0 58 | # via 59 | # google-api-core 60 | # google-cloud-trace 61 | protobuf==5.27.2 62 | # via 63 | # google-api-core 64 | # google-cloud-trace 65 | # googleapis-common-protos 66 | # grpcio-status 67 | # proto-plus 68 | pyasn1==0.6.0 69 | # via 70 | # pyasn1-modules 71 | # rsa 72 | pyasn1-modules==0.4.0 73 | # via google-auth 74 | requests==2.32.3 75 | # via 76 | # google-api-core 77 | # opentelemetry-resourcedetector-gcp 78 | rsa==4.9 79 | # via google-auth 80 | typing-extensions==4.12.2 81 | # via 82 | # opentelemetry-resourcedetector-gcp 83 | # opentelemetry-sdk 84 | urllib3==2.2.2 85 | # via requests 86 | wrapt==1.16.0 87 | # via deprecated 88 | zipp==3.19.2 89 | # via importlib-metadata 90 | -------------------------------------------------------------------------------- /docs/examples/cloud_trace_propagator/README.rst: -------------------------------------------------------------------------------- 1 | Cloud Trace Propagator Example 2 | ============================== 3 | 4 | These examples show how to make OpenTelemetry use the 5 | ``X-Cloud-Trace-Context`` header for context propagation. 6 | 7 | 8 | Basic Example 9 | ------------- 10 | 11 | To use this feature you first need to: 12 | 13 | * Create a Google Cloud project. You can `create one here `_. 14 | * Set up `Application Default Credentials 15 | `_ by `installing 16 | gcloud `_ and running ``gcloud auth 17 | application-default login``. 18 | 19 | 20 | * Installation 21 | 22 | .. code-block:: sh 23 | 24 | pip install opentelemetry-api \ 25 | opentelemetry-sdk \ 26 | opentelemetry-instrumentation-flask \ 27 | opentelemetry-instrumentation-requests \ 28 | opentelemetry-exporter-gcp-trace \ 29 | opentelemetry-propagator-gcp \ 30 | Flask 31 | 32 | * Create a server that uses the Cloud Trace header 33 | 34 | .. literalinclude:: server.py 35 | :language: python 36 | :lines: 1- 37 | 38 | * Make a client that uses the Cloud Trace header 39 | 40 | .. literalinclude:: client.py 41 | :language: python 42 | :lines: 1- 43 | 44 | 45 | Checking Output 46 | -------------------------- 47 | 48 | After running these examples, you can go to `Cloud Trace overview `_ to see the results. 49 | -------------------------------------------------------------------------------- /docs/examples/cloud_trace_propagator/client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright 2021 The OpenTelemetry Authors 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | from opentelemetry.instrumentation.requests import RequestsInstrumentor 17 | import requests 18 | from opentelemetry import trace 19 | from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter 20 | from opentelemetry.propagate import set_global_textmap 21 | from opentelemetry.sdk.trace import TracerProvider 22 | from opentelemetry.sdk.trace.export import BatchSpanProcessor 23 | from opentelemetry.propagators.cloud_trace_propagator import ( 24 | CloudTraceFormatPropagator, 25 | ) 26 | 27 | # Instrumenting requests 28 | RequestsInstrumentor().instrument() 29 | 30 | # Tracer boilerplate 31 | trace.set_tracer_provider(TracerProvider()) 32 | trace.get_tracer_provider().add_span_processor( 33 | BatchSpanProcessor(CloudTraceSpanExporter()) 34 | ) 35 | 36 | # Using the X-Cloud-Trace-Context header 37 | set_global_textmap(CloudTraceFormatPropagator()) 38 | 39 | tracer = trace.get_tracer(__name__) 40 | with tracer.start_as_current_span("client_span"): 41 | response = requests.get("http://localhost:5000/") 42 | -------------------------------------------------------------------------------- /docs/examples/cloud_trace_propagator/requirements.in: -------------------------------------------------------------------------------- 1 | -e ../../../opentelemetry-exporter-gcp-monitoring 2 | -e ../../../opentelemetry-exporter-gcp-trace 3 | -e ../../../opentelemetry-propagator-gcp 4 | -e ../../../opentelemetry-resourcedetector-gcp 5 | flask 6 | opentelemetry-api 7 | opentelemetry-instrumentation-flask 8 | opentelemetry-instrumentation-requests 9 | opentelemetry-sdk 10 | requests 11 | -------------------------------------------------------------------------------- /docs/examples/cloud_trace_propagator/server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright 2021 The OpenTelemetry Authors 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | from opentelemetry.instrumentation.requests import RequestsInstrumentor 17 | from opentelemetry.instrumentation.flask import FlaskInstrumentor 18 | from opentelemetry import trace 19 | from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter 20 | from opentelemetry.instrumentation.flask import FlaskInstrumentor 21 | from opentelemetry.propagate import set_global_textmap 22 | from opentelemetry.sdk.trace import TracerProvider 23 | from opentelemetry.sdk.trace.export import BatchSpanProcessor 24 | from opentelemetry.propagators.cloud_trace_propagator import ( 25 | CloudTraceFormatPropagator, 26 | ) 27 | 28 | from flask import Flask 29 | 30 | # Instrumenting requests 31 | RequestsInstrumentor().instrument() 32 | 33 | # Instrumenting flask 34 | app = Flask(__name__) 35 | FlaskInstrumentor().instrument_app(app) 36 | 37 | # Tracer boilerplate 38 | trace.set_tracer_provider(TracerProvider()) 39 | trace.get_tracer_provider().add_span_processor( 40 | BatchSpanProcessor(CloudTraceSpanExporter()) 41 | ) 42 | 43 | # Using the X-Cloud-Trace-Context header 44 | set_global_textmap(CloudTraceFormatPropagator()) 45 | 46 | 47 | @app.route("/") 48 | def hello_world(): 49 | tracer = trace.get_tracer(__name__) 50 | with tracer.start_as_current_span("server_span"): 51 | return "Hello World!" 52 | 53 | 54 | if __name__ == "__main__": 55 | port = 5000 56 | app.run(port=port) 57 | -------------------------------------------------------------------------------- /docs/examples/flask_e2e/client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright 2021 The OpenTelemetry Authors 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | import requests 17 | from opentelemetry import metrics, trace 18 | from opentelemetry.exporter.cloud_monitoring import ( 19 | CloudMonitoringMetricsExporter, 20 | ) 21 | from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter 22 | from opentelemetry.instrumentation.requests import RequestsInstrumentor 23 | from opentelemetry.propagate import set_global_textmap 24 | from opentelemetry.propagators.cloud_trace_propagator import ( 25 | CloudTraceFormatPropagator, 26 | ) 27 | from opentelemetry.sdk.metrics import MeterProvider 28 | from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader 29 | from opentelemetry.sdk.resources import Resource 30 | from opentelemetry.sdk.trace import TracerProvider 31 | from opentelemetry.sdk.trace.export import BatchSpanProcessor 32 | 33 | set_global_textmap(CloudTraceFormatPropagator()) 34 | 35 | resource = Resource.create( 36 | { 37 | "service.name": "flask_e2e_client", 38 | "service.namespace": "examples", 39 | "service.instance.id": "instance554", 40 | } 41 | ) 42 | 43 | tracer_provider = TracerProvider() 44 | cloud_trace_exporter = CloudTraceSpanExporter() 45 | tracer_provider.add_span_processor( 46 | # BatchSpanProcessor buffers spans and sends them in batches in a 47 | # background thread. The default parameters are sensible, but can be 48 | # tweaked to optimize your performance 49 | BatchSpanProcessor(cloud_trace_exporter) 50 | ) 51 | 52 | meter_provider = MeterProvider( 53 | metric_readers=[ 54 | PeriodicExportingMetricReader( 55 | CloudMonitoringMetricsExporter(), export_interval_millis=5000 56 | ) 57 | ], 58 | resource=resource, 59 | ) 60 | 61 | trace.set_tracer_provider(tracer_provider) 62 | metrics.set_meter_provider(meter_provider) 63 | 64 | tracer = trace.get_tracer(__name__) 65 | meter = metrics.get_meter(__name__) 66 | 67 | RequestsInstrumentor().instrument() 68 | 69 | res = requests.get("http://localhost:6000") 70 | print(res.text) 71 | -------------------------------------------------------------------------------- /docs/examples/flask_e2e/gcm_latency.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleCloudPlatform/opentelemetry-operations-python/54cb8a6db1f707ecc639e11c0a0d808deca6ac9e/docs/examples/flask_e2e/gcm_latency.png -------------------------------------------------------------------------------- /docs/examples/flask_e2e/gct_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleCloudPlatform/opentelemetry-operations-python/54cb8a6db1f707ecc639e11c0a0d808deca6ac9e/docs/examples/flask_e2e/gct_result.png -------------------------------------------------------------------------------- /docs/examples/flask_e2e/metrics_explorer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleCloudPlatform/opentelemetry-operations-python/54cb8a6db1f707ecc639e11c0a0d808deca6ac9e/docs/examples/flask_e2e/metrics_explorer.png -------------------------------------------------------------------------------- /docs/examples/flask_e2e/requirements.in: -------------------------------------------------------------------------------- 1 | -e ../../../opentelemetry-exporter-gcp-monitoring 2 | -e ../../../opentelemetry-exporter-gcp-trace 3 | -e ../../../opentelemetry-propagator-gcp 4 | -e ../../../opentelemetry-resourcedetector-gcp 5 | flask 6 | opentelemetry-api 7 | opentelemetry-instrumentation-flask 8 | opentelemetry-instrumentation-requests 9 | opentelemetry-sdk 10 | requests 11 | -------------------------------------------------------------------------------- /docs/examples/prometheus_exemplars/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 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 | # https://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 | services: 16 | # OpenTelemetry collector. Make sure you set USERID and GOOGLE_APPLICATION_CREDENTIALS 17 | # environment variables for your container to authenticate correctly 18 | otel-collector: 19 | user: ${USERID?set USERID=$(id -u)} 20 | image: otel/opentelemetry-collector-contrib:0.77.0 21 | environment: 22 | - GOOGLE_APPLICATION_CREDENTIALS=${GOOGLE_APPLICATION_CREDENTIALS?} 23 | - PROJECT_ID=${PROJECT_ID?} 24 | volumes: 25 | - ./otel-collector-config.yaml:/etc/otelcol-contrib/config.yaml 26 | - ${GOOGLE_APPLICATION_CREDENTIALS}:${GOOGLE_APPLICATION_CREDENTIALS} 27 | ports: 28 | - 4317:4317 # OTLP gRPC receiver 29 | 30 | # runs server.py 31 | python-server: 32 | build: 33 | context: . 34 | dockerfile: server.dockerfile 35 | init: true 36 | ports: 37 | - 6000:6000 38 | 39 | # load generator that sends requests to the python server 40 | hey-loadgen: 41 | build: 42 | context: . 43 | dockerfile: hey.dockerfile 44 | command: -c 50 -n 100000000 http://python-server:6000 45 | -------------------------------------------------------------------------------- /docs/examples/prometheus_exemplars/heatmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleCloudPlatform/opentelemetry-operations-python/54cb8a6db1f707ecc639e11c0a0d808deca6ac9e/docs/examples/prometheus_exemplars/heatmap.png -------------------------------------------------------------------------------- /docs/examples/prometheus_exemplars/hey.dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2023 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 | # https://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 | FROM golang:1.20-alpine 15 | RUN go install github.com/rakyll/hey@latest 16 | ENTRYPOINT ["hey"] 17 | -------------------------------------------------------------------------------- /docs/examples/prometheus_exemplars/requirements.in: -------------------------------------------------------------------------------- 1 | flask 2 | opentelemetry-api 3 | opentelemetry-exporter-otlp-proto-grpc 4 | opentelemetry-instrumentation-flask 5 | opentelemetry-sdk 6 | prometheus-client 7 | werkzeug 8 | -------------------------------------------------------------------------------- /docs/examples/prometheus_exemplars/select_metric.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleCloudPlatform/opentelemetry-operations-python/54cb8a6db1f707ecc639e11c0a0d808deca6ac9e/docs/examples/prometheus_exemplars/select_metric.png -------------------------------------------------------------------------------- /docs/examples/prometheus_exemplars/server.dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2023 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 | # https://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 | FROM python:3.10-alpine 16 | COPY requirements.txt . 17 | RUN pip install -r requirements.txt 18 | COPY server.py . 19 | ENV FLASK_APP=server.py 20 | ENTRYPOINT ["flask", "run", "-h", "0.0.0.0", "-p", "6000"] 21 | -------------------------------------------------------------------------------- /docs/examples/prometheus_exemplars/trace_details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleCloudPlatform/opentelemetry-operations-python/54cb8a6db1f707ecc639e11c0a0d808deca6ac9e/docs/examples/prometheus_exemplars/trace_details.png -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. Google Cloud OpenTelemetry documentation main file, created by 2 | sphinx-quickstart on Fri Jul 17 19:47:46 2020. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to Google Cloud OpenTelemetry's documentation! 7 | ====================================================== 8 | 9 | .. image:: https://badge.fury.io/py/opentelemetry-exporter-gcp-trace.svg 10 | :target: https://badge.fury.io/py/opentelemetry-exporter-gcp-trace 11 | 12 | .. image:: https://badge.fury.io/py/opentelemetry-exporter-gcp-monitoring.svg 13 | :target: https://badge.fury.io/py/opentelemetry-exporter-gcp-monitoring 14 | 15 | .. image:: https://badge.fury.io/py/opentelemetry-resourcedetector-gcp.svg 16 | :target: https://badge.fury.io/py/opentelemetry-resourcedetector-gcp 17 | 18 | .. image:: https://badge.fury.io/py/opentelemetry-propagator-gcp.svg 19 | :target: https://badge.fury.io/py/opentelemetry-propagator-gcp 20 | 21 | This documentation describes OpenTelemetry Python exporters, propagators, and 22 | resource detectors for Google Cloud Platform. Development for these packages 23 | takes place on `Github 24 | `_. 25 | 26 | To get started with instrumentation in Google Cloud, see `Generate traces and metrics with 27 | Python `_. 28 | 29 | To learn more about instrumentation and observability, including opinionated recommendations 30 | for Google Cloud Observability, visit `Instrumentation and observability 31 | `_. 32 | 33 | Installation 34 | ------------ 35 | 36 | To install the Cloud Trace exporter: 37 | 38 | .. code-block:: bash 39 | 40 | pip install opentelemetry-exporter-gcp-trace 41 | 42 | To install Cloud Monitoring exporter: 43 | 44 | .. code-block:: bash 45 | 46 | pip install opentelemetry-exporter-gcp-monitoring 47 | 48 | To install the GCP resource detector: 49 | 50 | .. code-block:: bash 51 | 52 | pip install opentelemetry-resourcedetector-gcp 53 | 54 | To install the GCP trace propagator: 55 | 56 | .. code-block:: bash 57 | 58 | pip install opentelemetry-propagator-gcp 59 | 60 | 61 | .. toctree:: 62 | :maxdepth: 1 63 | :caption: Exporters 64 | :name: exporters 65 | :glob: 66 | 67 | cloud_monitoring/** 68 | cloud_trace/** 69 | 70 | 71 | .. toctree:: 72 | :maxdepth: 1 73 | :caption: Examples 74 | :name: examples 75 | :glob: 76 | 77 | examples/** 78 | 79 | 80 | .. toctree:: 81 | :hidden: 82 | 83 | apireference 84 | 85 | :ref:`apireference` 86 | 87 | 88 | 89 | Indices and tables 90 | ================== 91 | 92 | * :ref:`genindex` 93 | * :ref:`modindex` 94 | * :ref:`search` 95 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /e2e-test-server/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2021 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 | # https://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 | # Build relative to root of repository i.e. `docker build --file Dockerfile --tag=$tag ..` 16 | 17 | FROM python:3.9-slim as python-base 18 | ENV PYTHONFAULTHANDLER=1 \ 19 | PYTHONUNBUFFERED=1 \ 20 | PYTHONHASHSEED=random \ 21 | PIP_NO_CACHE_DIR=off \ 22 | PIP_DISABLE_PIP_VERSION_CHECK=on \ 23 | PIP_DEFAULT_TIMEOUT=100 \ 24 | SRC="/src" 25 | WORKDIR $SRC 26 | 27 | FROM python-base as build-base 28 | # copy local dependencies 29 | COPY opentelemetry-exporter-gcp-trace opentelemetry-exporter-gcp-trace 30 | COPY opentelemetry-propagator-gcp opentelemetry-propagator-gcp 31 | COPY opentelemetry-resourcedetector-gcp opentelemetry-resourcedetector-gcp 32 | WORKDIR $SRC/e2e-test-server 33 | # copy requirements/constraints 34 | COPY e2e-test-server/*.txt ./ 35 | RUN python -m venv venv && ./venv/bin/pip install -r requirements-dockerfile.txt 36 | 37 | FROM python-base 38 | WORKDIR $SRC/e2e-test-server 39 | COPY --from=build-base $SRC/e2e-test-server/venv venv/ 40 | COPY e2e-test-server/ ./ 41 | 42 | ENTRYPOINT ["./venv/bin/python", "main.py"] 43 | -------------------------------------------------------------------------------- /e2e-test-server/constraints.txt: -------------------------------------------------------------------------------- 1 | annotated-types==0.6.0 2 | blinker==1.6.3 3 | cachetools==5.3.1 4 | certifi==2023.7.22 5 | charset-normalizer==3.3.0 6 | click==8.1.7 7 | cloudevents==1.11.0 8 | Deprecated==1.2.14 9 | deprecation==2.1.0 10 | Flask==3.0.0 11 | functions-framework==3.8.0 12 | google-api-core==2.12.0 13 | google-auth==2.23.3 14 | google-cloud-pubsub==2.18.4 15 | google-cloud-trace==1.11.2 16 | googleapis-common-protos==1.61.0 17 | grpc-google-iam-v1==0.12.6 18 | grpcio==1.59.0 19 | grpcio-status==1.59.0 20 | gunicorn==22.0.0 21 | idna==3.4 22 | importlib-metadata==6.8.0 23 | itsdangerous==2.1.2 24 | Jinja2==3.1.2 25 | MarkupSafe==2.1.3 26 | opentelemetry-api==1.30.0 27 | opentelemetry-sdk==1.30.0 28 | opentelemetry-semantic-conventions==0.51b0 29 | packaging==24.1 30 | proto-plus==1.22.3 31 | protobuf==4.24.4 32 | pyasn1==0.5.0 33 | pyasn1-modules==0.3.0 34 | pydantic==2.4.2 35 | pydantic_core==2.10.1 36 | requests==2.31.0 37 | rsa==4.9 38 | typing_extensions==4.8.0 39 | urllib3==2.0.6 40 | waitress==2.1.2 41 | watchdog==4.0.1 42 | Werkzeug==3.0.0 43 | wrapt==1.15.0 44 | zipp==3.17.0 45 | -------------------------------------------------------------------------------- /e2e-test-server/e2e_test_server/constants.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 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 | # https://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 | import enum 16 | import os 17 | 18 | 19 | class SubscriptionMode(enum.Enum): 20 | PULL = "pull" 21 | PUSH = "push" 22 | UNDEFINED = None 23 | 24 | 25 | INSTRUMENTING_MODULE_NAME = "opentelemetry-ops-e2e-test-server" 26 | SCENARIO = "scenario" 27 | STATUS_CODE = "status_code" 28 | TEST_ID = "test_id" 29 | TRACE_ID = "trace_id" 30 | SUBSCRIPTION_MODE: SubscriptionMode = SubscriptionMode( 31 | os.environ.get("SUBSCRIPTION_MODE") 32 | ) 33 | PROJECT_ID = os.environ["PROJECT_ID"] 34 | REQUEST_SUBSCRIPTION_NAME = os.environ.get("REQUEST_SUBSCRIPTION_NAME") 35 | RESPONSE_TOPIC_NAME = os.environ["RESPONSE_TOPIC_NAME"] 36 | PUSH_PORT = ( 37 | os.environ["PUSH_PORT"] 38 | if SUBSCRIPTION_MODE is SubscriptionMode.PUSH 39 | else None 40 | ) 41 | -------------------------------------------------------------------------------- /e2e-test-server/e2e_test_server/types.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 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 | # https://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 | import base64 16 | from dataclasses import dataclass 17 | from typing import Mapping, Protocol 18 | 19 | from pydantic import BaseModel, Field 20 | 21 | 22 | @dataclass(frozen=True) 23 | class PubsubMessage: 24 | """Wrapper for message that can be used for push and pull apis""" 25 | 26 | attributes: Mapping[str, str] 27 | data: bytes 28 | 29 | 30 | class PubsubPushPayload(BaseModel): 31 | """Shape of the JSON payload coming from a push subscription""" 32 | 33 | class Message(BaseModel): 34 | attributes: Mapping[str, str] 35 | data_base64: str = Field(default="", alias="data") 36 | 37 | def to_pubsub_message(self) -> PubsubMessage: 38 | return PubsubMessage( 39 | attributes=self.attributes, 40 | data=base64.b64decode(self.data_base64), 41 | ) 42 | 43 | message: Message 44 | subscription: str 45 | -------------------------------------------------------------------------------- /e2e-test-server/main.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 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 | # https://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 | import logging 16 | 17 | from e2e_test_server import server 18 | from e2e_test_server.server import cloud_functions_handler 19 | from e2e_test_server.constants import SUBSCRIPTION_MODE, SubscriptionMode 20 | 21 | if __name__ == "__main__": 22 | logging.basicConfig(level=logging.INFO) 23 | 24 | if SUBSCRIPTION_MODE is SubscriptionMode.PULL: 25 | server.pubsub_pull() 26 | elif SUBSCRIPTION_MODE is SubscriptionMode.PUSH: 27 | server.pubsub_push() 28 | 29 | # Expose handler to functions-framework 30 | __all__ = ["cloud_functions_handler"] 31 | -------------------------------------------------------------------------------- /e2e-test-server/requirements-dockerfile.txt: -------------------------------------------------------------------------------- 1 | # Used for installing from the monorepo in the Dockerfile 2 | -r requirements-shared.txt 3 | ../opentelemetry-exporter-gcp-trace 4 | ../opentelemetry-propagator-gcp 5 | ../opentelemetry-resourcedetector-gcp 6 | -------------------------------------------------------------------------------- /e2e-test-server/requirements-shared.txt: -------------------------------------------------------------------------------- 1 | # Shared by all requirements files 2 | -c constraints.txt 3 | opentelemetry-sdk 4 | opentelemetry-api 5 | Flask 6 | google-cloud-pubsub 7 | googleapis-common-protos 8 | pydantic 9 | waitress 10 | functions-framework 11 | -------------------------------------------------------------------------------- /e2e-test-server/requirements.txt: -------------------------------------------------------------------------------- 1 | # Used for Cloud Functions and GAE, has to be named requirements.txt 2 | -r requirements-shared.txt 3 | 4 | # allow installing dev versions so pip doesn't pull from pypi 5 | --pre 6 | # install monorepo packages from local vendored wheels directory 7 | --find-links wheels/ 8 | opentelemetry-exporter-gcp-trace 9 | opentelemetry-propagator-gcp 10 | opentelemetry-resourcedetector-gcp 11 | -------------------------------------------------------------------------------- /e2e-test-server/wait-for-image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Copyright 2021 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # https://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | while true; do 18 | if docker manifest inspect ${_TEST_SERVER_IMAGE} > /dev/null; then 19 | echo "Image is available, continuing onto test" 20 | break 21 | else 22 | echo "Image not available yet, will continue to retry" 23 | fi 24 | sleep 5 25 | done 26 | -------------------------------------------------------------------------------- /get_mock_server.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright 2021 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | # Use this envvar when testing a local mock_server binary 17 | if [ "$SKIP_GET_MOCK_SERVER" == "true" ]; then 18 | exit 19 | fi 20 | 21 | VERSION=v2-alpha 22 | BINARY=mock_server-x64-linux-$VERSION 23 | if ! [ -e $1/$BINARY ]; then 24 | curl -L -o $1/$BINARY https://github.com/googleinterns/cloud-operations-api-mock/releases/download/$VERSION/$BINARY 25 | chmod +x $1/$BINARY 26 | fi 27 | 28 | ln -sf $1/$BINARY $1/mock_server 29 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-logging/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Unreleased 4 | 5 | Added support for when `bytes` or `list['bytes']` is in `LogRecord.body` and 6 | body is of type Mapping. Update opentelemetry-api/sdk dependencies to 1.3. 7 | 8 | ## Version 1.9.0a0 9 | 10 | Released 2025-02-03 11 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-logging/MANIFEST.in: -------------------------------------------------------------------------------- 1 | graft src 2 | graft tests 3 | global-exclude *.pyc 4 | global-exclude *.pyo 5 | global-exclude __pycache__/* 6 | include CHANGELOG.md 7 | include MANIFEST.in 8 | include README.rst 9 | include LICENSE 10 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-logging/README.rst: -------------------------------------------------------------------------------- 1 | OpenTelemetry Google Cloud Logging Exporter 2 | ============================================== 3 | 4 | .. image:: https://badge.fury.io/py/opentelemetry-exporter-gcp-logging.svg 5 | :target: https://badge.fury.io/py/opentelemetry-exporter-gcp-logging 6 | 7 | .. image:: https://readthedocs.org/projects/google-cloud-opentelemetry/badge/?version=latest 8 | :target: https://google-cloud-opentelemetry.readthedocs.io/en/latest/?badge=latest 9 | :alt: Documentation Status 10 | 11 | This library provides support for exporting logs to Google Cloud 12 | Logging. 13 | 14 | To get started with instrumentation in Google Cloud, see `Generate traces and metrics with 15 | Python `_. 16 | 17 | To learn more about instrumentation and observability, including opinionated recommendations 18 | for Google Cloud Observability, visit `Instrumentation and observability 19 | `_. 20 | 21 | For resource detection and GCP trace context propagation, see 22 | `opentelemetry-tools-google-cloud 23 | `_. For the 24 | Google Cloud Trace exporter, see `opentelemetry-exporter-gcp-trace 25 | `_. 26 | 27 | Installation 28 | ------------ 29 | 30 | .. code:: bash 31 | 32 | pip install opentelemetry-exporter-gcp-logging 33 | 34 | Usage 35 | ----- 36 | 37 | .. code:: python 38 | 39 | import logging 40 | from opentelemetry.exporter.cloud_logging import ( 41 | CloudLoggingExporter, 42 | ) 43 | from opentelemetry.sdk.resources import Resource 44 | from opentelemetry._logs import set_logger_provider 45 | from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler 46 | from opentelemetry.sdk._logs.export import BatchLogRecordProcessor 47 | 48 | logger_provider = LoggerProvider( 49 | resource=Resource.create( 50 | { 51 | "service.name": "shoppingcart", 52 | "service.instance.id": "instance-12", 53 | } 54 | ), 55 | ) 56 | set_logger_provider(logger_provider) 57 | exporter = CloudLoggingExporter(default_log_name='my_log') 58 | logger_provider.add_log_record_processor(BatchLogRecordProcessor(exporter)) 59 | handler = LoggingHandler(level=logging.ERROR, logger_provider=logger_provider) 60 | 61 | # Attach OTLP handler to root logger 62 | logging.getLogger().addHandler(handler) 63 | 64 | # Create namespaced logger 65 | # It is recommended to not use the root logger with OTLP handler 66 | # so telemetry is collected only for the application 67 | logger1 = logging.getLogger("myapp.area1") 68 | 69 | logger1.warning("string log %s", "here") 70 | 71 | References 72 | ---------- 73 | 74 | * `Cloud Logging `_ 75 | * `OpenTelemetry Project `_ 76 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-logging/mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | namespace_packages = True 3 | explicit_package_bases = True 4 | mypy_path = $MYPY_CONFIG_FILE_DIR/src 5 | 6 | [mypy-google.auth.*] 7 | ignore_missing_imports = True 8 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-logging/setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = opentelemetry-exporter-gcp-logging 3 | description = Google Cloud Logging exporter for OpenTelemetry 4 | long_description = file: README.rst 5 | long_description_content_type = text/x-rst 6 | author = Google 7 | author_email = opentelemetry-pypi@google.com 8 | url = https://github.com/GoogleCloudPlatform/opentelemetry-operations-python/tree/main/opentelemetry-exporter-gcp-logging 9 | platforms = any 10 | license = Apache-2.0 11 | classifiers = 12 | Development Status :: 4 - Beta 13 | Intended Audience :: Developers 14 | License :: OSI Approved :: Apache Software License 15 | Programming Language :: Python 16 | Programming Language :: Python :: 3 17 | Programming Language :: Python :: 3.8 18 | Programming Language :: Python :: 3.9 19 | Programming Language :: Python :: 3.10 20 | Programming Language :: Python :: 3.11 21 | Programming Language :: Python :: 3.12 22 | 23 | [options] 24 | python_requires = >=3.8 25 | package_dir= 26 | =src 27 | packages=find_namespace: 28 | install_requires = 29 | google-cloud-logging ~= 3.0 30 | opentelemetry-sdk ~= 1.30 31 | opentelemetry-api ~= 1.30 32 | opentelemetry-resourcedetector-gcp >= 1.5.0dev0, == 1.* 33 | 34 | [options.packages.find] 35 | where = src 36 | 37 | [options.extras_require] 38 | test = 39 | 40 | [options.entry_points] 41 | opentelemetry_logs_exporter = 42 | gcp_logging = opentelemetry.exporter.cloud_logging:CloudLoggingExporter 43 | opentelemetry_environment_variables = 44 | gcp_logging = opentelemetry.exporter.cloud_logging.environment_variables 45 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-logging/setup.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 The OpenTelemetry Authors 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 | import os 15 | 16 | import setuptools 17 | 18 | BASE_DIR = os.path.dirname(__file__) 19 | VERSION_FILENAME = os.path.join( 20 | BASE_DIR, 21 | "src", 22 | "opentelemetry", 23 | "exporter", 24 | "cloud_logging", 25 | "version.py", 26 | ) 27 | PACKAGE_INFO = {} 28 | with open(VERSION_FILENAME) as f: 29 | exec(f.read(), PACKAGE_INFO) 30 | 31 | setuptools.setup( 32 | version=PACKAGE_INFO["__version__"], 33 | package_data={"opentelemetry": ["py.typed"]}, 34 | ) 35 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-logging/src/opentelemetry/exporter/cloud_logging/environment_variables.py: -------------------------------------------------------------------------------- 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 | # https://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 | OTEL_EXPORTER_GCP_LOGGING_PROJECT_ID = "OTEL_EXPORTER_GCP_LOGGING_PROJECT_ID" 16 | """ 17 | .. envvar:: OTEL_EXPORTER_GCP_LOGGING_PROJECT_ID 18 | 19 | GCP project ID for the exporter to send logs to. Equivalent to constructor parameter to 20 | :class:`opentelemetry.exporter.cloud_logging.CloudLoggingExporter`. 21 | """ 22 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-logging/src/opentelemetry/exporter/cloud_logging/version.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 The OpenTelemetry Authors 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 | __version__ = "1.10.0.dev0" 16 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-logging/tests/__snapshots__/test_cloud_logging/test_convert_non_json_dict_bytes.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "entries": [ 4 | { 5 | "logName": "projects/fakeproject/logs/test", 6 | "resource": { 7 | "labels": { 8 | "location": "global", 9 | "namespace": "", 10 | "node_id": "" 11 | }, 12 | "type": "generic_node" 13 | }, 14 | "textPayload": "MTIz", 15 | "timestamp": "2025-01-15T21:25:10.997977393Z" 16 | } 17 | ], 18 | "partialSuccess": true 19 | } 20 | ] 21 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-logging/tests/__snapshots__/test_cloud_logging/test_convert_otlp_dict_body.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "entries": [ 4 | { 5 | "jsonPayload": { 6 | "kvlistValue": { 7 | "bytes_field": "Ynl0ZXM=", 8 | "repeated_bytes_field": [ 9 | "Ynl0ZXM=", 10 | "Ynl0ZXM=", 11 | "Ynl0ZXM=" 12 | ], 13 | "values": [ 14 | { 15 | "key": "content", 16 | "value": { 17 | "stringValue": "You're a helpful assistant." 18 | } 19 | } 20 | ] 21 | } 22 | }, 23 | "labels": { 24 | "event.name": "gen_ai.system.message", 25 | "gen_ai.system": "true", 26 | "test": "23" 27 | }, 28 | "logName": "projects/fakeproject/logs/test", 29 | "resource": { 30 | "labels": { 31 | "location": "global", 32 | "namespace": "", 33 | "node_id": "" 34 | }, 35 | "type": "generic_node" 36 | }, 37 | "severity": "ERROR", 38 | "spanId": "0000000000000016", 39 | "timestamp": "2025-01-15T21:25:10.997977393Z", 40 | "trace": "projects/fakeproject/traces/00000000000000000000000000000019" 41 | } 42 | ], 43 | "partialSuccess": true 44 | } 45 | ] 46 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-logging/tests/__snapshots__/test_cloud_logging/test_convert_otlp_various_different_types_in_attrs_and_bytes_body.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "entries": [ 4 | { 5 | "jsonPayload": { 6 | "Classe": [ 7 | "Email addresses", 8 | "Passwords" 9 | ], 10 | "CreationDate": "2012-05-05", 11 | "Date": "2016-05-21T21:35:40Z", 12 | "Link": "http://some_link.com", 13 | "LogoType": "png", 14 | "Ref": 164611595.0 15 | }, 16 | "labels": { 17 | "boolArray": "[true, false, true, true]", 18 | "float": "25.43231", 19 | "int": "25", 20 | "intArray": "[21, 18, 23, 17]" 21 | }, 22 | "logName": "projects/fakeproject/logs/test", 23 | "resource": { 24 | "labels": { 25 | "location": "global", 26 | "namespace": "", 27 | "node_id": "" 28 | }, 29 | "type": "generic_node" 30 | }, 31 | "timestamp": "2025-01-15T21:25:10.997977393Z" 32 | } 33 | ], 34 | "partialSuccess": true 35 | } 36 | ] 37 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-logging/tests/__snapshots__/test_cloud_logging/test_convert_various_types_of_bodies[bool].json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "entries": [ 4 | { 5 | "logName": "projects/fakeproject/logs/test", 6 | "resource": { 7 | "labels": { 8 | "location": "global", 9 | "namespace": "", 10 | "node_id": "" 11 | }, 12 | "type": "generic_node" 13 | }, 14 | "textPayload": "true", 15 | "timestamp": "2025-01-15T21:25:10.997977393Z" 16 | } 17 | ], 18 | "partialSuccess": true 19 | } 20 | ] 21 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-logging/tests/__snapshots__/test_cloud_logging/test_convert_various_types_of_bodies[str].json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "entries": [ 4 | { 5 | "logName": "projects/fakeproject/logs/test", 6 | "resource": { 7 | "labels": { 8 | "location": "global", 9 | "namespace": "", 10 | "node_id": "" 11 | }, 12 | "type": "generic_node" 13 | }, 14 | "textPayload": "A text body", 15 | "timestamp": "2025-01-15T21:25:10.997977393Z" 16 | } 17 | ], 18 | "partialSuccess": true 19 | } 20 | ] 21 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-logging/tests/conftest.py: -------------------------------------------------------------------------------- 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 | # https://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 | # pylint: disable=unused-import 16 | 17 | # import fixtures to be made available to other tests 18 | from fixtures.cloud_logging_fake import fixture_cloudloggingfake 19 | from fixtures.snapshot_logging_calls import fixture_snapshot_writelogentrycalls 20 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-logging/tests/fixtures/snapshot_logging_calls.py: -------------------------------------------------------------------------------- 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 | # https://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 | from typing import List, Optional, cast 16 | 17 | import pytest 18 | from fixtures.cloud_logging_fake import WriteLogEntriesCall 19 | from google.protobuf import json_format 20 | from syrupy.extensions.json import JSONSnapshotExtension 21 | from syrupy.types import ( 22 | PropertyFilter, 23 | PropertyMatcher, 24 | SerializableData, 25 | SerializedData, 26 | ) 27 | 28 | 29 | # pylint: disable=too-many-ancestors 30 | class WriteLogEntryCallSnapshotExtension(JSONSnapshotExtension): 31 | """syrupy extension to serialize WriteLogEntriesRequest to JSON for storing as a snapshot.""" 32 | 33 | def serialize( 34 | self, 35 | data: SerializableData, 36 | *, 37 | exclude: Optional[PropertyFilter] = None, 38 | matcher: Optional[PropertyMatcher] = None, 39 | ) -> SerializedData: 40 | json = [ 41 | json_format.MessageToDict( 42 | type(call.write_log_entries_request).pb( 43 | call.write_log_entries_request 44 | ) 45 | ) 46 | for call in cast(List[WriteLogEntriesCall], data) 47 | ] 48 | return super().serialize(json, exclude=exclude, matcher=matcher) 49 | 50 | 51 | @pytest.fixture(name="snapshot_writelogentrycalls") 52 | def fixture_snapshot_writelogentrycalls(snapshot): 53 | """Fixture for snapshot testing of WriteLogEntriesCalls""" 54 | return snapshot.use_extension(WriteLogEntryCallSnapshotExtension)() 55 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-monitoring/MANIFEST.in: -------------------------------------------------------------------------------- 1 | graft src 2 | graft tests 3 | global-exclude *.pyc 4 | global-exclude *.pyo 5 | global-exclude __pycache__/* 6 | include CHANGELOG.md 7 | include MANIFEST.in 8 | include README.rst 9 | include LICENSE 10 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-monitoring/mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | namespace_packages = True 3 | explicit_package_bases = True 4 | mypy_path = $MYPY_CONFIG_FILE_DIR/src 5 | 6 | [mypy-google.auth.*] 7 | ignore_missing_imports = True 8 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-monitoring/setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = opentelemetry-exporter-gcp-monitoring 3 | description = Google Cloud Monitoring exporter for OpenTelemetry 4 | long_description = file: README.rst 5 | long_description_content_type = text/x-rst 6 | author = Google 7 | author_email = opentelemetry-pypi@google.com 8 | url = https://github.com/GoogleCloudPlatform/opentelemetry-operations-python/tree/main/opentelemetry-exporter-gcp-monitoring 9 | platforms = any 10 | license = Apache-2.0 11 | classifiers = 12 | Development Status :: 4 - Beta 13 | Intended Audience :: Developers 14 | License :: OSI Approved :: Apache Software License 15 | Programming Language :: Python 16 | Programming Language :: Python :: 3 17 | Programming Language :: Python :: 3.8 18 | Programming Language :: Python :: 3.9 19 | Programming Language :: Python :: 3.10 20 | Programming Language :: Python :: 3.11 21 | Programming Language :: Python :: 3.12 22 | Programming Language :: Python :: 3.13 23 | 24 | [options] 25 | python_requires = >=3.8 26 | package_dir= 27 | =src 28 | packages=find_namespace: 29 | install_requires = 30 | google-cloud-monitoring ~= 2.0 31 | opentelemetry-api ~= 1.30 32 | opentelemetry-sdk ~= 1.30 33 | opentelemetry-resourcedetector-gcp >= 1.5.0dev0, == 1.* 34 | 35 | [options.packages.find] 36 | where = src 37 | 38 | [options.extras_require] 39 | test = 40 | 41 | [options.entry_points] 42 | opentelemetry_metrics_exporter = 43 | gcp_monitoring = opentelemetry.exporter.cloud_monitoring:CloudMonitoringMetricsExporter 44 | opentelemetry_environment_variables = 45 | gcp_monitoring = opentelemetry.exporter.cloud_monitoring.environment_variables 46 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-monitoring/setup.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The OpenTelemetry Authors 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 | import os 15 | 16 | import setuptools 17 | 18 | BASE_DIR = os.path.dirname(__file__) 19 | VERSION_FILENAME = os.path.join( 20 | BASE_DIR, 21 | "src", 22 | "opentelemetry", 23 | "exporter", 24 | "cloud_monitoring", 25 | "version.py", 26 | ) 27 | PACKAGE_INFO = {} 28 | with open(VERSION_FILENAME) as f: 29 | exec(f.read(), PACKAGE_INFO) 30 | 31 | setuptools.setup( 32 | version=PACKAGE_INFO["__version__"], 33 | package_data={"opentelemetry": ["py.typed"]}, 34 | ) 35 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-monitoring/src/opentelemetry/exporter/cloud_monitoring/environment_variables.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 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 | # https://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 | OTEL_EXPORTER_GCP_MONITORING_PROJECT_ID = ( 16 | "OTEL_EXPORTER_GCP_MONITORING_PROJECT_ID" 17 | ) 18 | """ 19 | .. envvar:: OTEL_EXPORTER_GCP_MONITORING_PROJECT_ID 20 | 21 | GCP project ID for the exporter to send metrics to. Equivalent to constructor parameter to 22 | :class:`opentelemetry.exporter.cloud_monitoring.CloudMonitoringMetricsExporter`. 23 | """ 24 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-monitoring/src/opentelemetry/exporter/cloud_monitoring/version.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The OpenTelemetry Authors 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 | __version__ = "1.10.0.dev0" 16 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-monitoring/src/opentelemetry/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleCloudPlatform/opentelemetry-operations-python/54cb8a6db1f707ecc639e11c0a0d808deca6ac9e/opentelemetry-exporter-gcp-monitoring/src/opentelemetry/py.typed -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-monitoring/tests/__snapshots__/test_cloud_monitoring/test_counter[float].json: -------------------------------------------------------------------------------- 1 | { 2 | "/google.monitoring.v3.MetricService/CreateMetricDescriptor": [ 3 | { 4 | "metricDescriptor": { 5 | "description": "foo", 6 | "displayName": "mycounter", 7 | "labels": [ 8 | { 9 | "key": "string" 10 | }, 11 | { 12 | "key": "int" 13 | }, 14 | { 15 | "key": "float" 16 | } 17 | ], 18 | "metricKind": "CUMULATIVE", 19 | "type": "workload.googleapis.com/mycounter", 20 | "unit": "{myunit}", 21 | "valueType": "DOUBLE" 22 | }, 23 | "name": "projects/fakeproject" 24 | } 25 | ], 26 | "/google.monitoring.v3.MetricService/CreateTimeSeries": [ 27 | { 28 | "name": "projects/fakeproject", 29 | "timeSeries": [ 30 | { 31 | "metric": { 32 | "labels": { 33 | "float": "123.4", 34 | "int": "123", 35 | "string": "string" 36 | }, 37 | "type": "workload.googleapis.com/mycounter" 38 | }, 39 | "metricKind": "CUMULATIVE", 40 | "points": [ 41 | { 42 | "interval": { 43 | "endTime": "str", 44 | "startTime": "str" 45 | }, 46 | "value": { 47 | "doubleValue": 45.6 48 | } 49 | } 50 | ], 51 | "resource": { 52 | "labels": { 53 | "location": "global", 54 | "namespace": "", 55 | "node_id": "" 56 | }, 57 | "type": "generic_node" 58 | }, 59 | "unit": "{myunit}" 60 | } 61 | ] 62 | } 63 | ] 64 | } 65 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-monitoring/tests/__snapshots__/test_cloud_monitoring/test_counter[int].json: -------------------------------------------------------------------------------- 1 | { 2 | "/google.monitoring.v3.MetricService/CreateMetricDescriptor": [ 3 | { 4 | "metricDescriptor": { 5 | "description": "foo", 6 | "displayName": "mycounter", 7 | "labels": [ 8 | { 9 | "key": "string" 10 | }, 11 | { 12 | "key": "int" 13 | }, 14 | { 15 | "key": "float" 16 | } 17 | ], 18 | "metricKind": "CUMULATIVE", 19 | "type": "workload.googleapis.com/mycounter", 20 | "unit": "{myunit}", 21 | "valueType": "INT64" 22 | }, 23 | "name": "projects/fakeproject" 24 | } 25 | ], 26 | "/google.monitoring.v3.MetricService/CreateTimeSeries": [ 27 | { 28 | "name": "projects/fakeproject", 29 | "timeSeries": [ 30 | { 31 | "metric": { 32 | "labels": { 33 | "float": "123.4", 34 | "int": "123", 35 | "string": "string" 36 | }, 37 | "type": "workload.googleapis.com/mycounter" 38 | }, 39 | "metricKind": "CUMULATIVE", 40 | "points": [ 41 | { 42 | "interval": { 43 | "endTime": "str", 44 | "startTime": "str" 45 | }, 46 | "value": { 47 | "int64Value": "123" 48 | } 49 | } 50 | ], 51 | "resource": { 52 | "labels": { 53 | "location": "global", 54 | "namespace": "", 55 | "node_id": "" 56 | }, 57 | "type": "generic_node" 58 | }, 59 | "unit": "{myunit}" 60 | } 61 | ] 62 | } 63 | ] 64 | } 65 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-monitoring/tests/__snapshots__/test_cloud_monitoring/test_histogram_single_bucket.json: -------------------------------------------------------------------------------- 1 | { 2 | "/google.monitoring.v3.MetricService/CreateMetricDescriptor": [ 3 | { 4 | "metricDescriptor": { 5 | "description": "foo", 6 | "displayName": "myhistogram", 7 | "labels": [ 8 | { 9 | "key": "string" 10 | }, 11 | { 12 | "key": "int" 13 | }, 14 | { 15 | "key": "float" 16 | } 17 | ], 18 | "metricKind": "CUMULATIVE", 19 | "type": "workload.googleapis.com/myhistogram", 20 | "unit": "{myunit}", 21 | "valueType": "DISTRIBUTION" 22 | }, 23 | "name": "projects/fakeproject" 24 | } 25 | ], 26 | "/google.monitoring.v3.MetricService/CreateTimeSeries": [ 27 | { 28 | "name": "projects/fakeproject", 29 | "timeSeries": [ 30 | { 31 | "metric": { 32 | "labels": { 33 | "float": "123.4", 34 | "int": "123", 35 | "string": "string" 36 | }, 37 | "type": "workload.googleapis.com/myhistogram" 38 | }, 39 | "metricKind": "CUMULATIVE", 40 | "points": [ 41 | { 42 | "interval": { 43 | "endTime": "str", 44 | "startTime": "str" 45 | }, 46 | "value": { 47 | "distributionValue": { 48 | "bucketCounts": [ 49 | "6", 50 | "9994" 51 | ], 52 | "bucketOptions": { 53 | "explicitBuckets": { 54 | "bounds": [ 55 | 5.5 56 | ] 57 | } 58 | }, 59 | "count": "10000", 60 | "mean": 4999.5 61 | } 62 | } 63 | } 64 | ], 65 | "resource": { 66 | "labels": { 67 | "location": "global", 68 | "namespace": "", 69 | "node_id": "" 70 | }, 71 | "type": "generic_node" 72 | }, 73 | "unit": "{myunit}" 74 | } 75 | ] 76 | } 77 | ] 78 | } 79 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-monitoring/tests/__snapshots__/test_cloud_monitoring/test_invalid_label_keys.json: -------------------------------------------------------------------------------- 1 | { 2 | "/google.monitoring.v3.MetricService/CreateMetricDescriptor": [ 3 | { 4 | "metricDescriptor": { 5 | "description": "foo", 6 | "displayName": "mycounter", 7 | "labels": [ 8 | { 9 | "key": "key_1some_invalid__key" 10 | } 11 | ], 12 | "metricKind": "CUMULATIVE", 13 | "type": "workload.googleapis.com/mycounter", 14 | "unit": "{myunit}", 15 | "valueType": "INT64" 16 | }, 17 | "name": "projects/fakeproject" 18 | } 19 | ], 20 | "/google.monitoring.v3.MetricService/CreateTimeSeries": [ 21 | { 22 | "name": "projects/fakeproject", 23 | "timeSeries": [ 24 | { 25 | "metric": { 26 | "labels": { 27 | "key_1some_invalid__key": "value" 28 | }, 29 | "type": "workload.googleapis.com/mycounter" 30 | }, 31 | "metricKind": "CUMULATIVE", 32 | "points": [ 33 | { 34 | "interval": { 35 | "endTime": "str", 36 | "startTime": "str" 37 | }, 38 | "value": { 39 | "int64Value": "12" 40 | } 41 | } 42 | ], 43 | "resource": { 44 | "labels": { 45 | "location": "global", 46 | "namespace": "", 47 | "node_id": "" 48 | }, 49 | "type": "generic_node" 50 | }, 51 | "unit": "{myunit}" 52 | } 53 | ] 54 | } 55 | ] 56 | } 57 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-monitoring/tests/__snapshots__/test_cloud_monitoring/test_observable_counter[float].json: -------------------------------------------------------------------------------- 1 | { 2 | "/google.monitoring.v3.MetricService/CreateMetricDescriptor": [ 3 | { 4 | "metricDescriptor": { 5 | "description": "foo", 6 | "displayName": "myobservablecounter", 7 | "labels": [ 8 | { 9 | "key": "string" 10 | }, 11 | { 12 | "key": "int" 13 | }, 14 | { 15 | "key": "float" 16 | } 17 | ], 18 | "metricKind": "CUMULATIVE", 19 | "type": "workload.googleapis.com/myobservablecounter", 20 | "unit": "{myunit}", 21 | "valueType": "DOUBLE" 22 | }, 23 | "name": "projects/fakeproject" 24 | } 25 | ], 26 | "/google.monitoring.v3.MetricService/CreateTimeSeries": [ 27 | { 28 | "name": "projects/fakeproject", 29 | "timeSeries": [ 30 | { 31 | "metric": { 32 | "labels": { 33 | "float": "123.4", 34 | "int": "123", 35 | "string": "string" 36 | }, 37 | "type": "workload.googleapis.com/myobservablecounter" 38 | }, 39 | "metricKind": "CUMULATIVE", 40 | "points": [ 41 | { 42 | "interval": { 43 | "endTime": "str", 44 | "startTime": "str" 45 | }, 46 | "value": { 47 | "doubleValue": 45.6 48 | } 49 | } 50 | ], 51 | "resource": { 52 | "labels": { 53 | "location": "global", 54 | "namespace": "", 55 | "node_id": "" 56 | }, 57 | "type": "generic_node" 58 | }, 59 | "unit": "{myunit}" 60 | } 61 | ] 62 | } 63 | ] 64 | } 65 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-monitoring/tests/__snapshots__/test_cloud_monitoring/test_observable_counter[int].json: -------------------------------------------------------------------------------- 1 | { 2 | "/google.monitoring.v3.MetricService/CreateMetricDescriptor": [ 3 | { 4 | "metricDescriptor": { 5 | "description": "foo", 6 | "displayName": "myobservablecounter", 7 | "labels": [ 8 | { 9 | "key": "string" 10 | }, 11 | { 12 | "key": "int" 13 | }, 14 | { 15 | "key": "float" 16 | } 17 | ], 18 | "metricKind": "CUMULATIVE", 19 | "type": "workload.googleapis.com/myobservablecounter", 20 | "unit": "{myunit}", 21 | "valueType": "INT64" 22 | }, 23 | "name": "projects/fakeproject" 24 | } 25 | ], 26 | "/google.monitoring.v3.MetricService/CreateTimeSeries": [ 27 | { 28 | "name": "projects/fakeproject", 29 | "timeSeries": [ 30 | { 31 | "metric": { 32 | "labels": { 33 | "float": "123.4", 34 | "int": "123", 35 | "string": "string" 36 | }, 37 | "type": "workload.googleapis.com/myobservablecounter" 38 | }, 39 | "metricKind": "CUMULATIVE", 40 | "points": [ 41 | { 42 | "interval": { 43 | "endTime": "str", 44 | "startTime": "str" 45 | }, 46 | "value": { 47 | "int64Value": "123" 48 | } 49 | } 50 | ], 51 | "resource": { 52 | "labels": { 53 | "location": "global", 54 | "namespace": "", 55 | "node_id": "" 56 | }, 57 | "type": "generic_node" 58 | }, 59 | "unit": "{myunit}" 60 | } 61 | ] 62 | } 63 | ] 64 | } 65 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-monitoring/tests/__snapshots__/test_cloud_monitoring/test_observable_gauge[float].json: -------------------------------------------------------------------------------- 1 | { 2 | "/google.monitoring.v3.MetricService/CreateMetricDescriptor": [ 3 | { 4 | "metricDescriptor": { 5 | "description": "foo", 6 | "displayName": "myobservablegauge", 7 | "labels": [ 8 | { 9 | "key": "string" 10 | }, 11 | { 12 | "key": "int" 13 | }, 14 | { 15 | "key": "float" 16 | } 17 | ], 18 | "metricKind": "GAUGE", 19 | "type": "workload.googleapis.com/myobservablegauge", 20 | "unit": "{myunit}", 21 | "valueType": "DOUBLE" 22 | }, 23 | "name": "projects/fakeproject" 24 | } 25 | ], 26 | "/google.monitoring.v3.MetricService/CreateTimeSeries": [ 27 | { 28 | "name": "projects/fakeproject", 29 | "timeSeries": [ 30 | { 31 | "metric": { 32 | "labels": { 33 | "float": "123.4", 34 | "int": "123", 35 | "string": "string" 36 | }, 37 | "type": "workload.googleapis.com/myobservablegauge" 38 | }, 39 | "metricKind": "GAUGE", 40 | "points": [ 41 | { 42 | "interval": { 43 | "endTime": "str" 44 | }, 45 | "value": { 46 | "doubleValue": 45.6 47 | } 48 | } 49 | ], 50 | "resource": { 51 | "labels": { 52 | "location": "global", 53 | "namespace": "", 54 | "node_id": "" 55 | }, 56 | "type": "generic_node" 57 | }, 58 | "unit": "{myunit}" 59 | } 60 | ] 61 | } 62 | ] 63 | } 64 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-monitoring/tests/__snapshots__/test_cloud_monitoring/test_observable_gauge[int].json: -------------------------------------------------------------------------------- 1 | { 2 | "/google.monitoring.v3.MetricService/CreateMetricDescriptor": [ 3 | { 4 | "metricDescriptor": { 5 | "description": "foo", 6 | "displayName": "myobservablegauge", 7 | "labels": [ 8 | { 9 | "key": "string" 10 | }, 11 | { 12 | "key": "int" 13 | }, 14 | { 15 | "key": "float" 16 | } 17 | ], 18 | "metricKind": "GAUGE", 19 | "type": "workload.googleapis.com/myobservablegauge", 20 | "unit": "{myunit}", 21 | "valueType": "INT64" 22 | }, 23 | "name": "projects/fakeproject" 24 | } 25 | ], 26 | "/google.monitoring.v3.MetricService/CreateTimeSeries": [ 27 | { 28 | "name": "projects/fakeproject", 29 | "timeSeries": [ 30 | { 31 | "metric": { 32 | "labels": { 33 | "float": "123.4", 34 | "int": "123", 35 | "string": "string" 36 | }, 37 | "type": "workload.googleapis.com/myobservablegauge" 38 | }, 39 | "metricKind": "GAUGE", 40 | "points": [ 41 | { 42 | "interval": { 43 | "endTime": "str" 44 | }, 45 | "value": { 46 | "int64Value": "123" 47 | } 48 | } 49 | ], 50 | "resource": { 51 | "labels": { 52 | "location": "global", 53 | "namespace": "", 54 | "node_id": "" 55 | }, 56 | "type": "generic_node" 57 | }, 58 | "unit": "{myunit}" 59 | } 60 | ] 61 | } 62 | ] 63 | } 64 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-monitoring/tests/__snapshots__/test_cloud_monitoring/test_observable_updowncounter[float].json: -------------------------------------------------------------------------------- 1 | { 2 | "/google.monitoring.v3.MetricService/CreateMetricDescriptor": [ 3 | { 4 | "metricDescriptor": { 5 | "description": "foo", 6 | "displayName": "myobservableupdowncounter", 7 | "labels": [ 8 | { 9 | "key": "string" 10 | }, 11 | { 12 | "key": "int" 13 | }, 14 | { 15 | "key": "float" 16 | } 17 | ], 18 | "metricKind": "GAUGE", 19 | "type": "workload.googleapis.com/myobservableupdowncounter", 20 | "unit": "{myunit}", 21 | "valueType": "DOUBLE" 22 | }, 23 | "name": "projects/fakeproject" 24 | } 25 | ], 26 | "/google.monitoring.v3.MetricService/CreateTimeSeries": [ 27 | { 28 | "name": "projects/fakeproject", 29 | "timeSeries": [ 30 | { 31 | "metric": { 32 | "labels": { 33 | "float": "123.4", 34 | "int": "123", 35 | "string": "string" 36 | }, 37 | "type": "workload.googleapis.com/myobservableupdowncounter" 38 | }, 39 | "metricKind": "GAUGE", 40 | "points": [ 41 | { 42 | "interval": { 43 | "endTime": "str" 44 | }, 45 | "value": { 46 | "doubleValue": 45.6 47 | } 48 | } 49 | ], 50 | "resource": { 51 | "labels": { 52 | "location": "global", 53 | "namespace": "", 54 | "node_id": "" 55 | }, 56 | "type": "generic_node" 57 | }, 58 | "unit": "{myunit}" 59 | } 60 | ] 61 | } 62 | ] 63 | } 64 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-monitoring/tests/__snapshots__/test_cloud_monitoring/test_observable_updowncounter[int].json: -------------------------------------------------------------------------------- 1 | { 2 | "/google.monitoring.v3.MetricService/CreateMetricDescriptor": [ 3 | { 4 | "metricDescriptor": { 5 | "description": "foo", 6 | "displayName": "myobservableupdowncounter", 7 | "labels": [ 8 | { 9 | "key": "string" 10 | }, 11 | { 12 | "key": "int" 13 | }, 14 | { 15 | "key": "float" 16 | } 17 | ], 18 | "metricKind": "GAUGE", 19 | "type": "workload.googleapis.com/myobservableupdowncounter", 20 | "unit": "{myunit}", 21 | "valueType": "INT64" 22 | }, 23 | "name": "projects/fakeproject" 24 | } 25 | ], 26 | "/google.monitoring.v3.MetricService/CreateTimeSeries": [ 27 | { 28 | "name": "projects/fakeproject", 29 | "timeSeries": [ 30 | { 31 | "metric": { 32 | "labels": { 33 | "float": "123.4", 34 | "int": "123", 35 | "string": "string" 36 | }, 37 | "type": "workload.googleapis.com/myobservableupdowncounter" 38 | }, 39 | "metricKind": "GAUGE", 40 | "points": [ 41 | { 42 | "interval": { 43 | "endTime": "str" 44 | }, 45 | "value": { 46 | "int64Value": "123" 47 | } 48 | } 49 | ], 50 | "resource": { 51 | "labels": { 52 | "location": "global", 53 | "namespace": "", 54 | "node_id": "" 55 | }, 56 | "type": "generic_node" 57 | }, 58 | "unit": "{myunit}" 59 | } 60 | ] 61 | } 62 | ] 63 | } 64 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-monitoring/tests/__snapshots__/test_cloud_monitoring/test_up_down_counter[float].json: -------------------------------------------------------------------------------- 1 | { 2 | "/google.monitoring.v3.MetricService/CreateMetricDescriptor": [ 3 | { 4 | "metricDescriptor": { 5 | "description": "foo", 6 | "displayName": "myupdowncounter", 7 | "labels": [ 8 | { 9 | "key": "string" 10 | }, 11 | { 12 | "key": "int" 13 | }, 14 | { 15 | "key": "float" 16 | } 17 | ], 18 | "metricKind": "GAUGE", 19 | "type": "workload.googleapis.com/myupdowncounter", 20 | "unit": "{myunit}", 21 | "valueType": "DOUBLE" 22 | }, 23 | "name": "projects/fakeproject" 24 | } 25 | ], 26 | "/google.monitoring.v3.MetricService/CreateTimeSeries": [ 27 | { 28 | "name": "projects/fakeproject", 29 | "timeSeries": [ 30 | { 31 | "metric": { 32 | "labels": { 33 | "float": "123.4", 34 | "int": "123", 35 | "string": "string" 36 | }, 37 | "type": "workload.googleapis.com/myupdowncounter" 38 | }, 39 | "metricKind": "GAUGE", 40 | "points": [ 41 | { 42 | "interval": { 43 | "endTime": "str" 44 | }, 45 | "value": { 46 | "doubleValue": 45.6 47 | } 48 | } 49 | ], 50 | "resource": { 51 | "labels": { 52 | "location": "global", 53 | "namespace": "", 54 | "node_id": "" 55 | }, 56 | "type": "generic_node" 57 | }, 58 | "unit": "{myunit}" 59 | } 60 | ] 61 | } 62 | ] 63 | } 64 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-monitoring/tests/__snapshots__/test_cloud_monitoring/test_up_down_counter[int].json: -------------------------------------------------------------------------------- 1 | { 2 | "/google.monitoring.v3.MetricService/CreateMetricDescriptor": [ 3 | { 4 | "metricDescriptor": { 5 | "description": "foo", 6 | "displayName": "myupdowncounter", 7 | "labels": [ 8 | { 9 | "key": "string" 10 | }, 11 | { 12 | "key": "int" 13 | }, 14 | { 15 | "key": "float" 16 | } 17 | ], 18 | "metricKind": "GAUGE", 19 | "type": "workload.googleapis.com/myupdowncounter", 20 | "unit": "{myunit}", 21 | "valueType": "INT64" 22 | }, 23 | "name": "projects/fakeproject" 24 | } 25 | ], 26 | "/google.monitoring.v3.MetricService/CreateTimeSeries": [ 27 | { 28 | "name": "projects/fakeproject", 29 | "timeSeries": [ 30 | { 31 | "metric": { 32 | "labels": { 33 | "float": "123.4", 34 | "int": "123", 35 | "string": "string" 36 | }, 37 | "type": "workload.googleapis.com/myupdowncounter" 38 | }, 39 | "metricKind": "GAUGE", 40 | "points": [ 41 | { 42 | "interval": { 43 | "endTime": "str" 44 | }, 45 | "value": { 46 | "int64Value": "123" 47 | } 48 | } 49 | ], 50 | "resource": { 51 | "labels": { 52 | "location": "global", 53 | "namespace": "", 54 | "node_id": "" 55 | }, 56 | "type": "generic_node" 57 | }, 58 | "unit": "{myunit}" 59 | } 60 | ] 61 | } 62 | ] 63 | } 64 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-monitoring/tests/__snapshots__/test_cloud_monitoring/test_with_resource.json: -------------------------------------------------------------------------------- 1 | { 2 | "/google.monitoring.v3.MetricService/CreateMetricDescriptor": [ 3 | { 4 | "metricDescriptor": { 5 | "description": "foo", 6 | "displayName": "mycounter", 7 | "labels": [ 8 | { 9 | "key": "string" 10 | }, 11 | { 12 | "key": "int" 13 | }, 14 | { 15 | "key": "float" 16 | } 17 | ], 18 | "metricKind": "CUMULATIVE", 19 | "type": "workload.googleapis.com/mycounter", 20 | "unit": "{myunit}", 21 | "valueType": "INT64" 22 | }, 23 | "name": "projects/fakeproject" 24 | } 25 | ], 26 | "/google.monitoring.v3.MetricService/CreateTimeSeries": [ 27 | { 28 | "name": "projects/fakeproject", 29 | "timeSeries": [ 30 | { 31 | "metric": { 32 | "labels": { 33 | "float": "123.4", 34 | "int": "123", 35 | "string": "string" 36 | }, 37 | "type": "workload.googleapis.com/mycounter" 38 | }, 39 | "metricKind": "CUMULATIVE", 40 | "points": [ 41 | { 42 | "interval": { 43 | "endTime": "str", 44 | "startTime": "str" 45 | }, 46 | "value": { 47 | "int64Value": "12" 48 | } 49 | } 50 | ], 51 | "resource": { 52 | "labels": { 53 | "cluster_name": "mycluster", 54 | "container_name": "mycontainer", 55 | "location": "myavailzone", 56 | "namespace_name": "myns", 57 | "pod_name": "mypod" 58 | }, 59 | "type": "k8s_container" 60 | }, 61 | "unit": "{myunit}" 62 | } 63 | ] 64 | } 65 | ] 66 | } 67 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-monitoring/tests/conftest.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 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 | # https://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 | # pylint: disable=unused-import 16 | 17 | # import fixtures to be made available to other tests 18 | from fixtures.gcmfake import fixture_gcmfake, fixture_make_meter_provider 19 | from fixtures.snapshot_gcmcalls import fixture_snapshot_gcmcalls 20 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-monitoring/tests/fixtures/snapshot_gcmcalls.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 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 | # https://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 | from typing import Optional, cast 16 | 17 | import google.protobuf.message 18 | import proto 19 | import pytest 20 | from fixtures.gcmfake import GcmCalls 21 | from google.protobuf import json_format 22 | from syrupy.extensions.json import JSONSnapshotExtension 23 | from syrupy.matchers import path_type 24 | from syrupy.types import ( 25 | PropertyFilter, 26 | PropertyMatcher, 27 | SerializableData, 28 | SerializedData, 29 | ) 30 | 31 | 32 | # pylint: disable=too-many-ancestors 33 | class GcmCallsSnapshotExtension(JSONSnapshotExtension): 34 | """syrupy extension to serialize GcmCalls. 35 | 36 | Serializes the protobufs for each method call into JSON for storing as a snapshot. 37 | """ 38 | 39 | def serialize( 40 | self, 41 | data: SerializableData, 42 | *, 43 | exclude: Optional[PropertyFilter] = None, 44 | matcher: Optional[PropertyMatcher] = None, 45 | ) -> SerializedData: 46 | gcmcalls = cast(GcmCalls, data) 47 | json = {} 48 | for method, calls in gcmcalls.items(): 49 | dict_requests = [] 50 | for call in calls: 51 | if isinstance(call.message, proto.message.Message): 52 | call.message = type(call.message).pb(call.message) 53 | elif isinstance(call.message, google.protobuf.message.Message): 54 | pass 55 | else: 56 | raise ValueError( 57 | f"Excepted a proto-plus or protobuf message, got {type(call)}" 58 | ) 59 | dict_requests.append(json_format.MessageToDict(call.message)) 60 | json[method] = dict_requests 61 | 62 | return super().serialize(json, exclude=exclude, matcher=matcher) 63 | 64 | 65 | @pytest.fixture(name="snapshot_gcmcalls") 66 | def fixture_snapshot_gcmcalls(snapshot): 67 | """Fixture for snapshot testing of GcmCalls 68 | 69 | TimeInterval.start_time and TimeInterval.end_time timestamps are "redacted" since they are 70 | dynamic depending on when the test is run. 71 | """ 72 | return snapshot.use_extension(GcmCallsSnapshotExtension)( 73 | matcher=path_type( 74 | {r".*\.interval\.(start|end)Time": (str,)}, 75 | regex=True, 76 | ) 77 | ) 78 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-monitoring/tests/test_cloud_monitoring_auto_instrument.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 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 | # https://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 | from unittest import TestCase 16 | 17 | from opentelemetry.exporter.cloud_monitoring import ( 18 | CloudMonitoringMetricsExporter, 19 | ) 20 | 21 | # private import for testing only 22 | from opentelemetry.sdk._configuration import _import_exporters 23 | 24 | 25 | class TestCloudTraceAutoInstrument(TestCase): 26 | def test_loads_cloud_trace_exporter(self): 27 | """Test that OTel configuration internals can load the exporter from entrypoint by 28 | name""" 29 | _, metric_exporters, _ = _import_exporters( 30 | trace_exporter_names=[], 31 | log_exporter_names=[], 32 | metric_exporter_names=["gcp_monitoring"], 33 | ) 34 | self.assertEqual( 35 | metric_exporters, 36 | {"gcp_monitoring": CloudMonitoringMetricsExporter}, 37 | ) 38 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-monitoring/tests/test_normalize_label_key.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 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 | # https://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 | import pytest 16 | from opentelemetry.exporter.cloud_monitoring import _normalize_label_key 17 | 18 | 19 | @pytest.mark.parametrize( 20 | ("key", "expected"), 21 | [ 22 | ("valid_key_1", "valid_key_1"), 23 | ("hellø", "hellø"), 24 | ("123", "key_123"), 25 | ("key!321", "key_321"), 26 | ("key!321", "key_321"), 27 | ("hyphens-dots.slashes/", "hyphens_dots_slashes_"), 28 | ("non_letters_:£¢$∞", "non_letters______"), 29 | ], 30 | ) 31 | def test_normalize_label_key(key: str, expected: str) -> None: 32 | assert _normalize_label_key(key) == expected 33 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-monitoring/tests/test_user_agent.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 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 | # https://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 | import re 16 | 17 | from fixtures.gcmfake import GcmFake, GcmFakeMeterProvider 18 | 19 | 20 | def test_with_resource( 21 | gcmfake_meter_provider: GcmFakeMeterProvider, 22 | gcmfake: GcmFake, 23 | ) -> None: 24 | meter_provider = gcmfake_meter_provider() 25 | counter = meter_provider.get_meter(__name__).create_counter( 26 | "mycounter", description="foo", unit="{myunit}" 27 | ) 28 | counter.add(12) 29 | meter_provider.force_flush() 30 | 31 | for calls in gcmfake.get_calls().values(): 32 | for call in calls: 33 | assert ( 34 | re.match( 35 | r"^opentelemetry-python \S+; google-cloud-metric-exporter \S+ grpc-python/\S+", 36 | call.user_agent, 37 | ) 38 | is not None 39 | ) 40 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-trace/MANIFEST.in: -------------------------------------------------------------------------------- 1 | graft src 2 | graft tests 3 | global-exclude *.pyc 4 | global-exclude *.pyo 5 | global-exclude __pycache__/* 6 | include CHANGELOG.md 7 | include MANIFEST.in 8 | include README.rst 9 | include LICENSE 10 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-trace/README.rst: -------------------------------------------------------------------------------- 1 | OpenTelemetry Google Cloud Integration 2 | ====================================== 3 | 4 | .. image:: https://badge.fury.io/py/opentelemetry-exporter-gcp-trace.svg 5 | :target: https://badge.fury.io/py/opentelemetry-exporter-gcp-trace 6 | 7 | .. image:: https://readthedocs.org/projects/google-cloud-opentelemetry/badge/?version=latest 8 | :target: https://google-cloud-opentelemetry.readthedocs.io/en/latest/?badge=latest 9 | :alt: Documentation Status 10 | 11 | This library provides support for exporting traces to Google Cloud Trace. 12 | 13 | To get started with instrumentation in Google Cloud, see `Generate traces and metrics with 14 | Python `_. 15 | 16 | To learn more about instrumentation and observability, including opinionated recommendations 17 | for Google Cloud Observability, visit `Instrumentation and observability 18 | `_. 19 | 20 | For resource detection and GCP trace context propagation, see 21 | `opentelemetry-tools-google-cloud 22 | `_. For the 23 | Google Cloud Monitoring exporter, see 24 | `opentelemetry-exporter-gcp-monitoring 25 | `_. 26 | 27 | Installation 28 | ------------ 29 | 30 | .. code:: bash 31 | 32 | pip install opentelemetry-exporter-gcp-trace 33 | 34 | Usage 35 | ----- 36 | 37 | .. code:: python 38 | 39 | from opentelemetry import trace 40 | from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter 41 | from opentelemetry.sdk.trace import TracerProvider 42 | from opentelemetry.sdk.trace.export import ( 43 | SimpleSpanProcessor, 44 | ) 45 | 46 | trace.set_tracer_provider(TracerProvider()) 47 | 48 | cloud_trace_exporter = CloudTraceSpanExporter( 49 | project_id='my-gcloud-project', 50 | ) 51 | trace.get_tracer_provider().add_span_processor( 52 | SimpleSpanProcessor(cloud_trace_exporter) 53 | ) 54 | tracer = trace.get_tracer(__name__) 55 | with tracer.start_as_current_span('foo'): 56 | print('Hello world!') 57 | 58 | 59 | References 60 | ---------- 61 | 62 | * `Cloud Trace `_ 63 | * `OpenTelemetry Project `_ 64 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-trace/mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | namespace_packages = True 3 | explicit_package_bases = True 4 | mypy_path = $MYPY_CONFIG_FILE_DIR/src 5 | 6 | [mypy-google.auth.*] 7 | ignore_missing_imports = True 8 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-trace/setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = opentelemetry-exporter-gcp-trace 3 | description = Google Cloud Trace exporter for OpenTelemetry 4 | long_description = file: README.rst 5 | long_description_content_type = text/x-rst 6 | author = Google 7 | author_email = opentelemetry-pypi@google.com 8 | url = https://github.com/GoogleCloudPlatform/opentelemetry-operations-python/tree/main/opentelemetry-exporter-gcp-trace 9 | platforms = any 10 | license = Apache-2.0 11 | classifiers = 12 | Development Status :: 4 - Beta 13 | Intended Audience :: Developers 14 | License :: OSI Approved :: Apache Software License 15 | Programming Language :: Python 16 | Programming Language :: Python :: 3 17 | Programming Language :: Python :: 3.8 18 | Programming Language :: Python :: 3.9 19 | Programming Language :: Python :: 3.10 20 | Programming Language :: Python :: 3.11 21 | Programming Language :: Python :: 3.12 22 | Programming Language :: Python :: 3.13 23 | 24 | [options] 25 | package_dir= 26 | =src 27 | packages=find_namespace: 28 | install_requires = 29 | google-cloud-trace ~= 1.1 30 | opentelemetry-api ~= 1.30 31 | opentelemetry-sdk ~= 1.30 32 | opentelemetry-resourcedetector-gcp >= 1.5.0dev0, == 1.* 33 | 34 | [options.packages.find] 35 | where = src 36 | 37 | [options.extras_require] 38 | test = 39 | 40 | [options.entry_points] 41 | opentelemetry_traces_exporter = 42 | gcp_trace = opentelemetry.exporter.cloud_trace:CloudTraceSpanExporter 43 | opentelemetry_environment_variables = 44 | gcp_trace = opentelemetry.exporter.cloud_trace.environment_variables 45 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-trace/setup.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The OpenTelemetry Authors 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 | import os 15 | 16 | import setuptools 17 | 18 | BASE_DIR = os.path.dirname(__file__) 19 | VERSION_FILENAME = os.path.join( 20 | BASE_DIR, 21 | "src", 22 | "opentelemetry", 23 | "exporter", 24 | "cloud_trace", 25 | "version.py", 26 | ) 27 | PACKAGE_INFO = {} 28 | with open(VERSION_FILENAME) as f: 29 | exec(f.read(), PACKAGE_INFO) 30 | 31 | setuptools.setup( 32 | version=PACKAGE_INFO["__version__"], 33 | package_data={"opentelemetry": ["py.typed"]}, 34 | ) 35 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-trace/src/opentelemetry/exporter/cloud_trace/environment_variables.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 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 | # https://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 | OTEL_EXPORTER_GCP_TRACE_PROJECT_ID = "OTEL_EXPORTER_GCP_TRACE_PROJECT_ID" 16 | """ 17 | .. envvar:: OTEL_EXPORTER_GCP_TRACE_PROJECT_ID 18 | 19 | GCP project ID for the project to send spans to. Equivalent to constructor parameter to 20 | :class:`opentelemetry.exporter.cloud_trace.CloudTraceSpanExporter`. 21 | """ 22 | 23 | OTEL_EXPORTER_GCP_TRACE_RESOURCE_REGEX = ( 24 | "OTEL_EXPORTER_GCP_TRACE_RESOURCE_REGEX" 25 | ) 26 | """ 27 | .. envvar:: OTEL_EXPORTER_GCP_TRACE_RESOURCE_REGEX 28 | 29 | Resource attributes with keys matching this regex will be added to exported spans as labels 30 | :class:`opentelemetry.exporter.cloud_trace.CloudTraceSpanExporter`. Equivalent to constructor parameter to 31 | :class:`opentelemetry.exporter.cloud_trace.CloudTraceSpanExporter`. 32 | """ 33 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-trace/src/opentelemetry/exporter/cloud_trace/version.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 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 | __version__ = "1.10.0.dev0" 16 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-trace/src/opentelemetry/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleCloudPlatform/opentelemetry-operations-python/54cb8a6db1f707ecc639e11c0a0d808deca6ac9e/opentelemetry-exporter-gcp-trace/src/opentelemetry/py.typed -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-trace/tests/test_cloud_trace_auto_instrument.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 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 | # https://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 | from unittest import TestCase 16 | 17 | from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter 18 | 19 | # private import for testing only 20 | from opentelemetry.sdk._configuration import _import_exporters 21 | 22 | 23 | class TestCloudTraceAutoInstrument(TestCase): 24 | def test_loads_cloud_trace_exporter(self): 25 | """Test that OTel configuration internals can load the trace exporter from entrypoint 26 | by name""" 27 | trace_exporters, _, _ = _import_exporters( 28 | trace_exporter_names=["gcp_trace"], 29 | log_exporter_names=[], 30 | metric_exporter_names=[], 31 | ) 32 | self.assertEqual( 33 | trace_exporters, {"gcp_trace": CloudTraceSpanExporter} 34 | ) 35 | -------------------------------------------------------------------------------- /opentelemetry-exporter-gcp-trace/tests/test_integration_cloud_trace_exporter.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The OpenTelemetry Authors 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 | import grpc 16 | from google.cloud.trace_v2 import TraceServiceClient 17 | from google.cloud.trace_v2.services.trace_service.transports.grpc import ( 18 | TraceServiceGrpcTransport, 19 | ) 20 | from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter 21 | from opentelemetry.sdk.resources import Resource 22 | from opentelemetry.sdk.trace import _Span as Span 23 | from opentelemetry.sdk.trace.export import SpanExportResult 24 | from opentelemetry.trace import SpanContext, SpanKind 25 | from test_common import BaseExporterIntegrationTest, time_ns 26 | 27 | 28 | class TestCloudTraceSpanExporter(BaseExporterIntegrationTest): 29 | def test_export(self): 30 | trace_id = "6e0c63257de34c92bf9efcd03927272e" 31 | span_id = "95bb5edabd45950f" 32 | 33 | # Create span and associated data. 34 | resource_info = Resource( 35 | { 36 | "cloud.account.id": 123, 37 | "host.id": "host", 38 | "cloud.zone": "US", 39 | "cloud.provider": "gcp", 40 | "gcp.resource_type": "gce_instance", 41 | } 42 | ) 43 | span = Span( 44 | name="span_name", 45 | context=SpanContext( 46 | trace_id=int(trace_id, 16), 47 | span_id=int(span_id, 16), 48 | is_remote=False, 49 | ), 50 | parent=None, 51 | kind=SpanKind.INTERNAL, 52 | resource=resource_info, 53 | attributes={"attr_key": "attr_value"}, 54 | ) 55 | 56 | # pylint: disable=protected-access 57 | span._start_time = int(time_ns() - (60 * 1e9)) 58 | span._end_time = time_ns() 59 | span_data = [span] 60 | 61 | # Setup the trace exporter. 62 | channel = grpc.insecure_channel(self.address) 63 | transport = TraceServiceGrpcTransport(channel=channel) 64 | 65 | client = TraceServiceClient(transport=transport) 66 | trace_exporter = CloudTraceSpanExporter(self.project_id, client=client) 67 | 68 | # Export the spans and verify the results. 69 | result = trace_exporter.export(span_data) 70 | self.assertEqual(result, SpanExportResult.SUCCESS) 71 | -------------------------------------------------------------------------------- /opentelemetry-propagator-gcp/MANIFEST.in: -------------------------------------------------------------------------------- 1 | graft src 2 | graft tests 3 | global-exclude *.pyc 4 | global-exclude *.pyo 5 | global-exclude __pycache__/* 6 | include CHANGELOG.md 7 | include MANIFEST.in 8 | include README.rst 9 | include LICENSE 10 | -------------------------------------------------------------------------------- /opentelemetry-propagator-gcp/mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | namespace_packages = True 3 | explicit_package_bases = True 4 | mypy_path = $MYPY_CONFIG_FILE_DIR/src 5 | -------------------------------------------------------------------------------- /opentelemetry-propagator-gcp/setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = opentelemetry-propagator-gcp 3 | description = Google Cloud propagator for OpenTelemetry 4 | long_description = file: README.rst 5 | long_description_content_type = text/x-rst 6 | author = Google 7 | author_email = opentelemetry-pypi@google.com 8 | url = https://github.com/GoogleCloudPlatform/opentelemetry-operations-python/tree/main/opentelemetry-propagator-gcp 9 | platforms = any 10 | license = Apache-2.0 11 | classifiers = 12 | Development Status :: 4 - Beta 13 | Intended Audience :: Developers 14 | License :: OSI Approved :: Apache Software License 15 | Programming Language :: Python 16 | Programming Language :: Python :: 3 17 | Programming Language :: Python :: 3.8 18 | Programming Language :: Python :: 3.9 19 | Programming Language :: Python :: 3.10 20 | Programming Language :: Python :: 3.11 21 | Programming Language :: Python :: 3.12 22 | Programming Language :: Python :: 3.13 23 | 24 | [options] 25 | python_requires = >=3.8 26 | package_dir= 27 | =src 28 | packages=find_namespace: 29 | install_requires = 30 | opentelemetry-api ~= 1.0 31 | 32 | [options.packages.find] 33 | where = src 34 | 35 | [options.extras_require] 36 | test = 37 | 38 | [options.entry_points] 39 | opentelemetry_propagator = 40 | gcp_trace = opentelemetry.propagators.cloud_trace_propagator:CloudTraceFormatPropagator 41 | -------------------------------------------------------------------------------- /opentelemetry-propagator-gcp/setup.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The OpenTelemetry Authors 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 | import os 15 | 16 | import setuptools 17 | 18 | BASE_DIR = os.path.dirname(__file__) 19 | VERSION_FILENAME = os.path.join( 20 | BASE_DIR, 21 | "src", 22 | "opentelemetry", 23 | "propagators", 24 | "cloud_trace_propagator", 25 | "version.py", 26 | ) 27 | PACKAGE_INFO = {} 28 | with open(VERSION_FILENAME) as f: 29 | exec(f.read(), PACKAGE_INFO) 30 | 31 | setuptools.setup( 32 | version=PACKAGE_INFO["__version__"], 33 | package_data={"opentelemetry": ["py.typed"]}, 34 | ) 35 | -------------------------------------------------------------------------------- /opentelemetry-propagator-gcp/src/opentelemetry/propagators/cloud_trace_propagator/version.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The OpenTelemetry Authors 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 | __version__ = "1.10.0.dev0" 16 | -------------------------------------------------------------------------------- /opentelemetry-propagator-gcp/src/opentelemetry/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleCloudPlatform/opentelemetry-operations-python/54cb8a6db1f707ecc639e11c0a0d808deca6ac9e/opentelemetry-propagator-gcp/src/opentelemetry/py.typed -------------------------------------------------------------------------------- /opentelemetry-propagator-gcp/tests/test_cloud_trace_propagator_auto_instrument.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 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 | # https://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 | from unittest import TestCase 16 | from unittest.mock import patch 17 | 18 | from opentelemetry.environment_variables import OTEL_PROPAGATORS 19 | from opentelemetry.propagators.cloud_trace_propagator import ( 20 | CloudTraceFormatPropagator, 21 | ) 22 | 23 | 24 | class TestCloudTracePropagatorAutoInstrument(TestCase): 25 | @patch.dict("os.environ", {OTEL_PROPAGATORS: "gcp_trace"}) 26 | def test_loads_cloud_trace_propagator(self): 27 | # This test is a bit fragile as the propagator entry points are loaded on the first 28 | # import of opentelemetry.propagate and saved in a global variable. If another tests 29 | # imports that before this one, it can fail. 30 | # pylint: disable=import-outside-toplevel 31 | from opentelemetry.propagate import propagators 32 | 33 | self.assertEqual(len(propagators), 1) 34 | self.assertIsInstance(propagators[0], CloudTraceFormatPropagator) 35 | -------------------------------------------------------------------------------- /opentelemetry-resourcedetector-gcp/MANIFEST.in: -------------------------------------------------------------------------------- 1 | graft src 2 | graft tests 3 | global-exclude *.pyc 4 | global-exclude *.pyo 5 | global-exclude __pycache__/* 6 | include CHANGELOG.md 7 | include MANIFEST.in 8 | include README.rst 9 | include LICENSE 10 | -------------------------------------------------------------------------------- /opentelemetry-resourcedetector-gcp/README.rst: -------------------------------------------------------------------------------- 1 | OpenTelemetry Google Cloud Resource Detector 2 | ============================================ 3 | 4 | .. image:: https://badge.fury.io/py/opentelemetry-resourcedetector-gcp.svg 5 | :target: https://badge.fury.io/py/opentelemetry-resourcedetector-gcp 6 | 7 | .. image:: https://readthedocs.org/projects/google-cloud-opentelemetry/badge/?version=latest 8 | :target: https://google-cloud-opentelemetry.readthedocs.io/en/latest/?badge=latest 9 | :alt: Documentation Status 10 | 11 | This library provides support for detecting GCP resources like GCE, GKE, etc. 12 | 13 | To get started with instrumentation in Google Cloud, see `Generate traces and metrics with 14 | Python `_. 15 | 16 | To learn more about instrumentation and observability, including opinionated recommendations 17 | for Google Cloud Observability, visit `Instrumentation and observability 18 | `_. 19 | 20 | Installation 21 | ------------ 22 | 23 | .. code:: bash 24 | 25 | pip install opentelemetry-resourcedetector-gcp 26 | 27 | .. 28 | TODO: Add usage info here 29 | 30 | 31 | References 32 | ---------- 33 | 34 | * `Cloud Monitoring `_ 35 | * `OpenTelemetry Project `_ 36 | -------------------------------------------------------------------------------- /opentelemetry-resourcedetector-gcp/mypy.ini: -------------------------------------------------------------------------------- 1 | [mypy] 2 | namespace_packages = True 3 | explicit_package_bases = True 4 | mypy_path = $MYPY_CONFIG_FILE_DIR/src 5 | -------------------------------------------------------------------------------- /opentelemetry-resourcedetector-gcp/setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = opentelemetry-resourcedetector-gcp 3 | description = Google Cloud resource detector for OpenTelemetry 4 | long_description = file: README.rst 5 | long_description_content_type = text/x-rst 6 | author = Google 7 | author_email = opentelemetry-pypi@google.com 8 | url = https://github.com/GoogleCloudPlatform/opentelemetry-operations-python/tree/main/opentelemetry-resourcedetector-gcp 9 | platforms = any 10 | license = Apache-2.0 11 | classifiers = 12 | Development Status :: 4 - Beta 13 | Intended Audience :: Developers 14 | License :: OSI Approved :: Apache Software License 15 | Programming Language :: Python 16 | Programming Language :: Python :: 3 17 | Programming Language :: Python :: 3.8 18 | Programming Language :: Python :: 3.9 19 | Programming Language :: Python :: 3.10 20 | Programming Language :: Python :: 3.11 21 | Programming Language :: Python :: 3.12 22 | Programming Language :: Python :: 3.13 23 | 24 | [options] 25 | python_requires = >=3.8 26 | package_dir= 27 | =src 28 | packages=find_namespace: 29 | install_requires = 30 | opentelemetry-api ~= 1.30 31 | opentelemetry-sdk ~= 1.30 32 | requests ~= 2.24 33 | # TODO: remove when Python 3.7 is dropped 34 | typing_extensions ~= 4.0 35 | 36 | [options.packages.find] 37 | where = src 38 | 39 | [options.extras_require] 40 | test = 41 | -------------------------------------------------------------------------------- /opentelemetry-resourcedetector-gcp/setup.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The OpenTelemetry Authors 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 | import os 15 | 16 | import setuptools 17 | 18 | BASE_DIR = os.path.dirname(__file__) 19 | VERSION_FILENAME = os.path.join( 20 | BASE_DIR, 21 | "src", 22 | "opentelemetry", 23 | "resourcedetector", 24 | "gcp_resource_detector", 25 | "version.py", 26 | ) 27 | PACKAGE_INFO = {} 28 | with open(VERSION_FILENAME) as f: 29 | exec(f.read(), PACKAGE_INFO) 30 | 31 | setuptools.setup( 32 | version=PACKAGE_INFO["__version__"], 33 | package_data={"opentelemetry": ["py.typed"]}, 34 | ) 35 | -------------------------------------------------------------------------------- /opentelemetry-resourcedetector-gcp/src/opentelemetry/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleCloudPlatform/opentelemetry-operations-python/54cb8a6db1f707ecc639e11c0a0d808deca6ac9e/opentelemetry-resourcedetector-gcp/src/opentelemetry/py.typed -------------------------------------------------------------------------------- /opentelemetry-resourcedetector-gcp/src/opentelemetry/resourcedetector/gcp_resource_detector/_constants.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 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 | # https://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 | # TODO: use opentelemetry-semantic-conventions package for these constants once it has 17 | # stabilized. Right now, pinning an unstable version would cause dependency conflicts for 18 | # users so these are copied in. 19 | class ResourceAttributes: 20 | AWS_EC2 = "aws_ec2" 21 | CLOUD_ACCOUNT_ID = "cloud.account.id" 22 | CLOUD_AVAILABILITY_ZONE = "cloud.availability_zone" 23 | CLOUD_PLATFORM_KEY = "cloud.platform" 24 | CLOUD_PROVIDER = "cloud.provider" 25 | CLOUD_REGION = "cloud.region" 26 | FAAS_INSTANCE = "faas.instance" 27 | FAAS_NAME = "faas.name" 28 | FAAS_VERSION = "faas.version" 29 | GCP_APP_ENGINE = "gcp_app_engine" 30 | GCP_CLOUD_FUNCTIONS = "gcp_cloud_functions" 31 | GCP_CLOUD_RUN = "gcp_cloud_run" 32 | GCP_COMPUTE_ENGINE = "gcp_compute_engine" 33 | GCP_KUBERNETES_ENGINE = "gcp_kubernetes_engine" 34 | HOST_ID = "host.id" 35 | HOST_NAME = "host.name" 36 | HOST_TYPE = "host.type" 37 | K8S_CLUSTER_NAME = "k8s.cluster.name" 38 | K8S_CONTAINER_NAME = "k8s.container.name" 39 | K8S_NAMESPACE_NAME = "k8s.namespace.name" 40 | K8S_NODE_NAME = "k8s.node.name" 41 | K8S_POD_NAME = "k8s.pod.name" 42 | SERVICE_INSTANCE_ID = "service.instance.id" 43 | SERVICE_NAME = "service.name" 44 | SERVICE_NAMESPACE = "service.namespace" 45 | 46 | 47 | AWS_ACCOUNT = "aws_account" 48 | AWS_EC2_INSTANCE = "aws_ec2_instance" 49 | CLUSTER_NAME = "cluster_name" 50 | CONTAINER_NAME = "container_name" 51 | GCE_INSTANCE = "gce_instance" 52 | GENERIC_NODE = "generic_node" 53 | GENERIC_TASK = "generic_task" 54 | INSTANCE_ID = "instance_id" 55 | JOB = "job" 56 | K8S_CLUSTER = "k8s_cluster" 57 | K8S_CONTAINER = "k8s_container" 58 | K8S_NODE = "k8s_node" 59 | K8S_POD = "k8s_pod" 60 | LOCATION = "location" 61 | NAMESPACE = "namespace" 62 | NAMESPACE_NAME = "namespace_name" 63 | NODE_ID = "node_id" 64 | NODE_NAME = "node_name" 65 | POD_NAME = "pod_name" 66 | REGION = "region" 67 | TASK_ID = "task_id" 68 | ZONE = "zone" 69 | UNKNOWN_SERVICE_PREFIX = "unknown_service" 70 | -------------------------------------------------------------------------------- /opentelemetry-resourcedetector-gcp/src/opentelemetry/resourcedetector/gcp_resource_detector/_faas.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 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 | # https://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 | # Implementation in this file copied from 16 | # https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/blob/v1.8.0/detectors/gcp/faas.go 17 | 18 | import os 19 | 20 | from opentelemetry.resourcedetector.gcp_resource_detector import _metadata 21 | 22 | _CLOUD_RUN_CONFIG_ENV = "K_CONFIGURATION" 23 | _CLOUD_FUNCTION_TARGET_ENV = "FUNCTION_TARGET" 24 | _FAAS_SERVICE_ENV = "K_SERVICE" 25 | _FAAS_REVISION_ENV = "K_REVISION" 26 | 27 | 28 | def on_cloud_run() -> bool: 29 | return _CLOUD_RUN_CONFIG_ENV in os.environ 30 | 31 | 32 | def on_cloud_functions() -> bool: 33 | return _CLOUD_FUNCTION_TARGET_ENV in os.environ 34 | 35 | 36 | def faas_name() -> str: 37 | """The name of the Cloud Run or Cloud Function. 38 | 39 | Check that on_cloud_run() or on_cloud_functions() is true before calling this, or it may 40 | throw exceptions. 41 | """ 42 | return os.environ[_FAAS_SERVICE_ENV] 43 | 44 | 45 | def faas_version() -> str: 46 | """The version/revision of the Cloud Run or Cloud Function. 47 | 48 | Check that on_cloud_run() or on_cloud_functions() is true before calling this, or it may 49 | throw exceptions. 50 | """ 51 | return os.environ[_FAAS_REVISION_ENV] 52 | 53 | 54 | def faas_instance() -> str: 55 | return str(_metadata.get_metadata()["instance"]["id"]) 56 | 57 | 58 | def faas_cloud_region() -> str: 59 | region = _metadata.get_metadata()["instance"]["region"] 60 | return region[region.rfind("/") + 1 :] 61 | -------------------------------------------------------------------------------- /opentelemetry-resourcedetector-gcp/src/opentelemetry/resourcedetector/gcp_resource_detector/_gce.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 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 | # https://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 | import logging 16 | import re 17 | from dataclasses import dataclass 18 | 19 | from opentelemetry.resourcedetector.gcp_resource_detector import _metadata 20 | 21 | # Format described in 22 | # https://cloud.google.com/compute/docs/metadata/default-metadata-values#vm_instance_metadata 23 | _ZONE_REGION_RE = re.compile( 24 | r"projects\/\d+\/zones\/(?P(?P\w+-\w+)-\w+)" 25 | ) 26 | 27 | _logger = logging.getLogger(__name__) 28 | 29 | 30 | def on_gce() -> bool: 31 | try: 32 | _metadata.get_metadata()["instance"]["machineType"] 33 | except (_metadata.MetadataAccessException, KeyError): 34 | _logger.debug( 35 | "Could not fetch metadata attribute instance/machineType, " 36 | "assuming not on GCE.", 37 | exc_info=True, 38 | ) 39 | return False 40 | return True 41 | 42 | 43 | def host_type() -> str: 44 | return _metadata.get_metadata()["instance"]["machineType"] 45 | 46 | 47 | def host_id() -> str: 48 | return str(_metadata.get_metadata()["instance"]["id"]) 49 | 50 | 51 | def host_name() -> str: 52 | return _metadata.get_metadata()["instance"]["name"] 53 | 54 | 55 | @dataclass 56 | class ZoneAndRegion: 57 | zone: str 58 | region: str 59 | 60 | 61 | def availability_zone_and_region() -> ZoneAndRegion: 62 | full_zone = _metadata.get_metadata()["instance"]["zone"] 63 | match = _ZONE_REGION_RE.search(full_zone) 64 | if not match: 65 | raise Exception( 66 | "zone was not in the expected format: " 67 | f"projects/PROJECT_NUM/zones/COUNTRY-REGION-ZONE. Got {full_zone}" 68 | ) 69 | 70 | return ZoneAndRegion( 71 | zone=match.group("zone"), region=match.group("region") 72 | ) 73 | -------------------------------------------------------------------------------- /opentelemetry-resourcedetector-gcp/src/opentelemetry/resourcedetector/gcp_resource_detector/_gke.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 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 | # https://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 | import os 16 | from dataclasses import dataclass 17 | from typing import Literal 18 | 19 | from opentelemetry.resourcedetector.gcp_resource_detector import ( 20 | _gce, 21 | _metadata, 22 | ) 23 | 24 | KUBERNETES_SERVICE_HOST_ENV = "KUBERNETES_SERVICE_HOST" 25 | 26 | 27 | def on_gke() -> bool: 28 | return os.environ.get(KUBERNETES_SERVICE_HOST_ENV) is not None 29 | 30 | 31 | def host_id() -> str: 32 | return _gce.host_id() 33 | 34 | 35 | def cluster_name() -> str: 36 | return _metadata.get_metadata()["instance"]["attributes"]["cluster-name"] 37 | 38 | 39 | @dataclass 40 | class ZoneOrRegion: 41 | type: Literal["zone", "region"] 42 | value: str 43 | 44 | 45 | def availability_zone_or_region() -> ZoneOrRegion: 46 | cluster_location = _metadata.get_metadata()["instance"]["attributes"][ 47 | "cluster-location" 48 | ] 49 | hyphen_count = cluster_location.count("-") 50 | if hyphen_count == 1: 51 | return ZoneOrRegion(type="region", value=cluster_location) 52 | if hyphen_count == 2: 53 | return ZoneOrRegion(type="zone", value=cluster_location) 54 | raise Exception( 55 | f"unrecognized format for cluster location: {cluster_location}" 56 | ) 57 | -------------------------------------------------------------------------------- /opentelemetry-resourcedetector-gcp/src/opentelemetry/resourcedetector/gcp_resource_detector/_metadata.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 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 | # https://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 | import logging 16 | from functools import lru_cache 17 | from typing import TypedDict, Union 18 | 19 | import requests 20 | 21 | _GCP_METADATA_URL = "http://metadata.google.internal/computeMetadata/v1/" 22 | _INSTANCE = "instance" 23 | _RECURSIVE_PARAMS = {"recursive": "true"} 24 | _GCP_METADATA_URL_HEADER = {"Metadata-Flavor": "Google"} 25 | # Use a shorter timeout for connection so we won't block much if it's unreachable 26 | _TIMEOUT = (2, 5) 27 | 28 | _logger = logging.getLogger(__name__) 29 | 30 | 31 | class Project(TypedDict): 32 | projectId: str 33 | 34 | 35 | Attributes = TypedDict( 36 | "Attributes", {"cluster-location": str, "cluster-name": str}, total=False 37 | ) 38 | 39 | 40 | class Instance(TypedDict): 41 | attributes: Attributes 42 | # id can be an integer on GCE VMs or a string on other environments 43 | id: Union[int, str] 44 | machineType: str 45 | name: str 46 | region: str 47 | zone: str 48 | 49 | 50 | class Metadata(TypedDict): 51 | instance: Instance 52 | project: Project 53 | 54 | 55 | class MetadataAccessException(Exception): 56 | pass 57 | 58 | 59 | @lru_cache(maxsize=None) 60 | def get_metadata() -> Metadata: 61 | """Get all instance and project metadata from the metadata server 62 | 63 | Cached for the lifetime of the process. 64 | """ 65 | try: 66 | res = requests.get( 67 | f"{_GCP_METADATA_URL}", 68 | params=_RECURSIVE_PARAMS, 69 | headers=_GCP_METADATA_URL_HEADER, 70 | timeout=_TIMEOUT, 71 | ) 72 | res.raise_for_status() 73 | all_metadata = res.json() 74 | except requests.RequestException as err: 75 | raise MetadataAccessException() from err 76 | return all_metadata 77 | 78 | 79 | @lru_cache(maxsize=None) 80 | def is_available() -> bool: 81 | try: 82 | requests.get( 83 | f"{_GCP_METADATA_URL}{_INSTANCE}/", 84 | headers=_GCP_METADATA_URL_HEADER, 85 | timeout=_TIMEOUT, 86 | ).raise_for_status() 87 | except requests.RequestException: 88 | _logger.debug( 89 | "Failed to make request to metadata server, assuming it's not available", 90 | exc_info=True, 91 | ) 92 | return False 93 | return True 94 | -------------------------------------------------------------------------------- /opentelemetry-resourcedetector-gcp/src/opentelemetry/resourcedetector/gcp_resource_detector/version.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The OpenTelemetry Authors 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 | __version__ = "1.10.0.dev0" 16 | -------------------------------------------------------------------------------- /opentelemetry-resourcedetector-gcp/tests/__snapshots__/test_detector.ambr: -------------------------------------------------------------------------------- 1 | # name: test_detects_cloud_functions 2 | dict({ 3 | 'cloud.account.id': 'fakeProject', 4 | 'cloud.platform': 'gcp_cloud_functions', 5 | 'cloud.provider': 'gcp', 6 | 'cloud.region': 'us-east4', 7 | 'faas.instance': '0087244a', 8 | 'faas.name': 'fake-service', 9 | 'faas.version': 'fake-revision', 10 | }) 11 | # --- 12 | # name: test_detects_cloud_run 13 | dict({ 14 | 'cloud.account.id': 'fakeProject', 15 | 'cloud.platform': 'gcp_cloud_run', 16 | 'cloud.provider': 'gcp', 17 | 'cloud.region': 'us-east4', 18 | 'faas.instance': '0087244a', 19 | 'faas.name': 'fake-service', 20 | 'faas.version': 'fake-revision', 21 | }) 22 | # --- 23 | # name: test_detects_empty_as_fallback 24 | dict({ 25 | }) 26 | # --- 27 | # name: test_detects_empty_when_not_available 28 | dict({ 29 | }) 30 | # --- 31 | # name: test_detects_gae_flex 32 | dict({ 33 | 'cloud.account.id': 'fakeProject', 34 | 'cloud.availability_zone': 'us-east4-b', 35 | 'cloud.platform': 'gcp_app_engine', 36 | 'cloud.provider': 'gcp', 37 | 'cloud.region': 'us-east4', 38 | 'faas.instance': 'fake-instance', 39 | 'faas.name': 'fake-service', 40 | 'faas.version': 'fake-version', 41 | }) 42 | # --- 43 | # name: test_detects_gae_standard 44 | dict({ 45 | 'cloud.account.id': 'fakeProject', 46 | 'cloud.availability_zone': 'us-east4-b', 47 | 'cloud.platform': 'gcp_app_engine', 48 | 'cloud.provider': 'gcp', 49 | 'cloud.region': 'us-east4', 50 | 'faas.instance': 'fake-instance', 51 | 'faas.name': 'fake-service', 52 | 'faas.version': 'fake-version', 53 | }) 54 | # --- 55 | # name: test_detects_gce 56 | dict({ 57 | 'cloud.account.id': 'fakeProject', 58 | 'cloud.availability_zone': 'us-east4-b', 59 | 'cloud.platform': 'gcp_compute_engine', 60 | 'cloud.provider': 'gcp', 61 | 'cloud.region': 'us-east4', 62 | 'host.id': '0087244a', 63 | 'host.name': 'fakeName', 64 | 'host.type': 'fakeMachineType', 65 | }) 66 | # --- 67 | # name: test_detects_gke[regional] 68 | dict({ 69 | 'cloud.account.id': 'fakeProject', 70 | 'cloud.platform': 'gcp_kubernetes_engine', 71 | 'cloud.provider': 'gcp', 72 | 'cloud.region': 'us-east4', 73 | 'host.id': '12345', 74 | 'k8s.cluster.name': 'fakeClusterName', 75 | }) 76 | # --- 77 | # name: test_detects_gke[zonal] 78 | dict({ 79 | 'cloud.account.id': 'fakeProject', 80 | 'cloud.availability_zone': 'us-east4-b', 81 | 'cloud.platform': 'gcp_kubernetes_engine', 82 | 'cloud.provider': 'gcp', 83 | 'host.id': '12345', 84 | 'k8s.cluster.name': 'fakeClusterName', 85 | }) 86 | # --- 87 | -------------------------------------------------------------------------------- /opentelemetry-resourcedetector-gcp/tests/conftest.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 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 | # https://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 | from unittest.mock import MagicMock 16 | 17 | import pytest 18 | from opentelemetry.resourcedetector.gcp_resource_detector import _metadata 19 | 20 | 21 | @pytest.fixture(name="fake_get_metadata") 22 | def fixture_fake_get_metadata(monkeypatch: pytest.MonkeyPatch) -> MagicMock: 23 | mock = MagicMock() 24 | monkeypatch.setattr(_metadata, "get_metadata", mock) 25 | return mock 26 | -------------------------------------------------------------------------------- /opentelemetry-resourcedetector-gcp/tests/test_faas.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 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 | # https://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 | from unittest.mock import MagicMock 16 | 17 | import pytest 18 | from opentelemetry.resourcedetector.gcp_resource_detector import _faas 19 | 20 | 21 | # Reset stuff before every test 22 | # pylint: disable=unused-argument 23 | @pytest.fixture(autouse=True) 24 | def autouse(fake_get_metadata): 25 | pass 26 | 27 | 28 | def test_detects_on_cloud_run(monkeypatch: pytest.MonkeyPatch) -> None: 29 | monkeypatch.setenv("K_CONFIGURATION", "fake-configuration") 30 | assert _faas.on_cloud_run() 31 | 32 | 33 | def test_detects_not_on_cloud_run() -> None: 34 | assert not _faas.on_cloud_run() 35 | 36 | 37 | def test_detects_on_cloud_functions(monkeypatch: pytest.MonkeyPatch) -> None: 38 | monkeypatch.setenv("FUNCTION_TARGET", "fake-function-target") 39 | assert _faas.on_cloud_functions() 40 | 41 | 42 | def test_detects_not_on_cloud_functions() -> None: 43 | assert not _faas.on_cloud_functions() 44 | 45 | 46 | def test_detects_faas_name(monkeypatch: pytest.MonkeyPatch) -> None: 47 | monkeypatch.setenv("K_SERVICE", "fake-service") 48 | assert _faas.faas_name() == "fake-service" 49 | 50 | 51 | def test_detects_faas_version(monkeypatch: pytest.MonkeyPatch) -> None: 52 | monkeypatch.setenv("K_REVISION", "fake-revision") 53 | assert _faas.faas_version() == "fake-revision" 54 | 55 | 56 | def test_detects_faas_instance(fake_get_metadata: MagicMock) -> None: 57 | fake_get_metadata.return_value = {"instance": {"id": "0087244a"}} 58 | assert _faas.faas_instance() == "0087244a" 59 | 60 | 61 | def test_detects_faas_region(fake_get_metadata: MagicMock) -> None: 62 | fake_get_metadata.return_value = { 63 | "instance": {"region": "projects/233510669999/regions/us-east4"} 64 | } 65 | assert _faas.faas_cloud_region() == "us-east4" 66 | -------------------------------------------------------------------------------- /opentelemetry-resourcedetector-gcp/tests/test_gce.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 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 | # https://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 | from unittest.mock import MagicMock 16 | 17 | import pytest 18 | from opentelemetry.resourcedetector.gcp_resource_detector import ( 19 | _gce, 20 | _metadata, 21 | ) 22 | 23 | 24 | # Reset stuff before every test 25 | # pylint: disable=unused-argument 26 | @pytest.fixture(autouse=True) 27 | def autouse(fake_get_metadata): 28 | pass 29 | 30 | 31 | def test_detects_on_gce() -> None: 32 | assert _gce.on_gce() 33 | 34 | 35 | def test_detects_not_on_gce(fake_get_metadata: MagicMock) -> None: 36 | # when the metadata server is not accessible 37 | fake_get_metadata.side_effect = _metadata.MetadataAccessException() 38 | assert not _gce.on_gce() 39 | 40 | # when the metadata server doesn't have the expected structure 41 | fake_get_metadata.return_value = {} 42 | assert not _gce.on_gce() 43 | 44 | 45 | def test_detects_host_type(fake_get_metadata: MagicMock) -> None: 46 | fake_get_metadata.return_value = {"instance": {"machineType": "fake"}} 47 | assert _gce.host_type() == "fake" 48 | 49 | 50 | def test_detects_host_id(fake_get_metadata: MagicMock) -> None: 51 | fake_get_metadata.return_value = {"instance": {"id": 12345}} 52 | assert _gce.host_id() == "12345" 53 | 54 | 55 | def test_detects_host_name(fake_get_metadata: MagicMock) -> None: 56 | fake_get_metadata.return_value = {"instance": {"name": "fake"}} 57 | assert _gce.host_name() == "fake" 58 | 59 | 60 | def test_detects_zone_and_region(fake_get_metadata: MagicMock) -> None: 61 | fake_get_metadata.return_value = { 62 | "instance": {"zone": "projects/233510669999/zones/us-east4-b"} 63 | } 64 | zone_and_region = _gce.availability_zone_and_region() 65 | 66 | assert zone_and_region.zone == "us-east4-b" 67 | assert zone_and_region.region == "us-east4" 68 | 69 | 70 | def test_throws_for_invalid_zone(fake_get_metadata: MagicMock) -> None: 71 | fake_get_metadata.return_value = {"instance": {"zone": ""}} 72 | 73 | with pytest.raises(Exception, match="zone was not in the expected format"): 74 | _gce.availability_zone_and_region() 75 | -------------------------------------------------------------------------------- /opentelemetry-resourcedetector-gcp/tests/test_gke.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 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 | # https://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 | from unittest.mock import MagicMock 16 | 17 | import pytest 18 | from opentelemetry.resourcedetector.gcp_resource_detector import _gke 19 | 20 | 21 | def test_detects_on_gke(monkeypatch: pytest.MonkeyPatch) -> None: 22 | monkeypatch.setenv("KUBERNETES_SERVICE_HOST", "fakehost") 23 | assert _gke.on_gke() 24 | 25 | 26 | def test_detects_not_on_gke() -> None: 27 | assert not _gke.on_gke() 28 | 29 | 30 | def test_detects_host_id(fake_get_metadata: MagicMock) -> None: 31 | fake_get_metadata.return_value = {"instance": {"id": 12345}} 32 | assert _gke.host_id() == "12345" 33 | 34 | 35 | def test_detects_cluster_name(fake_get_metadata: MagicMock) -> None: 36 | fake_get_metadata.return_value = { 37 | "instance": {"attributes": {"cluster-name": "fake"}} 38 | } 39 | assert _gke.cluster_name() == "fake" 40 | 41 | 42 | def test_detects_zone(fake_get_metadata: MagicMock) -> None: 43 | fake_get_metadata.return_value = { 44 | "instance": {"attributes": {"cluster-location": "us-east4-b"}} 45 | } 46 | zone_or_region = _gke.availability_zone_or_region() 47 | assert zone_or_region.type == "zone" 48 | assert zone_or_region.value == "us-east4-b" 49 | 50 | 51 | def test_detects_region(fake_get_metadata: MagicMock) -> None: 52 | fake_get_metadata.return_value = { 53 | "instance": {"attributes": {"cluster-location": "us-east4"}} 54 | } 55 | zone_or_region = _gke.availability_zone_or_region() 56 | assert zone_or_region.type == "region" 57 | assert zone_or_region.value == "us-east4" 58 | 59 | 60 | def test_throws_for_invalid_cluster_location( 61 | fake_get_metadata: MagicMock, 62 | ) -> None: 63 | fake_get_metadata.return_value = { 64 | "instance": {"attributes": {"cluster-location": "invalid"}} 65 | } 66 | 67 | with pytest.raises( 68 | Exception, match="unrecognized format for cluster location" 69 | ): 70 | _gke.availability_zone_or_region() 71 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.black] 2 | line-length = 79 3 | -------------------------------------------------------------------------------- /samples/instrumentation-quickstart/.dockerignore: -------------------------------------------------------------------------------- 1 | integrationtest/ 2 | -------------------------------------------------------------------------------- /samples/instrumentation-quickstart/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.12-slim 2 | COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ 3 | WORKDIR /usr/src/app 4 | COPY . . 5 | RUN uv sync --frozen 6 | CMD uv run gunicorn -b 0.0.0.0:8080 -w 4 'app:app' 2>&1 | tee /var/log/app.log 7 | -------------------------------------------------------------------------------- /samples/instrumentation-quickstart/app.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 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 | import logging 16 | import time 17 | from random import randint, uniform 18 | 19 | import requests 20 | from flask import Flask, url_for 21 | from opentelemetry.instrumentation.flask import FlaskInstrumentor 22 | from opentelemetry.instrumentation.requests import RequestsInstrumentor 23 | 24 | from gcp_logging import setup_structured_logging 25 | from setup_opentelemetry import setup_opentelemetry 26 | 27 | # [START opentelemetry_instrumentation_main] 28 | logger = logging.getLogger(__name__) 29 | 30 | # Initialize OpenTelemetry Python SDK and structured logging 31 | setup_opentelemetry() 32 | setup_structured_logging() 33 | 34 | app = Flask(__name__) 35 | 36 | # Add instrumentation 37 | FlaskInstrumentor().instrument_app(app) 38 | RequestsInstrumentor().instrument() 39 | # [END opentelemetry_instrumentation_main] 40 | 41 | 42 | # [START opentelemetry_instrumentation_handle_multi] 43 | @app.route("/multi") 44 | def multi(): 45 | """Handle an http request by making 3-7 http requests to the /single endpoint.""" 46 | sub_requests = randint(3, 7) 47 | logger.info("handle /multi request", extra={"subRequests": sub_requests}) 48 | for _ in range(sub_requests): 49 | requests.get(url_for("single", _external=True)) 50 | return "ok" 51 | 52 | 53 | # [END opentelemetry_instrumentation_handle_multi] 54 | 55 | 56 | # [START opentelemetry_instrumentation_handle_single] 57 | @app.route("/single") 58 | def single(): 59 | """Handle an http request by sleeping for 100-200 ms, and write the number of seconds slept as the response.""" 60 | duration = uniform(0.1, 0.2) 61 | logger.info("handle /single request", extra={"duration": duration}) 62 | time.sleep(duration) 63 | return f"slept {duration} seconds" 64 | 65 | 66 | # [END opentelemetry_instrumentation_handle_single] 67 | -------------------------------------------------------------------------------- /samples/instrumentation-quickstart/cloudbuild-integration.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2024 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 | steps: 16 | - name: golang:1.23 17 | dir: samples/instrumentation-quickstart/integrationtest 18 | env: 19 | - COMPOSE_OVERRIDE_FILE=../docker-compose.cloudbuild.yaml 20 | # https://github.com/testcontainers/testcontainers-go/issues/2754 21 | - TESTCONTAINERS_RYUK_CONNECTION_TIMEOUT=10m 22 | - TESTCONTAINERS_RYUK_RECONNECTION_TIMEOUT=10m 23 | script: go test -v 24 | 25 | logsBucket: gs://opentelemetry-ops-e2e-cloud-build-logs 26 | options: 27 | machineType: E2_HIGHCPU_8 28 | -------------------------------------------------------------------------------- /samples/instrumentation-quickstart/docker-compose.cloudbuild.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2024 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 | # This compose file is only used for integration tests in Cloud Build 16 | 17 | version: "3" 18 | 19 | networks: 20 | # Make containers use default Cloud Build network for ADC 21 | # https://cloud.google.com/build/docs/build-config-file-schema#network 22 | default: 23 | name: cloudbuild 24 | external: true 25 | -------------------------------------------------------------------------------- /samples/instrumentation-quickstart/docker-compose.creds.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2024 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 | # Use this compose file along with docker-compose.yaml to pass a credentials file from the host 16 | # into the collector container: 17 | # 18 | # ``` 19 | # GOOGLE_CLOUD_PROJECT="otel-quickstart-demos" \ 20 | # GOOGLE_APPLICATION_CREDENTIALS="$HOME/.config/gcloud/application_default_credentials.json" \ 21 | # USERID="$(id -u)" \ 22 | # docker compose -f docker-compose.yaml -f docker-compose.creds.yaml up --abort-on-container-exit 23 | # ``` 24 | 25 | version: "3" 26 | 27 | services: 28 | otelcol: 29 | # If the collector does not have permission to read the mounted volumes, set 30 | # USERID=$(id -u) to run the container as the current user 31 | user: $USERID 32 | volumes: 33 | - ${GOOGLE_APPLICATION_CREDENTIALS?}:${GOOGLE_APPLICATION_CREDENTIALS}:ro 34 | environment: 35 | - GOOGLE_APPLICATION_CREDENTIALS -------------------------------------------------------------------------------- /samples/instrumentation-quickstart/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2024 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 | version: "3" 16 | 17 | services: 18 | app: 19 | build: . 20 | environment: 21 | - OTEL_EXPORTER_OTLP_ENDPOINT=http://otelcol:4318 22 | - OTEL_SERVICE_NAME=otel-quickstart-python 23 | - OTEL_METRIC_EXPORT_INTERVAL=5000 24 | - OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION=base2_exponential_bucket_histogram 25 | volumes: 26 | - logs:/var/log:rw 27 | depends_on: 28 | - "otelcol" 29 | ports: 30 | - 8080 31 | otelcol: 32 | image: otel/opentelemetry-collector-contrib:0.115.1 33 | volumes: 34 | - ./otel-collector-config.yaml:/etc/otelcol-contrib/config.yaml:ro 35 | - logs:/var/log:ro 36 | environment: 37 | - GOOGLE_CLOUD_PROJECT 38 | - GOOGLE_CLOUD_QUOTA_PROJECT 39 | ports: 40 | # Collector prometheus port. The metrics are checked in tests 41 | - 8888 42 | loadgen: 43 | image: golang:1.21 44 | command: 45 | [ 46 | "go", 47 | "run", 48 | "github.com/rakyll/hey@latest", 49 | "-c=2", 50 | "-q=1", 51 | "http://app:8080/multi", 52 | ] 53 | depends_on: 54 | - "app" 55 | volumes: 56 | logs: 57 | -------------------------------------------------------------------------------- /samples/instrumentation-quickstart/gcp_logging.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 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 | import logging 16 | from datetime import datetime 17 | from typing import Optional 18 | 19 | from opentelemetry.instrumentation.logging import LoggingInstrumentor 20 | from pythonjsonlogger import jsonlogger 21 | 22 | 23 | # We override JsonFormatter.formatTime() instead of using the datefmt strftime parameter 24 | # because it does not support microsecond precision. 25 | 26 | 27 | # [START opentelemetry_instrumentation_setup_logging] 28 | class JsonFormatter(jsonlogger.JsonFormatter): 29 | def formatTime(self, record: logging.LogRecord, datefmt: Optional[str] = None): 30 | # Format the timestamp as RFC 3339 with microsecond precision 31 | isoformat = datetime.fromtimestamp(record.created).isoformat() 32 | return f"{isoformat}Z" 33 | 34 | 35 | def setup_structured_logging() -> None: 36 | LoggingInstrumentor().instrument() 37 | 38 | log_handler = logging.StreamHandler() 39 | formatter = JsonFormatter( 40 | "%(asctime)s %(levelname)s %(message)s %(otelTraceID)s %(otelSpanID)s %(otelTraceSampled)s", 41 | rename_fields={ 42 | "levelname": "severity", 43 | "asctime": "timestamp", 44 | "otelTraceID": "logging.googleapis.com/trace", 45 | "otelSpanID": "logging.googleapis.com/spanId", 46 | "otelTraceSampled": "logging.googleapis.com/trace_sampled", 47 | }, 48 | ) 49 | log_handler.setFormatter(formatter) 50 | logging.basicConfig( 51 | level=logging.INFO, 52 | handlers=[log_handler], 53 | ) 54 | 55 | 56 | # [END opentelemetry_instrumentation_setup_logging] 57 | -------------------------------------------------------------------------------- /samples/instrumentation-quickstart/integrationtest/quickstart_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 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 | // https://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 | // Tests that docker compose services come up and that metrics, logs, and traces are 16 | // successfully sent from the collector to GCP. See 17 | // https://github.com/GoogleCloudPlatform/opentelemetry-operations-e2e-testing/blob/main/quickstarttest/README.md 18 | // for details 19 | 20 | package integrationtest 21 | 22 | import ( 23 | "testing" 24 | 25 | "github.com/GoogleCloudPlatform/opentelemetry-operations-e2e-testing/quickstarttest" 26 | ) 27 | 28 | func TestApp(t *testing.T) { 29 | quickstarttest.InstrumentationQuickstartTest(t, "..") 30 | } 31 | -------------------------------------------------------------------------------- /samples/instrumentation-quickstart/pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "instrumentation-quickstart" 3 | version = "0.1.0" 4 | description = "A Flask app instrumented with OpenTelemetry and structured logging for GCP" 5 | readme = "README.md" 6 | requires-python = ">=3.9" 7 | dependencies = [ 8 | "flask>=3.1.0", 9 | "gunicorn>=23.0.0", 10 | "opentelemetry-api>=1.29.0", 11 | "opentelemetry-exporter-otlp-proto-http>=1.29.0", 12 | "opentelemetry-instrumentation-flask>=0.50b0", 13 | "opentelemetry-instrumentation-logging>=0.50b0", 14 | "opentelemetry-instrumentation-requests>=0.50b0", 15 | "opentelemetry-sdk>=1.29.0", 16 | "python-json-logger>=3.2.0", 17 | "requests>=2.32.3", 18 | ] 19 | -------------------------------------------------------------------------------- /samples/instrumentation-quickstart/setup_opentelemetry.py: -------------------------------------------------------------------------------- 1 | # Copyright 2024 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 | import os 16 | 17 | from opentelemetry import _events as events 18 | from opentelemetry import _logs as logs 19 | from opentelemetry import metrics, trace 20 | from opentelemetry.exporter.otlp.proto.http._log_exporter import OTLPLogExporter 21 | from opentelemetry.exporter.otlp.proto.http.metric_exporter import OTLPMetricExporter 22 | from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter 23 | from opentelemetry.sdk._events import EventLoggerProvider 24 | from opentelemetry.sdk._logs import LoggerProvider 25 | from opentelemetry.sdk._logs.export import BatchLogRecordProcessor 26 | from opentelemetry.sdk.metrics import MeterProvider 27 | from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader 28 | from opentelemetry.sdk.resources import SERVICE_INSTANCE_ID, Resource 29 | from opentelemetry.sdk.trace import TracerProvider 30 | from opentelemetry.sdk.trace.export import BatchSpanProcessor 31 | 32 | 33 | # [START opentelemetry_instrumentation_setup_opentelemetry] 34 | def setup_opentelemetry() -> None: 35 | resource = Resource.create( 36 | attributes={ 37 | # Use the PID as the service.instance.id to avoid duplicate timeseries 38 | # from different Gunicorn worker processes. 39 | SERVICE_INSTANCE_ID: f"worker-{os.getpid()}", 40 | } 41 | ) 42 | 43 | # Set up OpenTelemetry Python SDK 44 | tracer_provider = TracerProvider(resource=resource) 45 | tracer_provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter())) 46 | trace.set_tracer_provider(tracer_provider) 47 | 48 | logger_provider = LoggerProvider(resource=resource) 49 | logger_provider.add_log_record_processor(BatchLogRecordProcessor(OTLPLogExporter())) 50 | logs.set_logger_provider(logger_provider) 51 | 52 | event_logger_provider = EventLoggerProvider(logger_provider) 53 | events.set_event_logger_provider(event_logger_provider) 54 | 55 | reader = PeriodicExportingMetricReader(OTLPMetricExporter()) 56 | meter_provider = MeterProvider(metric_readers=[reader], resource=resource) 57 | metrics.set_meter_provider(meter_provider) 58 | 59 | 60 | # [END opentelemetry_instrumentation_setup_opentelemetry] 61 | -------------------------------------------------------------------------------- /samples/langgraph-sql-agent/.python-version: -------------------------------------------------------------------------------- 1 | 3.13 2 | -------------------------------------------------------------------------------- /samples/langgraph-sql-agent/README.md: -------------------------------------------------------------------------------- 1 | # OpenTelemetry LangGraph instrumentation example 2 | 3 | 4 | 5 | This sample is a LangGraph agent instrumented with OpenTelemetry to send traces and logs with 6 | GenAI prompts and responses, and metrics to Google Cloud Observability. 7 | 8 | The Agent is a SQL expert that has full access to an ephemeral SQLite database. The database is 9 | initially empty. It is built with the the LangGraph prebuilt [ReAct 10 | Agent](https://langchain-ai.github.io/langgraph/agents/agents/#basic-configuration#code) and the 11 | [SQLDatabaseToolkit](https://python.langchain.com/docs/integrations/tools/sql_database/). 12 | 13 | ## APIs and Permissions 14 | 15 | Enable the relevant Cloud Observability APIs if they aren't already enabled. 16 | ```sh 17 | gcloud services enable telemetry.googleapis.com logging.googleapis.com monitoring.googleapis.com cloudtrace.googleapis.com 18 | ``` 19 | 20 | This sample writes to Cloud Logging, Cloud Monitoring, and Cloud Trace. Grant yourself the 21 | following roles to run the example: 22 | - `roles/logging.logWriter` – see https://cloud.google.com/logging/docs/access-control#permissions_and_roles 23 | - `roles/monitoring.metricWriter` – see https://cloud.google.com/monitoring/access-control#predefined_roles 24 | - `roles/telemetry.writer` – see https://cloud.google.com/trace/docs/iam#telemetry-roles 25 | 26 | ## Running the example 27 | 28 | The sample can easily be run in Cloud Shell. You can also use 29 | [Application Default Credentials][ADC] locally. Clone and set environment variables: 30 | ```sh 31 | git clone https://github.com/GoogleCloudPlatform/opentelemetry-operations-python.git 32 | cd opentelemetry-operations-python/samples/langgraph-sql-agent 33 | 34 | # Capture GenAI prompts and responses 35 | export OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true 36 | # Capture application logs automatically 37 | export OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true 38 | ``` 39 | 40 | Create a virtual environment and run the sample: 41 | ```sh 42 | python -m venv venv/ 43 | source venv/bin/activate 44 | pip install -r requirements.txt 45 | python main.py 46 | ``` 47 | 48 | Alternatively if you have [`uv`](https://docs.astral.sh/uv/) installed: 49 | 50 | ```sh 51 | uv run main.py 52 | ``` 53 | 54 | ## Viewing the results 55 | 56 | To view the generated traces with [Generative AI 57 | events](https://cloud.google.com/trace/docs/finding-traces#view_generative_ai_events) in the 58 | GCP console, use the [Trace Explorer](https://cloud.google.com/trace/docs/finding-traces). Filter for spans named `invoke agent`. 59 | 60 | [ADC]: https://cloud.google.com/docs/authentication/application-default-credentials 61 | -------------------------------------------------------------------------------- /samples/langgraph-sql-agent/patched_vertexai.py: -------------------------------------------------------------------------------- 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 | # https://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 | from __future__ import annotations 16 | 17 | from typing import Any 18 | 19 | from google.cloud.aiplatform_v1.types import ( 20 | GenerateContentRequest as v1GenerateContentRequest, 21 | ) 22 | from google.cloud.aiplatform_v1beta1.types import ( 23 | GenerateContentRequest, 24 | ) 25 | from langchain_core.messages import ( 26 | BaseMessage, 27 | ) 28 | from langchain_google_vertexai import ChatVertexAI 29 | 30 | 31 | class PatchedChatVertexAI(ChatVertexAI): 32 | def _prepare_request_gemini( 33 | self, messages: list[BaseMessage], *args: Any, **kwargs: Any 34 | ) -> v1GenerateContentRequest | GenerateContentRequest: 35 | # See https://github.com/langchain-ai/langchain-google/issues/886 36 | # 37 | # Filter out any blocked messages with no content which can appear if you have a blocked 38 | # message from finish_reason SAFETY: 39 | # 40 | # AIMessage( 41 | # content="", 42 | # additional_kwargs={}, 43 | # response_metadata={ 44 | # "is_blocked": True, 45 | # "safety_ratings": [ ... ], 46 | # "finish_reason": "SAFETY", 47 | # }, 48 | # ... 49 | # ) 50 | # 51 | # These cause `google.api_core.exceptions.InvalidArgument: 400 Unable to submit request 52 | # because it must include at least one parts field` 53 | 54 | messages = [ 55 | message 56 | for message in messages 57 | if not message.response_metadata.get("is_blocked", False) 58 | ] 59 | return super()._prepare_request_gemini(messages, *args, **kwargs) 60 | -------------------------------------------------------------------------------- /samples/langgraph-sql-agent/pyproject.toml: -------------------------------------------------------------------------------- 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 | # https://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 | [project] 16 | name = "langgraph-sql-agent" 17 | version = "0.1.0" 18 | description = "A LangGraph ReAct agent that can run queries on an ephemeral SQLite database" 19 | readme = "README.md" 20 | requires-python = ">=3.12" 21 | dependencies = [ 22 | "langchain-community>=0.3.16", 23 | "langchain-google-vertexai>=2.0.7", 24 | "langgraph>=0.4.3", 25 | "opentelemetry-exporter-gcp-logging>=1.9.0a0", 26 | "opentelemetry-exporter-gcp-monitoring>=1.9.0a0", 27 | "opentelemetry-exporter-otlp-proto-grpc>=1.33.0", 28 | "opentelemetry-instrumentation-httpx>=0.54b0", 29 | "opentelemetry-instrumentation-requests>=0.54b0", 30 | "opentelemetry-instrumentation-sqlite3>=0.54b0", 31 | "opentelemetry-instrumentation-vertexai>=2.0b0", 32 | "rich>=14.0.0", 33 | ] 34 | -------------------------------------------------------------------------------- /samples/langgraph-sql-agent/utils.py: -------------------------------------------------------------------------------- 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 | # https://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 | from typing import Iterable 16 | 17 | from langchain_core.messages.base import BaseMessage 18 | from rich.console import Console 19 | from rich.markdown import Markdown 20 | 21 | console = Console() 22 | 23 | 24 | def render_messages(messages: Iterable[BaseMessage]) -> None: 25 | for message in messages: 26 | _render_message(message) 27 | print_markdown("---") 28 | 29 | 30 | def _render_message(message: BaseMessage) -> None: 31 | # Filter out tool calls 32 | if message.type not in ("human", "ai"): 33 | return 34 | 35 | content = ( 36 | message.content 37 | if isinstance(message.content, str) 38 | else message.content[-1]["text"] 39 | ).strip() 40 | 41 | # Response was probably blocked by a harm category, go check the trace for details 42 | if message.response_metadata.get("is_blocked", False): 43 | console.print("❌ Response blocked, try again") 44 | 45 | if not content: 46 | return 47 | 48 | if message.type == "human": 49 | print_markdown(f"👤 User:\n{content}") 50 | else: 51 | print_markdown(f"🤖 Agent:\n{content}") 52 | 53 | 54 | def print_markdown(markdown: str) -> None: 55 | console.print(Markdown(markdown)) 56 | 57 | 58 | def ask_prompt() -> str: 59 | return console.input("[bold magenta]Talk to the SQL agent >> [/]") 60 | -------------------------------------------------------------------------------- /samples/otlpmetric/README.md: -------------------------------------------------------------------------------- 1 | ### OTLP Export Sample with GCP Auth 2 | This example shows how to send metrics to an OTLP (OpenTelemetry Protocol) endpoint that is protected by GCP authentication. The sample showcases the metric export using gRPC. 3 | 4 | #### Installation 5 | Install the dependencies and libraries required to run the samples: 6 | 7 | ```sh 8 | # Move to the sample repository 9 | cd samples/otlpmetric 10 | 11 | pip install -r requirements.txt 12 | ``` 13 | 14 | #### Prerequisites 15 | Get Google credentials on your machine: 16 | 17 | ```sh 18 | gcloud auth application-default login 19 | ``` 20 | 21 | #### Run the Sample 22 | ```sh 23 | # export necessary OTEL environment variables 24 | export PROJECT_ID= 25 | export OTEL_EXPORTER_OTLP_ENDPOINT= 26 | export OTEL_RESOURCE_ATTRIBUTES="gcp.project_id=$PROJECT_ID,service.name=otlp-sample,service.instance.id=1" 27 | 28 | # from the samples/otlpmetric repository 29 | python3 example.py 30 | ``` 31 | -------------------------------------------------------------------------------- /samples/otlpmetric/example.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright 2025 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | import time 17 | 18 | import google.auth 19 | import google.auth.transport.grpc 20 | import google.auth.transport.requests 21 | import grpc 22 | from google.auth.transport.grpc import AuthMetadataPlugin 23 | from opentelemetry import metrics 24 | from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import ( 25 | OTLPMetricExporter, 26 | ) 27 | from opentelemetry.resourcedetector.gcp_resource_detector._detector import ( 28 | GoogleCloudResourceDetector, 29 | ) 30 | from opentelemetry.sdk.resources import SERVICE_NAME, Resource, get_aggregated_resources 31 | from opentelemetry.sdk.metrics import MeterProvider 32 | from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader 33 | 34 | """ 35 | This is a sample script that exports OTLP metrics encoded as protobufs via gRPC. 36 | """ 37 | 38 | credentials, project_id = google.auth.default() 39 | request = google.auth.transport.requests.Request() 40 | resource = get_aggregated_resources( 41 | [GoogleCloudResourceDetector(raise_on_error=True)] 42 | ) 43 | 44 | auth_metadata_plugin = AuthMetadataPlugin( 45 | credentials=credentials, request=request 46 | ) 47 | channel_creds = grpc.composite_channel_credentials( 48 | grpc.ssl_channel_credentials(), 49 | grpc.metadata_call_credentials(auth_metadata_plugin), 50 | ) 51 | 52 | exporter = OTLPMetricExporter(credentials=channel_creds) 53 | reader = PeriodicExportingMetricReader(exporter) 54 | provider = MeterProvider(metric_readers=[reader],resource=resource) 55 | meter = provider.get_meter("gcp.otlp.sample") 56 | counter = meter.create_counter("sample.otlp.counter") 57 | 58 | 59 | def do_work(): 60 | counter.add(1) 61 | # do some work that the 'counter' will track 62 | print("doing some work...") 63 | 64 | 65 | def do_work_repeatedly(): 66 | try: 67 | while True: 68 | do_work() 69 | time.sleep(1) 70 | except KeyboardInterrupt: 71 | print("\nKeyboard Interrupt: Stopping work.") 72 | 73 | 74 | do_work_repeatedly() 75 | -------------------------------------------------------------------------------- /samples/otlpmetric/requirements.txt: -------------------------------------------------------------------------------- 1 | # Dependencies require for trace export samples 2 | opentelemetry-api==1.24.0 3 | opentelemetry-sdk==1.24.0 4 | google-auth==2.18.1 5 | opentelemetry-exporter-otlp-proto-grpc==1.24.0 6 | grpcio==1.63.0 7 | opentelemetry-resourcedetector-gcp==1.8.0 8 | -------------------------------------------------------------------------------- /samples/otlptrace/README.md: -------------------------------------------------------------------------------- 1 | ### OTLP Export Sample with GCP Auth 2 | This example shows how to send traces to an OTLP (OpenTelemetry Protocol) endpoint that is protected by GCP authentication. The sample showcases the trace export using: 3 | - gRPC 4 | - http with protobuf 5 | 6 | #### Installation 7 | Install the dependencies and libraries required to run the samples: 8 | 9 | ```sh 10 | # Move to the sample repository 11 | cd samples/otlptrace 12 | 13 | pip install -r requirements.txt 14 | ``` 15 | 16 | #### Prerequisites 17 | Get Google credentials on your machine: 18 | 19 | ```sh 20 | gcloud auth application-default login 21 | ``` 22 | 23 | #### Run the Sample 24 | ```sh 25 | # export necessary OTEL environment variables 26 | export OTEL_RESOURCE_ATTRIBUTES="gcp.project_id=" 27 | 28 | # from the samples/otlptrace repository 29 | python3 example_grpc.py 30 | ``` 31 | Other variations of the sample: 32 | - `python3 example_http.py` - will run a program that will export traces using http/protobuf. 33 | -------------------------------------------------------------------------------- /samples/otlptrace/example_grpc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright 2024 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | import time 17 | 18 | import google.auth 19 | import google.auth.transport.grpc 20 | import google.auth.transport.requests 21 | import grpc 22 | from google.auth.transport.grpc import AuthMetadataPlugin 23 | from opentelemetry import trace 24 | from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import ( 25 | OTLPSpanExporter, 26 | ) 27 | from opentelemetry.sdk.resources import SERVICE_NAME, Resource 28 | from opentelemetry.sdk.trace import TracerProvider 29 | from opentelemetry.sdk.trace.export import BatchSpanProcessor 30 | 31 | """ 32 | This is a sample script that exports OTLP traces encoded as protobufs via gRPC. 33 | """ 34 | 35 | credentials, _ = google.auth.default() 36 | request = google.auth.transport.requests.Request() 37 | resource = Resource.create(attributes={SERVICE_NAME: "otlp-gcp-grpc-sample"}) 38 | 39 | auth_metadata_plugin = AuthMetadataPlugin(credentials=credentials, request=request) 40 | channel_creds = grpc.composite_channel_credentials( 41 | grpc.ssl_channel_credentials(), 42 | grpc.metadata_call_credentials(auth_metadata_plugin), 43 | ) 44 | 45 | trace_provider = TracerProvider(resource=resource) 46 | processor = BatchSpanProcessor( 47 | OTLPSpanExporter( 48 | credentials=channel_creds, 49 | endpoint="https://telemetry.googleapis.com:443/v1/traces", 50 | ) 51 | ) 52 | trace_provider.add_span_processor(processor) 53 | trace.set_tracer_provider(trace_provider) 54 | tracer = trace.get_tracer("my.tracer.name") 55 | 56 | 57 | def do_work(): 58 | with tracer.start_as_current_span("span-grpc") as span: 59 | # do some work that 'span' will track 60 | print("doing some work...") 61 | # When the 'with' block goes out of scope, 'span' is closed for you 62 | 63 | 64 | def do_work_repeatedly(): 65 | try: 66 | while True: 67 | do_work() 68 | time.sleep(10) 69 | except KeyboardInterrupt: 70 | print("\nKeyboard Interrupt: Stopping work.") 71 | 72 | 73 | do_work_repeatedly() 74 | -------------------------------------------------------------------------------- /samples/otlptrace/example_http.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright 2024 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | import google.auth 17 | import google.auth.transport.requests 18 | from opentelemetry import trace 19 | from opentelemetry.exporter.otlp.proto.http.trace_exporter import ( 20 | OTLPSpanExporter, 21 | ) 22 | from google.auth.transport.requests import AuthorizedSession 23 | from opentelemetry.sdk.resources import SERVICE_NAME, Resource 24 | from opentelemetry.sdk.trace import TracerProvider 25 | from opentelemetry.sdk.trace.export import BatchSpanProcessor 26 | 27 | credentials, _ = google.auth.default() 28 | trace_provider = TracerProvider( 29 | resource=Resource.create(attributes={SERVICE_NAME: "otlp-gcp-http-sample"}) 30 | ) 31 | processor = BatchSpanProcessor( 32 | OTLPSpanExporter( 33 | session=AuthorizedSession(credentials), 34 | endpoint="https://telemetry.googleapis.com:443/v1/traces", 35 | ) 36 | ) 37 | trace_provider.add_span_processor(processor) 38 | trace.set_tracer_provider(trace_provider) 39 | tracer = trace.get_tracer("my.tracer.name") 40 | 41 | 42 | def do_work(): 43 | with tracer.start_as_current_span("span-http") as span: 44 | # do some work that 'span' will track 45 | print("doing some work...") 46 | # When the 'with' block goes out of scope, 'span' is closed for you 47 | 48 | 49 | do_work() 50 | -------------------------------------------------------------------------------- /samples/otlptrace/requirements.txt: -------------------------------------------------------------------------------- 1 | # Dependencies require for trace export samples 2 | opentelemetry-api==1.24.0 3 | opentelemetry-sdk==1.24.0 4 | google-auth==2.18.1 5 | opentelemetry-exporter-otlp-proto-http==1.24.0 6 | opentelemetry-exporter-otlp-proto-grpc==1.24.0 7 | grpcio==1.63.0 8 | -------------------------------------------------------------------------------- /test-common/MANIFEST.in: -------------------------------------------------------------------------------- 1 | graft src 2 | graft tests 3 | global-exclude *.pyc 4 | global-exclude *.pyo 5 | global-exclude __pycache__/* 6 | include MANIFEST.in 7 | -------------------------------------------------------------------------------- /test-common/setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = test-common 3 | description = Test utilities used across packages in this repo 4 | 5 | [options] 6 | package_dir= 7 | =src 8 | packages=find_namespace: 9 | install_requires = 10 | 11 | [options.packages.find] 12 | where = src 13 | 14 | -------------------------------------------------------------------------------- /test-common/setup.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 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 | import setuptools 16 | 17 | setuptools.setup() 18 | -------------------------------------------------------------------------------- /test-common/src/test_common/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 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 | """Test utilities used across packages 16 | 17 | This code is only used in other modules' tests 18 | """ 19 | 20 | 21 | from .base_exporter_integration_test import BaseExporterIntegrationTest 22 | 23 | try: 24 | from time import time_ns as _time_ns 25 | except ImportError: 26 | from time import time 27 | 28 | def _time_ns() -> int: 29 | return int(time() * 1e9) 30 | 31 | 32 | def time_ns() -> int: 33 | """ 34 | Use time.time_ns if it is available or convert time.time() to nanoseconds 35 | (lower resolution) 36 | 37 | TODO: remove when python3.6 is dropped 38 | """ 39 | return _time_ns() 40 | 41 | 42 | __all__ = ["time_ns", "BaseExporterIntegrationTest"] 43 | 44 | -------------------------------------------------------------------------------- /test-common/src/test_common/base_exporter_integration_test.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 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 | import socket 16 | import subprocess 17 | import unittest 18 | 19 | 20 | class BaseExporterIntegrationTest(unittest.TestCase): 21 | def setUp(self) -> None: 22 | self.project_id = "TEST-PROJECT" 23 | 24 | # Find a free port to spin up our server at. 25 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 26 | sock.bind(("localhost", 0)) 27 | self.address = "localhost:" + str(sock.getsockname()[1]) 28 | sock.close() 29 | 30 | # Start the mock server. 31 | args = ["mock_server", "-address", self.address] 32 | self.mock_server_process = subprocess.Popen( 33 | args, stderr=subprocess.PIPE, stdout=subprocess.PIPE 34 | ) 35 | # Block until the mock server starts (it will output the address after starting). 36 | if ( 37 | self.mock_server_process.stderr is None 38 | or self.mock_server_process.stdout is None 39 | ): 40 | raise RuntimeError("stderr or stdout is None") 41 | self.mock_server_process.stderr.readline() 42 | 43 | def tearDown(self) -> None: 44 | self.mock_server_process.kill() 45 | if ( 46 | self.mock_server_process.stderr is None 47 | or self.mock_server_process.stdout is None 48 | ): 49 | raise RuntimeError("stderr or stdout is None") 50 | stdout = self.mock_server_process.stdout.read().decode() 51 | stderr = self.mock_server_process.stderr.read().decode() 52 | if stderr or stdout: 53 | self.fail( 54 | "Mock server should not have had any output, got stdout:\n%s\n\nstderr:\n%s", 55 | stdout, 56 | stderr, 57 | ) 58 | --------------------------------------------------------------------------------