Skip to content

Add a Customizer class that helps initialize python auto instrumentation to send telemetry to GCP #388

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions opentelemetry-customizer/MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
graft src
graft tests
global-exclude *.pyc
global-exclude *.pyo
global-exclude __pycache__/*
global-exclude myproj*
include CHANGELOG.md
include MANIFEST.in
include README.rst
include LICENSE
Empty file.
49 changes: 49 additions & 0 deletions opentelemetry-customizer/setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
[metadata]
name = opentelemetry-gcp-customizer
description = Google Cloud Auto Instrumentation Customizer for OpenTelemetry
long_description = file: README.rst
long_description_content_type = text/x-rst
author = Google
author_email = [email protected]
url = https://github.com/GoogleCloudPlatform/opentelemetry-operations-python/tree/main/opentelemetry-exporter-gcp-logging
platforms = any
license = Apache-2.0
classifiers =
Development Status :: 4 - Beta
Intended Audience :: Developers
License :: OSI Approved :: Apache Software License
Programming Language :: Python
Programming Language :: Python :: 3
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: 3.11
Programming Language :: Python :: 3.12

[options]
python_requires = >=3.7
package_dir=
=src
packages=find_namespace:
install_requires =
google-auth ~= 2.38
grpcio ~= 1.7
opentelemetry-sdk ~= 1.13
opentelemetry-resourcedetector-gcp ~= 1.9.0a0

[options.packages.find]
where = src

[options.extras_require]
test =

[options.entry_points]
opentelemetry_customizer =
send_logs_and_traces_to_gcp = opentelemetry.customizer:send_logs_and_traces_to_gcp
send_metrics_and_traces_to_gcp = opentelemetry.customizer:send_metrics_and_traces_to_gcp
send_logs_and_metrics_to_gcp = opentelemetry.customizer:send_logs_and_metrics_to_gcp
send_only_traces_to_gcp = opentelemetry.customizer:send_only_traces_to_gcp
send_only_metrics_to_gcp = opentelemetry.customizer:send_only_metrics_to_gcp
send_only_logs_to_gcp = opentelemetry.customizer:send_only_logs_to_gcp
send_all_telemetry_to_gcp = opentelemetry.customizer:send_all_telemetry_to_gcp
33 changes: 33 additions & 0 deletions opentelemetry-customizer/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Copyright 2025 The OpenTelemetry Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os

import setuptools

BASE_DIR = os.path.dirname(__file__)
VERSION_FILENAME = os.path.join(
BASE_DIR,
"src",
"opentelemetry",
"customizer",
"version.py",
)
PACKAGE_INFO = {}
with open(VERSION_FILENAME) as f:
exec(f.read(), PACKAGE_INFO)

setuptools.setup(
version=PACKAGE_INFO["__version__"],
package_data={"opentelemetry": ["py.typed"]},
)
124 changes: 124 additions & 0 deletions opentelemetry-customizer/src/opentelemetry/customizer/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
from opentelemetry.sdk._config_customizer import _BaseConfiguratorCustomizer
import inspect
from opentelemetry.sdk._logs.export import LogExporter
from opentelemetry.sdk.metrics.export import (
MetricExporter,
)
from typing import Type, Union
from opentelemetry.sdk.trace.export import SpanExporter
import google.auth
import grpc
from google.auth.transport import requests as auth_requests
from google.auth.transport.grpc import AuthMetadataPlugin
from google.auth.transport.requests import AuthorizedSession
from opentelemetry.resourcedetector.gcp_resource_detector._detector import (
GoogleCloudResourceDetector,
)


class GoogleCloudConfiguratorCustomizer(_BaseConfiguratorCustomizer):
def __init__(
self,
send_metrics_to_gcp: bool = False,
send_logs_to_gcp: bool = False,
send_spans_to_gcp: bool = False,
):
self.send_metrics_to_gcp = send_metrics_to_gcp
self.send_logs_to_gcp = send_logs_to_gcp
self.send_spans_to_gcp = send_spans_to_gcp
credentials, _ = google.auth.default()
self.channel_credentials = grpc.composite_channel_credentials(
grpc.ssl_channel_credentials(),
grpc.metadata_call_credentials(
AuthMetadataPlugin(
credentials=credentials, request=auth_requests.Request()
)
),
)
self.session = AuthorizedSession(credentials)

def init_resource(self):
return GoogleCloudResourceDetector().detect()

def init_log_exporter(self, log_exporter: Type[LogExporter]) -> LogExporter:
return self._init_exporter(self.send_logs_to_gcp, log_exporter)

def init_metric_exporter(
self,
metric_exporter: Type[MetricExporter],
) -> MetricExporter:
return self._init_exporter(self.send_metrics_to_gcp, metric_exporter)

def init_span_exporter(
self,
span_exporter: Type[SpanExporter],
) -> SpanExporter:
return self._init_exporter(self.send_spans_to_gcp, span_exporter)

def _init_exporter(
self,
customize_exporter: bool,
exporter_class: Type[Union[SpanExporter, MetricExporter, LogExporter]],
) -> Union[SpanExporter, MetricExporter, LogExporter]:
if not customize_exporter:
print("initializing class")
return exporter_class()
params = inspect.signature(exporter_class.__init__).parameters
if "credentials" in params and "grpc.ChannelCredentials" in str(
params["credentials"].annotation
):
return exporter_class(
credentials=self.channel_credentials,
endpoint="google.googleapis.com",
)
if "session" in params and str(
"requests.Session" in params["session"].annotation
):
return exporter_class(
session=self.session, endpoint="google.googleapis.com"
)
return exporter_class()


def send_metrics_and_traces_to_gcp() -> GoogleCloudConfiguratorCustomizer:
return GoogleCloudConfiguratorCustomizer(
send_spans_to_gcp=True, send_metrics_to_gcp=True
)


def send_logs_and_traces_to_gcp() -> GoogleCloudConfiguratorCustomizer:
return GoogleCloudConfiguratorCustomizer(
send_logs_to_gcp=True, send_spans_to_gcp=True
)


def send_logs_and_metrics_to_gcp() -> GoogleCloudConfiguratorCustomizer:
return GoogleCloudConfiguratorCustomizer(
send_logs_to_gcp=True, send_metrics_to_gcp=True
)


def send_only_traces_to_gcp() -> GoogleCloudConfiguratorCustomizer:
return GoogleCloudConfiguratorCustomizer(
send_spans_to_gcp=True,
)


def send_only_metrics_to_gcp() -> GoogleCloudConfiguratorCustomizer:
return GoogleCloudConfiguratorCustomizer(
send_metrics_to_gcp=True,
)


def send_only_logs_to_gcp() -> GoogleCloudConfiguratorCustomizer:
return GoogleCloudConfiguratorCustomizer(
send_logs_to_gcp=True,
)


def send_all_telemetry_to_gcp() -> GoogleCloudConfiguratorCustomizer:
return GoogleCloudConfiguratorCustomizer(
send_spans_to_gcp=True,
send_metrics_to_gcp=True,
send_logs_to_gcp=True,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright 2025 The OpenTelemetry Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

__version__ = "1.9.0a0"