From 322d1c4a943694f0616a57d068b4bef1c9039fcb Mon Sep 17 00:00:00 2001 From: Aaron Abbott Date: Mon, 4 Apr 2022 10:01:06 -0400 Subject: [PATCH] Add entry point for Cloud Trace exporter to work with auto instrumentation (#179) --- opentelemetry-exporter-gcp-trace/CHANGELOG.md | 3 ++ opentelemetry-exporter-gcp-trace/setup.cfg | 6 +++ .../exporter/cloud_trace/__init__.py | 51 ++++++++++++++++--- .../cloud_trace/environment_variables.py | 32 ++++++++++++ .../tests/test_cloud_trace_auto_instrument.py | 32 ++++++++++++ 5 files changed, 117 insertions(+), 7 deletions(-) create mode 100644 opentelemetry-exporter-gcp-trace/src/opentelemetry/exporter/cloud_trace/environment_variables.py create mode 100644 opentelemetry-exporter-gcp-trace/tests/test_cloud_trace_auto_instrument.py diff --git a/opentelemetry-exporter-gcp-trace/CHANGELOG.md b/opentelemetry-exporter-gcp-trace/CHANGELOG.md index 714ac57d..5a00ffc6 100644 --- a/opentelemetry-exporter-gcp-trace/CHANGELOG.md +++ b/opentelemetry-exporter-gcp-trace/CHANGELOG.md @@ -2,6 +2,9 @@ ## Unreleased +- Add entry point for Cloud Trace exporter to work with auto instrumentation + ([#179](https://github.com/GoogleCloudPlatform/opentelemetry-operations-python/pull/179)) + ## Version 1.1.0 Released 2022-01-13 diff --git a/opentelemetry-exporter-gcp-trace/setup.cfg b/opentelemetry-exporter-gcp-trace/setup.cfg index bda81ce7..dbd24f43 100644 --- a/opentelemetry-exporter-gcp-trace/setup.cfg +++ b/opentelemetry-exporter-gcp-trace/setup.cfg @@ -34,3 +34,9 @@ where = src [options.extras_require] test = + +[options.entry_points] +opentelemetry_traces_exporter = + gcp_trace = opentelemetry.exporter.cloud_trace:CloudTraceSpanExporter +opentelemetry_environment_variables = + gcp_trace = opentelemetry.exporter.cloud_trace.environment_variables diff --git a/opentelemetry-exporter-gcp-trace/src/opentelemetry/exporter/cloud_trace/__init__.py b/opentelemetry-exporter-gcp-trace/src/opentelemetry/exporter/cloud_trace/__init__.py index d9f90ecd..a3e3291e 100644 --- a/opentelemetry-exporter-gcp-trace/src/opentelemetry/exporter/cloud_trace/__init__.py +++ b/opentelemetry-exporter-gcp-trace/src/opentelemetry/exporter/cloud_trace/__init__.py @@ -44,6 +44,28 @@ :class:`opentelemetry.sdk.trace.export.BatchSpanProcessor` with the default parameters for performance reasons. +Auto-instrumentation +-------------------- + +This exporter can also be used with `OpenTelemetry auto-instrumentation +`_: + +.. code-block:: sh + + opentelemetry-instrument --traces_exporter gcp_trace + +Configuration is supported through environment variables +(:mod:`opentelemetry.exporter.cloud_trace.environment_variables`) or the corresponding command +line arguments to ``opentelemetry-instrument``: + +.. code-block:: sh + + opentelemetry-instrument --traces_exporter gcp_trace \\ + --exporter_gcp_trace_project_id my-project \\ + + +See ``opentelemetry-instrument --help`` for all configuration options. + API --- """ @@ -51,6 +73,7 @@ import logging import re from collections.abc import Sequence as SequenceABC +from os import environ from typing import ( Any, Dict, @@ -67,8 +90,14 @@ import pkg_resources from google.cloud.trace_v2 import BatchWriteSpansRequest, TraceServiceClient from google.cloud.trace_v2 import types as trace_types -from google.protobuf.timestamp_pb2 import Timestamp +from google.protobuf.timestamp_pb2 import ( # pylint: disable=no-name-in-module + Timestamp, +) from google.rpc import code_pb2, status_pb2 +from opentelemetry.exporter.cloud_trace.environment_variables import ( + OTEL_EXPORTER_GCP_TRACE_PROJECT_ID, + OTEL_EXPORTER_GCP_TRACE_RESOURCE_REGEX, +) from opentelemetry.exporter.cloud_trace.version import __version__ from opentelemetry.sdk.resources import Resource from opentelemetry.sdk.trace import Event @@ -97,11 +126,13 @@ class CloudTraceSpanExporter(SpanExporter): """Cloud Trace span exporter for OpenTelemetry. Args: - project_id: ID of the cloud project that will receive the traces. + project_id: GCP project ID for the project to send spans to. Alternatively, can be + configured with :envvar:`OTEL_EXPORTER_GCP_TRACE_PROJECT_ID`. client: Cloud Trace client. If not given, will be taken from gcloud default credentials - resource_regex: Resource attributes with keys matching this regex will be - added to exported spans as labels (default: None). + resource_regex: Resource attributes with keys matching this regex will be added to + exported spans as labels (default: None). Alternatively, can be configured with + :envvar:`OTEL_EXPORTER_GCP_TRACE_RESOURCE_REGEX`. """ def __init__( @@ -112,9 +143,15 @@ def __init__( ): self.client: TraceServiceClient = client or TraceServiceClient() if not project_id: - _, self.project_id = google.auth.default() - else: - self.project_id = project_id + project_id = environ.get(OTEL_EXPORTER_GCP_TRACE_PROJECT_ID) + if not project_id: + _, project_id = google.auth.default() + self.project_id = project_id + + if not resource_regex: + resource_regex = environ.get( + OTEL_EXPORTER_GCP_TRACE_RESOURCE_REGEX + ) self.resource_regex = ( re.compile(resource_regex) if resource_regex else None ) diff --git a/opentelemetry-exporter-gcp-trace/src/opentelemetry/exporter/cloud_trace/environment_variables.py b/opentelemetry-exporter-gcp-trace/src/opentelemetry/exporter/cloud_trace/environment_variables.py new file mode 100644 index 00000000..387ce3d5 --- /dev/null +++ b/opentelemetry-exporter-gcp-trace/src/opentelemetry/exporter/cloud_trace/environment_variables.py @@ -0,0 +1,32 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +OTEL_EXPORTER_GCP_TRACE_PROJECT_ID = "OTEL_EXPORTER_GCP_TRACE_PROJECT_ID" +""" +.. envvar:: OTEL_EXPORTER_GCP_TRACE_PROJECT_ID + + GCP project ID for the project to send spans to. Equivalent to constructor parameter to + :class:`opentelemetry.exporter.cloud_trace.CloudTraceSpanExporter`. +""" + +OTEL_EXPORTER_GCP_TRACE_RESOURCE_REGEX = ( + "OTEL_EXPORTER_GCP_TRACE_RESOURCE_REGEX" +) +""" +.. envvar:: OTEL_EXPORTER_GCP_TRACE_RESOURCE_REGEX + + Resource attributes with keys matching this regex will be added to exported spans as labels + :class:`opentelemetry.exporter.cloud_trace.CloudTraceSpanExporter`. Equivalent to constructor parameter to + :class:`opentelemetry.exporter.cloud_trace.CloudTraceSpanExporter`. +""" diff --git a/opentelemetry-exporter-gcp-trace/tests/test_cloud_trace_auto_instrument.py b/opentelemetry-exporter-gcp-trace/tests/test_cloud_trace_auto_instrument.py new file mode 100644 index 00000000..f6b8ba91 --- /dev/null +++ b/opentelemetry-exporter-gcp-trace/tests/test_cloud_trace_auto_instrument.py @@ -0,0 +1,32 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from unittest import TestCase + +from opentelemetry.exporter.cloud_trace import CloudTraceSpanExporter + +# private import for testing only +from opentelemetry.sdk._configuration import _import_exporters + + +class TestCloudTraceAutoInstrument(TestCase): + def test_loads_cloud_trace_exporter(self): + """Test that OTel configuration internals can load the trace exporter from entrypoint + by name""" + trace_exporters, _ = _import_exporters( + trace_exporter_names=["gcp_trace"], log_exporter_names=[] + ) + self.assertEqual( + trace_exporters, {"gcp_trace": CloudTraceSpanExporter} + )