Library / SDK
open-telemetry/opentelemetry-cpp avatar
open-telemetry/opentelemetry-cpp

opentelemetry-cpp's CI matrix never tests a single operating system with both build systems, and its repository description stops mid-sentence

The OpenTelemetry C++ Client. To use it with Bazel, add the following to your MODULE.bazel file: For the latest version, see BCR: opentelemetry-cpp.

1,396 stars663 forksC++Apache-2.0

At a glance

What is it?
opentelemetry-cpp is the OpenTelemetry client for C++, shipping under Apache-2.0 with both CMake and Bazel build systems, four supported language standards, and a component tree that includes an older-tracing compatibility shim. It is a mature, carefully governed project: two months between releases, a public roster of maintainers with their employers, and licence and security scanning badges. The build matrix is where the interesting gap is.
Who is it for?
opentelemetry-cpp is worth using if you are instrumenting a C++ service and want to emit the three signals to a collector without hand-rolling the SDK, and the maturity signals here are real: a two-month release cadence, a spec compliance position stated per signal rather than claimed in aggregate, and a public record of who maintains it and where they work. Two things to check before you rely on it.
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 C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 13, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • open-telemetry/opentelemetry-cpp1,396 ★ · +60
Star history
Repository2026-08-042026-11-13
open-telemetry/opentelemetry-cpp1.3k1.4k

60 Stars in the last 101 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

No operating system in the matrix is tested with both build systems

The platform table has six rows and two build types, and reading it across rather than down reveals the gap. One Linux release is built with CMake only, and a newer Linux release with CMake and Bazel. One macOS release is built with CMake only, and a different, newer macOS release with Bazel only. One Windows Server release is built with CMake and Bazel, and a newer one with CMake only. So exactly three of the six rows exercise both build systems, and they are the three newest of their respective families, while the older sibling of each family gets only one build type. The consequence is precise. A macOS user building with CMake is tested on the older macOS and a macOS user building with Bazel is tested on the newer one, so a macOS build failure that only reproduces on the newer release will only appear for people using Bazel. The same shape holds on both Linux and Windows. It is a reasonable trade for matrix budget, and it is the kind of decision that is invisible until you hit it, because the table looks complete at a glance and the gap is in the cells rather than the rows.

Four language standards are supported, with the exceptions written per component

The stated support covers four published C++ standards, from the 2014 revision through the 2017, 2020, and 2024 revisions, which in practice means anything from the older standard through the newest one the toolchains in use can handle. The phrasing is careful in a way that matters: the code shipped generally supports these versions, and any exceptions are noted in the individual readmes. So the version matrix is not one table, it is a default plus a set of per-component exceptions scattered across the component tree, and the tree here is not small. It has separate directories for the API, the SDK, exporters, resource detectors, an extension area, a test helper, build scripts, CMake files, and a third-party area. A component that has dropped support for the oldest standard, or that needs a newer one for a feature, will say so in its own readme and nowhere else. One explicit exclusion is stated up front and is worth knowing before you plan around it: supporting the C programming language is not a goal of the project. For a telemetry library that is often the first request from a C codebase, that is a hard no rather than a maybe.

The Bazel snippet is fenced as Python and pins a placeholder version

The three-line snippet in the readme that shows how to consume the project through Bazel has two small errors in it, and both are the kind that survive review because the snippet is short. First, the code fence is tagged with a language that is not the language of the content. Bazel's module syntax is not Python, and the content it contains is a module dependency declaration:

python
bazel_dep(name = "opentelemetry-cpp", version = "x.y.z")

So the tag misleads anyone who copies it into an editor expecting Python tooling and gets nothing. Second, the version argument is a literal placeholder of three groups of letters rather than a number, and the line above it tells you to go and look up the current version in a central registry. That indirection is the right call for a registry-managed module, since the registry is the source of truth for what has been published. But combined with the fence, the snippet is a step where two of three details are wrong and the third is deferred, which is exactly the shape of thing that produces a confusing first failure. The alternative would have been to quote one concrete version and say it may be stale.

Stability is claimed per signal and the compliance detail lives in another repository

The project status section is three lines and each of them matters. It states the client is stable across all three signals, meaning logs, metrics, and traces, and then immediately points at a compliance matrix in the specification repository to understand which portions of the specification have actually been implemented here. That is the right structure, because a single stable label tells you nothing and a matrix tells you everything, but it has a consequence: the authoritative statement of what this client implements lives in a different repository on a different branch. That document can change without this repository changing, and nothing in the readme pins a version of it. So the compatibility claim is real but external, and a team that needs to reason about a specific specification clause is reading another project's file. The three-signal framing is also the honest way to state it, since it is common for one signal in a client to be less complete than the other two, and a single aggregate status would hide exactly that. Here all three are claimed equally, which is the easier claim to make and the one this project makes.

A shim for the older tracing API and a file whose name is DEPRECATED

Two things in the tree describe the project's own history. There is a directory named for the previous generation of the tracing API, which is a compatibility layer rather than a feature: it lets code written against the older interface keep working while the native interface is what new code uses. That directory's presence tells you the project has been through an API consolidation, and anyone arriving with existing instrumentation has a migration question that this repository answers by shipping the bridge. The second item is a file at the root whose entire purpose is to be a deprecation list. That is an unusual thing to keep as a top-level document, and keeping it is a choice: deprecations are usually buried in a changelog and lost by the time somebody needs them, whereas a file named for the concept is findable by anyone auditing their dependency. Both artefacts point the same way, which is a project that treats its own API transitions as an ongoing obligation rather than a past event.

The readme carries a public roster with employers and prior roles

The governance section is longer than the installation section, and it is unusually specific. Four maintainers are named, one of them with a company affiliation. Two approvers are named without affiliations. Then there are nine people listed as emeritus, each labelled with the role they held, so the list distinguishes people who maintained, people who approved changes, and people who triaged issues. That is a public record of how the work was actually distributed, and for a project that has existed through at least one major API transition it doubles as a history. Two affiliations are named in total, which is a small number and suggests a project whose maintainers come mostly from independent backgrounds with a couple of corporate stewards. The same section documents the mechanics: a weekly meeting that alternates between two days and times in Pacific time, notes kept in a public document rather than a private wiki, edit access requested through a named chat channel, and an explicit invitation to anyone including newcomers and the merely curious. It is the kind of governance write-up that reduces the cost of a first contribution.

Twenty-three example directories, and one of them is a Windows-only tracing path

The examples directory is large and, unusually for this kind of library, organised by concern rather than by signal. There are separate directories for the two simplest cases and then directories for each transport and each extension point: a batch example, a configuration example, a custom HTTP client, an environment carrier, a plugin loader, a multi-processor setup, a logger configurator, a tracer configurator, a multi-threaded example, an explicit parent context example, and one each for the OTLP protocol, plain HTTP, gRPC, Prometheus, and Zipkin. Reading that list tells you what the extension points actually are, which is more useful than a feature list would be. Two entries deserve a note. The custom HTTP client example exists because the SDK lets you replace its HTTP stack, which is a compatibility escape hatch for environments the default client does not work in. And the directory named for Event Tracing for Windows threads is the only example that is inherently platform-specific, because thread-level tracing on Windows goes through a facility that has no equivalent elsewhere; it is also the reason the Windows build rows in the matrix matter more than the count suggests.

The release cadence is regular and the schedule section is a link to a tracker

Three recent tags are visible and the spacing is metronomic: one in May, one in July, one in September, roughly two months apart, all in the same minor stream with patch-level increments. That regularity is the strongest maintenance signal in the repository, and it is more informative than any badge. What backs it up is visible in the tooling: a dedicated release document, a versioning document, a configuration file for automated version bumping, and a configuration for a service that comments on changes. The dependency hygiene is configured too, with an include-what-you-use configuration file and clang tidy, so the include graph is enforced rather than reviewed. The schedule section itself, though, is a punt, and honestly labelled as one. It links to the release notes for what has shipped and to the project milestones for what is coming, then says the dates and features described in issues and milestones are estimates and subject to change. There is no stated support window anywhere in the readme. One last detail: the repository's own description, which is what appears in every link to the project, is a truncated instruction that begins by telling you to add something to a build file and stops before finishing the sentence.

Editorial conclusion

opentelemetry-cpp is worth using if you are instrumenting a C++ service and want to emit the three signals to a collector without hand-rolling the SDK, and the maturity signals here are real: a two-month release cadence, a spec compliance position stated per signal rather than claimed in aggregate, and a public record of who maintains it and where they work. Two things to check before you rely on it. Which build system and operating system you are on, because the matrix tests each build system on different operating systems rather than both on the same one, so a Bazel build on one macOS release and a CMake build on another is the configuration the project actually exercises. And which language standard each component supports, because the stated range spans four standards and the exceptions are recorded in individual per-component readmes rather than in one table. If you need C rather than C++, supporting it is explicitly not a goal of this project and you will be on your own.

Frequently asked questions

Which platforms and build systems does opentelemetry-cpp support?

Continuous integration builds six platform rows with CMake, Bazel, or both, covering two Ubuntu releases, two macOS releases on arm64, and two Windows Server releases. The gap is that no single operating system is tested with both build systems on the same release: the two rows that do carry both are the newer release of each family.

Which C++ standards can I use with opentelemetry-cpp?

The shipped code generally supports the 2014, 2017, 2020, and 2024 revisions of the language standard, and exceptions are noted in the individual component readmes rather than in one table. Supporting the C programming language is explicitly not a goal of the project.

Is the OpenTelemetry C++ client stable?

The project states it is stable across all three signals, meaning logs, metrics, and traces, and points to a compliance matrix in the specification repository for which portions are actually implemented. That matrix lives in another project, so the detailed compatibility position is maintained outside this repository.

How do I add opentelemetry-cpp to a Bazel build?

It is published in the Bazel central registry, and you add a dependency declaration for the module with a version in your module file. The snippet in the readme uses a placeholder version and tells you to look up the current one in the registry, and its code fence is tagged with a language that is not the one the syntax belongs to.

What does the opentracing shim directory in opentelemetry-cpp do?

It is a compatibility layer for the previous generation of the tracing API, so code written against that older interface keeps working while new code uses the native one. Its presence tells you the project went through an API consolidation and expects existing instrumentation to have a migration question.

How often does opentelemetry-cpp release?

Roughly every two months, judging by three consecutive tags in May, July, and September of this year, all patch-level increments in the same minor stream. The repository carries a release document, a versioning document, and configuration for automated version bumping and change commenting, but the schedule section states no policy and points at the project milestones while noting their dates are estimates.

Official sources

  1. Official documentation
  2. Official README
  3. Project repository
  4. Release notes
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/open-telemetry-opentelemetry-cpp.svg)](https://hysenlabs.com/projects/open-telemetry-opentelemetry-cpp)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/open-telemetry-opentelemetry-cpp.svg)](https://hysenlabs.com/projects/open-telemetry-opentelemetry-cpp)

Was this useful?