Skip to content

Remove packaging as a runtime dependency of opentelemetry-instrumentation #4882

Description

@ocelotl

Remove packaging as a runtime dependency of opentelemetry-instrumentation

Summary

opentelemetry-instrumentation declares packaging
(packaging >= 18.0) as a runtime dependency. It is used only for two small,
well-defined tasks — comparing PEP 440 version strings and parsing PEP 508
requirement specifiers — both of which can be satisfied by a tiny internal
implementation, letting us drop the external dependency.

This issue is scoped to the core opentelemetry-instrumentation package. The
same removal for the four instrumentations that also depend on packaging is
tracked separately and depends on this one (they will reuse the internal
implementation added here):

Motivation: the auto-instrumentation injector

The main driver is the OpenTelemetry auto-instrumentation injector (the Python
auto-instrumentation shipped by the OpenTelemetry Operator). The injector bundles
the instrumentation packages and all of their runtime dependencies into an
init-container image, copies that directory into a volume shared with the target
application's container, and prepends it to the application's PYTHONPATH.

As a result, every runtime dependency is injected into the user's application
process
, alongside the application's own dependencies:

  • Version conflicts / shadowing. packaging is an extremely common library
    that many applications already import. Injecting our copy onto PYTHONPATH
    risks shadowing the version the application expects, or being shadowed — the
    class of hard-to-debug failures the injector is designed to avoid.
  • Payload size. Everything shipped must be baked into the init-container
    image and copied at pod startup.
  • Blast radius. Fewer third-party packages forced into a customer's runtime
    means a smaller surface for incompatibilities.

Because packaging is used only for a narrow, stable subset of functionality,
the cost of carrying it as an injected runtime dependency outweighs the cost of a
small internal implementation.

Where it is used in opentelemetry-instrumentation

  • pyproject.toml: packaging >= 18.0 in dependencies.

PEP 440 version comparison (packaging.version)

  • src/opentelemetry/instrumentation/_semconv.py:745 — compares semantic
    convention schema version strings (Version(a) > Version(b)) to select the
    highest schema URL across signal types.

PEP 508 requirement parsing / PEP 440 specifier matching (packaging.requirements, and transitively packaging.specifiers / packaging.markers)

  • src/opentelemetry/instrumentation/dependencies.py:9 — the dependency-conflict
    machinery (get_dist_dependency_conflicts, get_dependency_conflicts) parses
    each instrumentation's declared instruments / instruments-any dependency
    strings into Requirement objects, evaluates their environment markers
    (extra == "instruments"), and checks the installed distribution version
    against the requirement's specifier (req.specifier.contains(dist_version)).
  • src/opentelemetry/instrumentation/bootstrap.py:90Requirement(req) when
    computing which instrumentation packages to install/print.

Proposed resolution

Add a small internal implementation under
opentelemetry.instrumentation._packaging covering just the required subset:

  • PEP 440 Version parsing, normalization and ordering.
  • PEP 508 Requirement parsing plus PEP 440 specifier containment and marker
    evaluation.

Point _semconv.py, dependencies.py and bootstrap.py at it, and remove
packaging from opentelemetry-instrumentation's dependencies. The internal
implementation must match packaging's behavior on the inputs these sites see,
verified against packaging across a broad version/specifier corpus.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions