diff --git a/opentelemetry-customizer/MANIFEST.in b/opentelemetry-customizer/MANIFEST.in new file mode 100644 index 00000000..61cc6926 --- /dev/null +++ b/opentelemetry-customizer/MANIFEST.in @@ -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 diff --git a/opentelemetry-customizer/README.rst b/opentelemetry-customizer/README.rst new file mode 100644 index 00000000..e69de29b diff --git a/opentelemetry-customizer/setup.cfg b/opentelemetry-customizer/setup.cfg new file mode 100644 index 00000000..c8e7885f --- /dev/null +++ b/opentelemetry-customizer/setup.cfg @@ -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 = opentelemetry-pypi@google.com +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 diff --git a/opentelemetry-customizer/setup.py b/opentelemetry-customizer/setup.py new file mode 100644 index 00000000..202880f5 --- /dev/null +++ b/opentelemetry-customizer/setup.py @@ -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"]}, +) diff --git a/opentelemetry-customizer/src/opentelemetry/customizer/__init__.py b/opentelemetry-customizer/src/opentelemetry/customizer/__init__.py new file mode 100644 index 00000000..dc0310c3 --- /dev/null +++ b/opentelemetry-customizer/src/opentelemetry/customizer/__init__.py @@ -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, + ) diff --git a/opentelemetry-customizer/src/opentelemetry/customizer/version.py b/opentelemetry-customizer/src/opentelemetry/customizer/version.py new file mode 100644 index 00000000..79b0360c --- /dev/null +++ b/opentelemetry-customizer/src/opentelemetry/customizer/version.py @@ -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"