OpenTelemetry Go auto instrumentation: tracing Go services with eBPF, no code changes
OpenTelemetry Auto Instrumentation using eBPF
At a glance
- What is it?
- The OpenTelemetry Go auto instrumentation project injects OpenTelemetry tracing into Go binaries at runtime using eBPF, so a service gets spans without a single line of instrumentation code, at the cost of Linux, root privileges and a project that says it is work in progress.
- Who is it for?
- This project fits a team running Go services on Linux that wants distributed traces without editing the source of every service, and that accepts running an agent with elevated privileges next to the process.
- 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 last received commits 2 days ago.
- What is it written in?
- Mainly C, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 21, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Tracing without touching the source
The OpenTelemetry Go Automatic Instrumentation project provides OpenTelemetry tracing instrumentation for Go libraries using eBPF.
The mechanism is what makes it interesting. The project does not ask you to add a middleware, an import or a decorator to your service. Instead it attaches to the running process at the kernel level and reconstructs the spans from what the binary actually does. For an organisation with forty Go services and a mix of libraries, that difference is the whole value proposition, because instrumenting by hand is a per-service project and this is a per-host one.
The module path is go.opentelemetry.io/auto, and the primary language of the repository is C, with the eBPF programs written in C and the control plane in Go. The dependency that makes the eBPF half possible is github.com/cilium/ebpf at 0.22.0, which is the library that loads and manages the eBPF programs.
Two things in the README bracket what this is. It is compatible with all current supported versions of the Go language, and it carries a construction sign saying the project is currently work in progress. Both statements matter, and they pull in opposite directions: the compatibility promise is broad, the maturity is not.
The version scheme is unusual and worth reading. The recent releases are v0.24.0, tagged as v0.24.0/v1.2.1, and sdk/v1.2.1, and the module is still 0.x, so the auto instrumentation component and the SDK it embeds version separately. The go.mod also carries a long retract list of versions from v0.5.0 to v0.6.5 marked as published accidentally, which tells you the release tooling here has had a rough patch and that the project is the one to trust for what actually shipped.
The support matrix, and the two newest Go releases only
The compatibility section is unusually explicit, and it is the part to read before you plan a rollout.
The tested environments are a small table: Ubuntu with Go 1.27 on amd64, Ubuntu with Go 1.26 on amd64, Ubuntu with Go 1.27 on arm64, and Ubuntu with Go 1.26 on arm64. So the project supports arm64 and CI tests the supported Go versions on Ubuntu arm64 runners, but the matrix covers the two newest Go releases on one Linux distribution.
The policy behind that is stated as a note. Each major Go release is supported until there are two newer major releases, with the example given that Go 1.5 was supported until the Go 1.7 release and Go 1.6 was supported until Go 1.8. And for versions of Go that are no longer supported upstream, the project says it will stop ensuring compatibility in a defined way: a minor release adds support for the new supported release of Go, and the following minor release removes compatibility testing for the oldest, now archived upstream, version. Those releases may include features only supported by the currently supported versions.
That last sentence is the practical warning. A minor version bump can drop a Go version, and a feature can arrive that only works on the newer Go. If your fleet is pinned to an older Go, your upgrade path is bounded by the project's own release cadence rather than by your schedule.
Automatic instrumentation is documented as working on any Linux kernel above 4.4, which is a low floor and a useful one, since it means the constraint is the kernel version rather than a recent distribution.
For users of non-Linux operating systems, the documented options are the Docker images or creating a virtual machine to compile and run the project. There is no native macOS or Windows path, and the compatibility file, COMPATIBILITY.md, is where you find which Go packages this project provides instrumentation for.
The container build, and what the Dockerfile reveals
The Dockerfile is the clearest statement of how the project is put together, and it is a three stage build.
The base stage is golang:1.27.2-bookworm, pinned by digest, and it installs the build dependencies the eBPF half needs: curl, clang, gcc, llvm, make and libbpf-dev. The clang and llvm packages are the eBPF compiler, and libbpf-dev is the user space library that the generated code talks to.
The builder stage copies the sdk/ directory first, and the comment explains why: the go.mod has a replace directive for the SDK module, so copying it before the rest of the source lets go mod resolve. Then go.mod and go.sum are copied and go mod download and go mod verify run with a cache mount, so dependencies are fetched once and verified. The full source is copied after that.
Then the code generation, which is the key step:
RUN --mount=type=cache,target=/root/.cache/go-build \
--mount=type=cache,target=/go/pkg \
go generate ./... \
&& go build -o otel-go-instrumentation ./cli/...go generate is what compiles the eBPF programs into Go code, using the bpf2go generator, and the BPF2GO_CFLAGS argument points at the include directories for libbpf and the project headers. The CGO_ENABLED argument is a build argument defaulting to 0, so the binary is static.
The runtime stage is gcr.io/distroless/base-debian12, pinned by digest, containing only the single otel-go-instrumentation binary. No shell, no package manager, nothing else in the image.
That is the whole deployment story, and it is also the whole risk story: the container needs privileges to load eBPF programs and attach to another process, and the image is built so that the only thing running inside it is the instrumenter.
The precommit target, and the tooling it drags in
The Makefile shows what the maintainers expect of a contribution, and the default goal is precommit, which is a chain of five checks:
precommit: license-header-check golangci-lint-fix test codespell markdown-lintLicense header check first, then golangci-lint with fix enabled, then the tests, then a spell check and a markdown lint. The order matters slightly, because the license header check comes before everything else and the project is Apache-2.0 with a third-party licences directory, so every new source file needs the right header.
The tool dependencies are built rather than downloaded, which is the pattern most Go projects use now. The Makefile has a TOOLS directory and a rule that builds a tool from a module in internal/tools by copying the module and running go build with -buildvcs=false. The tools are multimod for the multi-module versioning, go-licenses for the third-party licence inventory, dbotconf, golangci-lint, and offsetgen. The.golangci.yml at the root is the lint configuration.
The multi-module setup is visible in the Makefile too. ALL_GO_MOD_DIRS finds every go.mod in the tree except the LICENSES directory, and EXAMPLE_MODS filters to the examples, so the examples are separate modules with their own dependencies. That matches the repository listing, where examples/httpPlusdb, examples/kafka-go and examples/rolldice are each self-contained, and where the sdk/ directory is a separate module, and where hooks/, pipeline/, provider/, cli/ and internal/ split the codebase into its parts.
The image build has its own targets, with IMG_NAME defaulting to otel-go-instrumentation and a base image variant, and DOCKER_USER is set from the host uid and gid, so a locally built image runs as the same user as the person who built it rather than as root. The dependencies.Dockerfile is a separate file for the dependency layer, which is the standard trick for keeping the layer cache useful.
What it costs, and where to look first
The first limitation is the platform, and it is not a soft one. The documented support is Linux with a kernel above 4.4, and everything else runs through a Docker image or a virtual machine. If your developers are on macOS, every change to the instrumented service means a round trip to a Linux environment, and if your production is on Windows or a managed platform that forbids privileged containers, the whole approach is out.
The second limitation is the privilege requirement. Loading eBPF programs and attaching to another process is a privileged operation, and the project ships a distroless container that contains nothing but the instrumenter, which is the shape of a component that expects to run with elevated rights next to the workload. The security review conversation is therefore not optional, and it is a conversation about your orchestrator's policy, not just about a container image.
The third limitation is the maturity. The project says it is work in progress, the auto module is still 0.x with a separate SDK version, and the go.mod retracts a dozen versions as published accidentally. The compatibility matrix covers two Go releases on one distribution, so a version you support may not be in the tested set.
The fourth is scope of coverage. COMPATIBILITY.md is where you find which Go packages this project provides instrumentation for, and that list is the real limit on what you get traces for. The documentation splits into getting-started for setup, deployment and configuration, a configuration document, a tutorial that sets up a sample Emojivoto application, and a how-it-works document for the technical and design detail.
The licence is the easy part. The project is licensed under the Apache Software License version 2.0, with the licence file in the repository and third-party licences and copyright notices in the LICENSES directory, and the last push was on 2026-10-15.
Editorial conclusion
This project fits a team running Go services on Linux that wants distributed traces without editing the source of every service, and that accepts running an agent with elevated privileges next to the process. It is a poor fit for a workload you cannot instrument at the process level, for a macOS or Windows development machine, since the supported path is the Docker image or a virtual machine, and for a team that needs a stable production dependency, since the project states it is work in progress. Before adopting, read COMPATIBILITY.md to see which Go packages are actually instrumented, and check the kernel version, because automatic instrumentation is documented as working only on Linux kernels above 4.4.
Frequently asked questions
What does the OpenTelemetry Go auto instrumentation project do?
It provides OpenTelemetry tracing instrumentation for Go libraries using eBPF, attaching to a running Go binary at the kernel level so you get spans without adding instrumentation code to your service.
Which Go versions and operating systems does it support?
It is compatible with all current supported Go versions, following the policy that each major Go release is supported until there are two newer major releases. The tested environments are Ubuntu with Go 1.27 and 1.26 on amd64 and arm64, and automatic instrumentation works on any Linux kernel above 4.4.
Can I use it on macOS or Windows?
Not natively. Users of non-Linux operating systems can use the Docker images or create a virtual machine to compile and run OpenTelemetry Go Automatic Instrumentation.
How is the eBPF code compiled into the project?
The Dockerfile installs clang, llvm and libbpf-dev, then the builder stage runs go generate ./... with BPF2GO_CFLAGS pointing at the libbpf and project include directories, which compiles the eBPF programs into Go code, before go build -o otel-go-instrumentation ./cli/... produces the binary that is copied into a distroless runtime image.
How mature is this project?
The README marks it as work in progress, the auto module is versioned 0.x with the SDK versioned separately, and the go.mod retracts a list of versions marked as published accidentally. The repository is not archived and the last push was on 2026-10-15, with the most recent release v0.24.0 tagged as v0.24.0/v1.2.1.
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-go-instrumentation)Was this useful?