opentelemetry-python-contrib: per-library instrumentation for Python, still on beta
OpenTelemetry instrumentation for Python modules
At a glance
- What is it?
- opentelemetry-python-contrib is the Apache-2.0 home of the OpenTelemetry auto-instrumentation libraries for Python, one installable package per instrumented library, built to OTEP 0001. The judgement is that the repository's real value is its dependency discipline and its instrumentation catalogue, and that its own warning against production use is the first thing to read before you adopt it.
- Who is it for?
- opentelemetry-python-contrib fits a Python team that has already adopted the OpenTelemetry API and SDK and wants span coverage for a specific third-party library without writing the instrumentation by hand, and that is prepared to track a monthly release train.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One package per library, with a deliberate dependency rule
opentelemetry-python-contrib is described as the Python auto-instrumentation libraries for OpenTelemetry, per OTEP 0001, which is the proposal for telemetry without manual instrumentation.
The repository holds installable packages for each instrumented library, and the dependency rule is stated as a design principle rather than a convention. Libraries that produce telemetry data should only depend on `opentelemetry-api`, and defer the choice of the SDK to the application developer. Applications may depend on `opentelemetry-sdk` or another package that implements the API.
That split is the whole architectural idea. A library that instruments itself must not drag in a particular SDK, an exporter, or a batching configuration, because the application is the thing that knows which of those it wants. The instrumentation package calls the API, and whatever the application configured behind that API does the work. It is the same reason you should not make a web framework depend on a database driver.
The practical effect is that installing an instrumentation package adds a small, well-behaved dependency to a library, and the exporter and processor configuration stays entirely on the application side.
There is a second rule that is easy to miss and worth stating separately. Unless explicitly stated otherwise, any instrumentation here for a particular library is not developed or maintained by the authors of such library. The instrumentation for aiohttp is maintained by the OpenTelemetry community, not by the aiohttp maintainers, and that has consequences for who you file a bug against and whether the upstream project has any obligation to keep the instrumentation working when they change their API.
Installing one instrumentation without touching the repository
The installation model is deliberately granular, and it is the main reason the repository is laid out as it is.
The `instrumentation/` directory includes the OpenTelemetry instrumentation packages, which can be installed separately as:
pip install opentelemetry-instrumentation-{integration}So the integration name is substituted, and you install only the ones whose libraries you actually use. The development version of the same package comes from an editable install of the subdirectory:
pip install -e ./instrumentation/opentelemetry-instrumentation-{integration}That second form is for working on the instrumentation itself, which is why the repository keeps each package in its own directory with its own metadata. A monorepo where each instrumentation is an independently versioned, independently installable distribution is a different proposition from a monorepo where one `pip install` pulls in thirty packages you do not use.
The breadth of the catalogue is visible in the development dependency list in `pyproject.toml`, which enumerates the instrumented libraries. The list includes aiohttp client and server, aio-pika, aiokafka, aiopg, asyncio, asyncpg, AWS Lambda, boto3 SQS, botocore, cassandra, celery, click, confluent-kafka, dbapi, django, falcon, fastapi, flask, gRPC, httpx, jinja2, kafka-python, and the list continues beyond what is shown. The mix is telling: web frameworks, HTTP clients, message brokers, databases, task queues, cloud SDKs and templating engines, which is the set of libraries a Python web service actually touches.
The `pyproject.toml` also shows the project requires Python 3.10 or newer, and that the root package is explicitly marked as not to be published, with a version of `0.0.0` and a comment saying it is not used.
The beta warning is in the installation section, not buried
There is a note in the installation section that deserves to be read as the headline rather than the footnote.
Please note that these libraries are currently in beta, and shouldn't generally be used in production environments.
That is a strong statement from a project that most Python teams will treat as their default path to OpenTelemetry coverage. It tells you the maintainers consider the instrumentation surface unstable, and that a production deployment should be a deliberate decision rather than the path of least resistance.
The context around it explains how a package earns its way out of that state. The releasing section describes a monthly cadence, with maintainers releasing new versions of the packages in `opentelemetry-python-contrib` on a monthly cadence, and the releases page carrying all previous releases. So the cadence is regular and the project is not in a state of neglect.
The path to `1.0` is a per-package decision, and the mechanism is CODEOWNERS. Contributions that enhance OTel for Python are welcome to be hosted upstream for the benefit of group collaboration, and maintainers will look for things like good documentation, good unit tests, and in general their own confidence when deciding to release a package with the stability guarantees that are implied with a `1.0` release. Members of the community are encouraged to commit to becoming a CODEOWNER for packages in `-contrib` that they feel experienced enough to maintain.
So a package becomes stable when someone who understands it takes responsibility for it, and the checklist for that is documentation, unit tests and the maintainers' confidence. To release a package as `1.0` stable it should have a CODEOWNER, and to become one you submit an issue and explain why.
That is a more honest model of stability than a global version number, and it also tells you where to look when an instrumentation misbehaves: the CODEOWNERS file, which tells you who is accountable for that specific package.
Semantic convention status is tracked per instrumentation
The index in the README includes an entry for Semantic Convention status of instrumentations, and that points at a real problem in the OpenTelemetry ecosystem rather than a documentation nicety.
OpenTelemetry's semantic conventions are the naming scheme that turns raw spans into something a backend can aggregate. The convention for a database span, for a messaging span, for an HTTP span, is a set of attribute names and their expected values. Those conventions evolve, and a span emitted by an instrumentation that follows last year's convention may not join the same dashboards as one that follows the current one.
The result is a dashboard with gaps. A trace has spans, but the spans do not group by the attribute you are filtering on, and the query returns half the data with no error to tell you why. This is invisible when you first adopt telemetry and painful when you try to build a latency panel across a fleet of services.
Tracking convention status per instrumentation, rather than assuming every package follows the current conventions, is what lets an adopter answer the question that matters before they commit: will the spans from this package line up with the ones from the package I already have.
The README's table of contents also links the instrumentations index, and the API documentation is hosted on Read the Docs with a per-instrumentation reference, so the catalogue is browsable both as a list and as documentation.
The wider repository layout supports the same idea of many independent pieces. Beyond `instrumentation/` there is `exporter/`, `processor/`, `propagator/`, `resource/`, `sdk-extension/`, `opamp/`, `util/`, `typings/`, `instrumentation-genai/` and `opentelemetry-contrib-instrumentations/`, which is the aggregate package that installs a set of them together. There is also `opentelemetry-distro/` and `opentelemetry-instrumentation/`, the two packages that provide the default wiring rather than a specific library integration.
A monorepo with a lot of moving parts in the tooling
The repository is large and the tooling around it is correspondingly substantial, which is worth knowing before you clone it.
There is a `tox.ini` and a `tox-uv.toml` for running the test matrix across Python versions and dependency sets, a `pytest.ini`, a `.coveragerc`, a `test-constraints.txt` that pins the versions the tests run against, and separate requirement files for development, docs, the code generator, the OpAMP client and the readthedocs build. There is a `.pre-commit-config.yaml`, a `.pylintrc`, a `.codespellrc`, an `.rstcheck.cfg` for the documentation prose, and a `.readthedocs.yml`.
The code generation pieces deserve a note. There is a `gen-requirements.txt` for the generator itself and an `instrumentation-genai/` directory, which is the instrumentation generator rather than a set of instrumentations. That distinction matters because the generated instrumentation packages are checked in, and a change to the generator can produce a change across many packages at once.
The `.changelog/` directory holds the per-package changelog fragments, and `CHANGELOG.md` at the root, `RELEASING.md`, and `eachdist.ini` for the per-package distribution builds are all in place. There is a `uv.lock` at the root and a `pyproject.toml` that is used for local development and not to be published, as its own comment says.
What the tooling implies is that this repository is not one project but a release process for many. Every package has its own version, its own changelog, its own release decision and its own CODEOWNER, and the monthly cadence is what keeps a hundred separate distributions in step. That is a different maintenance model from a normal library, and it is the reason the project can offer per-package stability while the repository as a whole stays in beta.
Where the beta status actually bites
Three concrete consequences follow from the beta status, and they are worth separating from the general caution.
The first is the version floor. One recent listed release is v0.66b1, tagged with the note that it is version 1.45.1/0.66b1, so the core API and SDK in that release are at 1.45.1 while the contrib packages sit at 0.66b1. A beta suffix in a pre-1.0 version means the package is not covered by semantic versioning's compatibility guarantee, so a minor bump may carry breaking changes to the instrumentation's own API. If you pin an instrumentation, you pin it exactly, and you read its changelog when you move.
The second is that the instrumentation is not covered by the upstream library's own maintenance. The rule is explicit: unless explicitly stated otherwise, any instrumentation here for a particular library is not developed or maintained by the authors of such library. When the upstream library changes its internals, the instrumentation can break, and there is no upstream commitment to fix it or to file the issue upstream. The people who maintain a given package are the CODEOWNERS, which is the community members who volunteered for it.
The third is the release cadence itself. A monthly cadence across a hundred packages means you will be looking at a steady stream of new versions, and a team that wants stability will end up pinning rather than upgrading, which reintroduces the problem the monthly release is meant to solve.
None of this makes the project a poor choice. It makes it a choice with a specific shape: the instrumentation surface is broad and maintained by the community, the version numbers move fast, and the production suitability is explicitly not guaranteed. The alternative of writing the instrumentation yourself is a real option, and for a critical library in your request path it is sometimes the right one, because then you own the compatibility with the library's next release.
Editorial conclusion
opentelemetry-python-contrib fits a Python team that has already adopted the OpenTelemetry API and SDK and wants span coverage for a specific third-party library without writing the instrumentation by hand, and that is prepared to track a monthly release train. It does not fit a team that needs a stable, supported production dependency today, because the documentation states the libraries are currently in beta and shouldn't generally be used in production environments, and it does not fit a team that has not yet chosen an OpenTelemetry SDK at all. Verify first that the instrumentation for your library exists and that the package names match the ones in the `instrumentation/` directory, that the semantic conventions the instrumentation emits are the ones your backend expects, since the project tracks a per-instrumentation convention status, and that the API and SDK versions you pin are compatible with the instrumentation release you install.
Frequently asked questions
How do I install a single OpenTelemetry instrumentation for Python?
Install the package for your library from PyPI with `pip install opentelemetry-instrumentation-{integration}`. To work on the instrumentation itself, clone or fork the repository and do an editable install of the subdirectory with `pip install -e ./instrumentation/opentelemetry-instrumentation-{integration}`.
Are the opentelemetry-python-contrib libraries safe for production?
The documentation states plainly that these libraries are currently in beta and shouldn't generally be used in production environments. A package earns `1.0` stable status individually, by having a CODEOWNER, good documentation, good unit tests and the maintainers' confidence.
Why does an instrumentation package not depend on the OpenTelemetry SDK?
Because libraries that produce telemetry data should only depend on `opentelemetry-api` and defer the choice of the SDK to the application developer. Applications may depend on `opentelemetry-sdk` or another package that implements the API, so the instrumentation never dictates the exporter or the configuration.
How often are new versions of the contrib packages released?
Maintainers release new versions of the packages on a monthly cadence, and the releases page carries all previous releases. A recent listed release is v0.66b1, which corresponds to version 1.45.1 of the core API and SDK.
Who maintains the instrumentation for a library like aiohttp or celery?
Not the authors of the instrumented library. The documentation states that unless explicitly stated otherwise, any instrumentation here for a particular library is not developed or maintained by the authors of such library. Maintenance comes from community CODEOWNERS who volunteer for the package they know.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/open-telemetry-opentelemetry-python-contrib)