From ff39f37a5fb9eeca3482515a45ede461df8f8154 Mon Sep 17 00:00:00 2001 From: Alex Boten <223565+codeboten@users.noreply.github.com> Date: Mon, 8 Apr 2024 15:30:55 -0700 Subject: [PATCH] split distro package into two modules The first module `honeycomb-opentelemetry` imports the second module `honeycomb-opentelemetry-components`. The original package `honeycomb-opentelemetry` will continue to work as it did before. For users that want to utilize components without using the auto configuration provided by the distro, they can import the components package and configure things manually. Signed-off-by: Alex Boten <223565+codeboten@users.noreply.github.com> --- examples/distroless/Dockerfile | 28 ++++++++++++ examples/distroless/README.md | 44 ++++++++++++++++++ examples/distroless/app.py | 45 +++++++++++++++++++ examples/distroless/pyproject.toml | 15 +++++++ .../README.md | 41 +++++++++++++++++ .../pyproject.toml | 39 ++++++++++++++++ .../opentelemetry/components/__init__.py | 1 + .../opentelemetry/components}/baggage.py | 0 .../components}/local_exporter.py | 2 +- .../opentelemetry/components}/metrics.py | 2 +- .../opentelemetry/components}/options.py | 0 .../opentelemetry/components}/resource.py | 4 +- .../opentelemetry/components}/sampler.py | 2 +- .../opentelemetry/components}/trace.py | 8 ++-- .../opentelemetry/components}/version.py | 0 src/honeycomb-opentelemetry/README.md | 41 +++++++++++++++++ src/honeycomb-opentelemetry/pyproject.toml | 43 ++++++++++++++++++ .../src}/honeycomb/opentelemetry/distro.py | 8 ++-- src/honeycomb/opentelemetry/__init__.py | 2 - 19 files changed, 310 insertions(+), 15 deletions(-) create mode 100644 examples/distroless/Dockerfile create mode 100644 examples/distroless/README.md create mode 100644 examples/distroless/app.py create mode 100644 examples/distroless/pyproject.toml create mode 100644 src/honeycomb-opentelemetry-components/README.md create mode 100644 src/honeycomb-opentelemetry-components/pyproject.toml create mode 100644 src/honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components/__init__.py rename src/{honeycomb/opentelemetry => honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components}/baggage.py (100%) rename src/{honeycomb/opentelemetry => honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components}/local_exporter.py (97%) rename src/{honeycomb/opentelemetry => honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components}/metrics.py (95%) rename src/{honeycomb/opentelemetry => honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components}/options.py (100%) rename src/{honeycomb/opentelemetry => honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components}/resource.py (83%) rename src/{honeycomb/opentelemetry => honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components}/sampler.py (98%) rename src/{honeycomb/opentelemetry => honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components}/trace.py (86%) rename src/{honeycomb/opentelemetry => honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components}/version.py (100%) create mode 100644 src/honeycomb-opentelemetry/README.md create mode 100644 src/honeycomb-opentelemetry/pyproject.toml rename src/{ => honeycomb-opentelemetry/src}/honeycomb/opentelemetry/distro.py (89%) delete mode 100644 src/honeycomb/opentelemetry/__init__.py diff --git a/examples/distroless/Dockerfile b/examples/distroless/Dockerfile new file mode 100644 index 0000000..6a5d459 --- /dev/null +++ b/examples/distroless/Dockerfile @@ -0,0 +1,28 @@ +# to be run with docker-compose in smoke-tests directory +FROM python:3.10-slim + +WORKDIR /app + +ENV PYTHONFAULTHANDLER=1 \ + PYTHONUNBUFFERED=1 \ + PYTHONHASHSEED=random \ + PIP_NO_CACHE_DIR=off \ + PIP_DISABLE_PIP_VERSION_CHECK=on \ + PIP_DEFAULT_TIMEOUT=100 \ + POETRY_VERSION=1.3.2 + +RUN pip install "poetry==$POETRY_VERSION" +# This image is single purpose, so we won't need to compartmentalize Py deps in virtualenvs. +RUN poetry config virtualenvs.create false + +COPY README.md pyproject.toml poetry.lock ./ +COPY src/ ./src/ +RUN poetry install + +# Copy the examples into the image and install deps. +COPY examples/ ./examples/ +RUN cd ./examples/distroless && poetry install + +# From this point forward, we're operating on the example app. +WORKDIR /app/examples/distroless +CMD ["python", "app.py"] \ No newline at end of file diff --git a/examples/distroless/README.md b/examples/distroless/README.md new file mode 100644 index 0000000..4ecb830 --- /dev/null +++ b/examples/distroless/README.md @@ -0,0 +1,44 @@ +# hello-world + +This Python app returns "Hello World". This app uses the standard OpenTelemetry library to set up OpenTelemetry to export data to Honeycomb through configuration options set in the app's code. It is also possible to set configuration options through the `opentelemetry_instrument` command (see the [flask app](../hello-world-flask/README.md) as an example). + +## Prerequisites + +You'll also need [Poetry](https://python-poetry.org/) installed to run the example. Poetry automatically creates a virtual environment to run the example in so you don't need to manage one yourself. + +## Running the example + +Install the dependencies: + +```bash +poetry install +``` + +Run the application: + +```bash +poetry run python3 app.py +``` + +The app will output `Hello World` and then exit. + +This app will send traces to local console with the configured `debug=True`. + +To enable local visualizations: + +```bash +export HONEYCOMB_ENABLE_LOCAL_VISUALIZATIONS=1 +poetry run python3 app.py +``` + +To send to Honeycomb, set the API Key: + +```bash +export OTEL_SERVICE_NAME=distroless-example +export OTEL_EXPORTER_OTLP_HEADERS="x-honeycomb-team=XXXX" +export OTEL_EXPORTER_OTLP_ENDPOINT=https://api.honeycomb.io:443 +poetry run python3 app.py +``` + +You can configure exporter protocol with this flag: +`OTEL_EXPORTER_OTLP_PROTOCOL=grpc` or `OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf` diff --git a/examples/distroless/app.py b/examples/distroless/app.py new file mode 100644 index 0000000..6783771 --- /dev/null +++ b/examples/distroless/app.py @@ -0,0 +1,45 @@ +import os +from opentelemetry import trace, baggage, metrics +from opentelemetry.trace import set_tracer_provider +from opentelemetry.sdk.trace import TracerProvider +from opentelemetry.sdk.trace.export import ( + SimpleSpanProcessor +) +from opentelemetry.context import attach, detach +from honeycomb.opentelemetry.components.options import HoneycombOptions +from honeycomb.opentelemetry.components.resource import create_resource +from honeycomb.opentelemetry.components.local_exporter import LocalTraceLinkSpanExporter +from honeycomb.opentelemetry.components.sampler import configure_sampler +from honeycomb.opentelemetry.components.resource import create_resource +from honeycomb.opentelemetry.components.trace import create_tracer_provider +from honeycomb.opentelemetry.components.metrics import create_meter_provider + + +def configure_honeycomb_components(): + opts = HoneycombOptions() + resource = create_resource(opts) + set_tracer_provider(create_tracer_provider(opts, resource)) + +configure_honeycomb_components() + +meter = metrics.get_meter("hello_world_meter") +sheep = meter.create_counter('sheep') + +tracer = trace.get_tracer("hello_world_tracer") + +def hello_world(): + token = attach(baggage.set_baggage( + "baggy", "important_value")) + with tracer.start_as_current_span(name="hello"): + token_second = attach(baggage.set_baggage( + "for_the_children", "another_important_value")) + with tracer.start_as_current_span(name="world") as span: + span.set_attribute("message", "hello world!") + print("Hello World") + detach(token_second) + detach(token) + sheep.add(1, {'app.route': '/'}) + return "Hello World" + + +hello_world() diff --git a/examples/distroless/pyproject.toml b/examples/distroless/pyproject.toml new file mode 100644 index 0000000..8437f7e --- /dev/null +++ b/examples/distroless/pyproject.toml @@ -0,0 +1,15 @@ +[tool.poetry] +name = "distroless" +version = "0.1.0" +description = "" +authors = ["Honeycomb "] +readme = "README.md" + +[tool.poetry.dependencies] +python = "^3.10" +honeycomb-opentelemetry-components = {path = "../../src/honeycomb-opentelemetry-components", develop = true} +opentelemetry-api = "1.22.0" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/src/honeycomb-opentelemetry-components/README.md b/src/honeycomb-opentelemetry-components/README.md new file mode 100644 index 0000000..2e56912 --- /dev/null +++ b/src/honeycomb-opentelemetry-components/README.md @@ -0,0 +1,41 @@ +# Honeycomb OpenTelemetry Components for Python + +[![OSS Lifecycle](https://img.shields.io/osslifecycle/honeycombio/honeycomb-opentelemetry-python)](https://github.com/honeycombio/home/blob/main/honeycomb-oss-lifecycle-and-practices.md) +[![CircleCI](https://circleci.com/gh/honeycombio/honeycomb-opentelemetry-python.svg?style=shield)](https://circleci.com/gh/honeycombio/honeycomb-opentelemetry-python) +[![PyPi](https://img.shields.io/pypi/v/honeycomb-opentelemetry)](https://pypi.org/project/honeycomb-opentelemetry/) + +**STATUS: this library is BETA.** +You're welcome to try it, and let us know your feedback in the issues! + +This is Honeycomb's Distribution of OpenTelemetry for Python. +It makes getting started with OpenTelemetry and Honeycomb easier! + +Latest release built with: + +- [OpenTelemetry version 1.22.0/0.43b0](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.22.0) + +## Requirements + +- Python 3.7 or higher + +## Getting Started + +Honeycomb's Distribution of OpenTelemetry for Python allows you to streamline configuration and to instrument as quickly and easily as possible. + +- [Documentation](https://docs.honeycomb.io/getting-data-in/opentelemetry/python/) +- [Examples](/examples/) + - [Flask](/examples/hello-world-flask/) + - [Django](/examples/hello-world-django/) +- See [DEVELOPING.md](/DEVELOPING.md) for additional instructions for building and testing this project in development. + +## Why would I want to use this? + +- Streamlined configuration for sending data to Honeycomb! +- Easy interop with existing instrumentation with OpenTelemetry! +- Deterministic sampling! +- Multi-span attributes! +- Local visualizations! + +## License + +[Apache 2.0 License](./LICENSE). diff --git a/src/honeycomb-opentelemetry-components/pyproject.toml b/src/honeycomb-opentelemetry-components/pyproject.toml new file mode 100644 index 0000000..e5594de --- /dev/null +++ b/src/honeycomb-opentelemetry-components/pyproject.toml @@ -0,0 +1,39 @@ +[tool.poetry] +name = "honeycomb-opentelemetry-components" +version = "0.1.0b0" +description = "Honeycomb OpenTelemetry Components for Python" +authors = ["Honeycomb "] +readme = "README.md" +packages = [{include = "honeycomb", from = "src" }] +license = "Apache-2.0" +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "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", + "Typing :: Typed", +] + +[tool.poetry.dependencies] +python = "^3.7, >= 3.7.2" +opentelemetry-api = "^1.22.0" +opentelemetry-sdk = "^1.22.0" +opentelemetry-exporter-otlp = "^1.22.0" +opentelemetry-instrumentation = "~0.43b0" + +[tool.poetry.group.dev.dependencies] +coverage = ">=6.5,<8.0" +pytest = "^7.2.0" +pylint = "^2.16.0" +pycodestyle = "^2.10.0" +importlib-metadata = { version = ">=0.12", python = "<3.8" } +requests-mock = "^1.10.0" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/src/honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components/__init__.py b/src/honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components/__init__.py new file mode 100644 index 0000000..59014bf --- /dev/null +++ b/src/honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components/__init__.py @@ -0,0 +1 @@ +from honeycomb.opentelemetry.components.options import HoneycombOptions diff --git a/src/honeycomb/opentelemetry/baggage.py b/src/honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components/baggage.py similarity index 100% rename from src/honeycomb/opentelemetry/baggage.py rename to src/honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components/baggage.py diff --git a/src/honeycomb/opentelemetry/local_exporter.py b/src/honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components/local_exporter.py similarity index 97% rename from src/honeycomb/opentelemetry/local_exporter.py rename to src/honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components/local_exporter.py index 0aa60b4..d3b29b0 100644 --- a/src/honeycomb/opentelemetry/local_exporter.py +++ b/src/honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components/local_exporter.py @@ -5,7 +5,7 @@ from opentelemetry.sdk.trace import ReadableSpan from opentelemetry.sdk.trace.export import SpanExporter, SpanExportResult -from honeycomb.opentelemetry.options import HoneycombOptions, is_classic +from honeycomb.opentelemetry.components.options import HoneycombOptions, is_classic MISSING_API_OR_SERVICE_NAME_ERROR = "disabling local visualizations - " + \ "must have both service name and API key configured." diff --git a/src/honeycomb/opentelemetry/metrics.py b/src/honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components/metrics.py similarity index 95% rename from src/honeycomb/opentelemetry/metrics.py rename to src/honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components/metrics.py index 920bdb5..71ff3f9 100644 --- a/src/honeycomb/opentelemetry/metrics.py +++ b/src/honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components/metrics.py @@ -10,7 +10,7 @@ from opentelemetry.exporter.otlp.proto.http.metric_exporter import ( OTLPMetricExporter as HTTPMetricExporter ) -from honeycomb.opentelemetry.options import HoneycombOptions +from honeycomb.opentelemetry.components.options import HoneycombOptions def create_meter_provider(options: HoneycombOptions, resource: Resource): diff --git a/src/honeycomb/opentelemetry/options.py b/src/honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components/options.py similarity index 100% rename from src/honeycomb/opentelemetry/options.py rename to src/honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components/options.py diff --git a/src/honeycomb/opentelemetry/resource.py b/src/honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components/resource.py similarity index 83% rename from src/honeycomb/opentelemetry/resource.py rename to src/honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components/resource.py index 1815c76..38da5cd 100644 --- a/src/honeycomb/opentelemetry/resource.py +++ b/src/honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components/resource.py @@ -1,7 +1,7 @@ import platform from opentelemetry.sdk.resources import Resource -from honeycomb.opentelemetry.options import HoneycombOptions -from honeycomb.opentelemetry.version import __version__ +from honeycomb.opentelemetry.components.options import HoneycombOptions +from honeycomb.opentelemetry.components.version import __version__ def create_resource(options: HoneycombOptions): diff --git a/src/honeycomb/opentelemetry/sampler.py b/src/honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components/sampler.py similarity index 98% rename from src/honeycomb/opentelemetry/sampler.py rename to src/honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components/sampler.py index 1faaf5a..d9a4175 100644 --- a/src/honeycomb/opentelemetry/sampler.py +++ b/src/honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components/sampler.py @@ -14,7 +14,7 @@ from opentelemetry.util.types import Attributes from opentelemetry.context import Context -from honeycomb.opentelemetry.options import ( +from honeycomb.opentelemetry.components.options import ( DEFAULT_SAMPLE_RATE, HoneycombOptions ) diff --git a/src/honeycomb/opentelemetry/trace.py b/src/honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components/trace.py similarity index 86% rename from src/honeycomb/opentelemetry/trace.py rename to src/honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components/trace.py index d7ec6ed..1a93b32 100644 --- a/src/honeycomb/opentelemetry/trace.py +++ b/src/honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components/trace.py @@ -11,10 +11,10 @@ from opentelemetry.exporter.otlp.proto.http.trace_exporter import ( OTLPSpanExporter as HTTPSpanExporter ) -from honeycomb.opentelemetry.local_exporter import configure_local_exporter -from honeycomb.opentelemetry.options import HoneycombOptions -from honeycomb.opentelemetry.sampler import configure_sampler -from honeycomb.opentelemetry.baggage import BaggageSpanProcessor +from honeycomb.opentelemetry.components.local_exporter import configure_local_exporter +from honeycomb.opentelemetry.components.options import HoneycombOptions +from honeycomb.opentelemetry.components.sampler import configure_sampler +from honeycomb.opentelemetry.components.baggage import BaggageSpanProcessor def create_tracer_provider( diff --git a/src/honeycomb/opentelemetry/version.py b/src/honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components/version.py similarity index 100% rename from src/honeycomb/opentelemetry/version.py rename to src/honeycomb-opentelemetry-components/src/honeycomb/opentelemetry/components/version.py diff --git a/src/honeycomb-opentelemetry/README.md b/src/honeycomb-opentelemetry/README.md new file mode 100644 index 0000000..c16d3ea --- /dev/null +++ b/src/honeycomb-opentelemetry/README.md @@ -0,0 +1,41 @@ +# Honeycomb OpenTelemetry Distro for Python + +[![OSS Lifecycle](https://img.shields.io/osslifecycle/honeycombio/honeycomb-opentelemetry-python)](https://github.com/honeycombio/home/blob/main/honeycomb-oss-lifecycle-and-practices.md) +[![CircleCI](https://circleci.com/gh/honeycombio/honeycomb-opentelemetry-python.svg?style=shield)](https://circleci.com/gh/honeycombio/honeycomb-opentelemetry-python) +[![PyPi](https://img.shields.io/pypi/v/honeycomb-opentelemetry)](https://pypi.org/project/honeycomb-opentelemetry/) + +**STATUS: this library is BETA.** +You're welcome to try it, and let us know your feedback in the issues! + +This is Honeycomb's Distribution of OpenTelemetry for Python. +It makes getting started with OpenTelemetry and Honeycomb easier! + +Latest release built with: + +- [OpenTelemetry version 1.22.0/0.43b0](https://github.com/open-telemetry/opentelemetry-python/releases/tag/v1.22.0) + +## Requirements + +- Python 3.7 or higher + +## Getting Started + +Honeycomb's Distribution of OpenTelemetry for Python allows you to streamline configuration and to instrument as quickly and easily as possible. + +- [Documentation](https://docs.honeycomb.io/getting-data-in/opentelemetry/python/) +- [Examples](/examples/) + - [Flask](/examples/hello-world-flask/) + - [Django](/examples/hello-world-django/) +- See [DEVELOPING.md](/DEVELOPING.md) for additional instructions for building and testing this project in development. + +## Why would I want to use this? + +- Streamlined configuration for sending data to Honeycomb! +- Easy interop with existing instrumentation with OpenTelemetry! +- Deterministic sampling! +- Multi-span attributes! +- Local visualizations! + +## License + +[Apache 2.0 License](./LICENSE). diff --git a/src/honeycomb-opentelemetry/pyproject.toml b/src/honeycomb-opentelemetry/pyproject.toml new file mode 100644 index 0000000..0d46fc2 --- /dev/null +++ b/src/honeycomb-opentelemetry/pyproject.toml @@ -0,0 +1,43 @@ +[tool.poetry] +name = "honeycomb-opentelemetry" +version = "0.4.0b0" +description = "Honeycomb OpenTelemetry Distro for Python" +authors = ["Honeycomb "] +readme = "README.md" +packages = [{include = "honeycomb", from = "src" }] +license = "Apache-2.0" +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "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", + "Typing :: Typed", +] + +[tool.poetry.dependencies] +python = "^3.7, >= 3.7.2" +opentelemetry-api = "^1.22.0" +opentelemetry-sdk = "^1.22.0" +opentelemetry-exporter-otlp = "^1.22.0" +opentelemetry-instrumentation = "~0.43b0" +honeycomb-opentelemetry-components = "~0.1.0b0" + +[tool.poetry.group.dev.dependencies] +coverage = ">=6.5,<8.0" +pytest = "^7.2.0" +pylint = "^2.16.0" +pycodestyle = "^2.10.0" +importlib-metadata = { version = ">=0.12", python = "<3.8" } +requests-mock = "^1.10.0" + +[tool.poetry.plugins."opentelemetry_distro"] +distro = "honeycomb.opentelemetry.distro:HoneycombDistro" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/src/honeycomb/opentelemetry/distro.py b/src/honeycomb-opentelemetry/src/honeycomb/opentelemetry/distro.py similarity index 89% rename from src/honeycomb/opentelemetry/distro.py rename to src/honeycomb-opentelemetry/src/honeycomb/opentelemetry/distro.py index 32bbee8..ea30cea 100644 --- a/src/honeycomb/opentelemetry/distro.py +++ b/src/honeycomb-opentelemetry/src/honeycomb/opentelemetry/distro.py @@ -21,10 +21,10 @@ from opentelemetry.instrumentation.distro import BaseDistro from opentelemetry.metrics import set_meter_provider from opentelemetry.trace import set_tracer_provider -from honeycomb.opentelemetry.metrics import create_meter_provider -from honeycomb.opentelemetry.options import HoneycombOptions -from honeycomb.opentelemetry.resource import create_resource -from honeycomb.opentelemetry.trace import create_tracer_provider +from honeycomb.opentelemetry.components.metrics import create_meter_provider +from honeycomb.opentelemetry.components.options import HoneycombOptions +from honeycomb.opentelemetry.components.resource import create_resource +from honeycomb.opentelemetry.components.trace import create_tracer_provider _logger = getLogger(__name__) diff --git a/src/honeycomb/opentelemetry/__init__.py b/src/honeycomb/opentelemetry/__init__.py deleted file mode 100644 index a910c89..0000000 --- a/src/honeycomb/opentelemetry/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from honeycomb.opentelemetry.distro import configure_opentelemetry -from honeycomb.opentelemetry.options import HoneycombOptions