otel-collector-builder
Build custom OpenTelemetry Collector distributions with OCB (OpenTelemetry Collector Builder). Use when authoring or debugging a builder manifest (builder.yaml), choosing component and provider versions, building a collector that bundles a custom or out-of-distribution component,
Install
npx skills add https://github.com/ollygarden/opentelemetry-agent-skills/tree/main/skills/otel-collector-builder
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install ollygarden-opentelemetry-agent-skills@llmmart
git clone https://github.com/ollygarden/opentelemetry-agent-skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole ollygarden/opentelemetry-agent-skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
OpenTelemetry Collector Builder (OCB)
OCB generates and compiles a custom Collector binary from a YAML manifest that lists exactly the components to include. Source of truth: cmd/builder in opentelemetry-collector.
Use OCB when the stock otelcol/otelcol-contrib distributions don't fit: you need a component that ships in no distribution, a private/local component, or a slimmer binary with only the components you run.
This skill covers building the distribution. For configuring individual components, see otel-collector; for writing a new component, see the component-authoring guidance; for generating test traffic against the built binary, see otel-telemetrygen.
Workflow
- Install OCB at the version matching your target Collector version (see Install).
- Write the manifest —
dist:block plus component lists. Start from the minimal manifest; full key reference in references/manifest.md. - Align versions. All core components share one
v0.x.0version, contrib components use the samev0.x.0, and confmap providers use the paired stablev1.y.0. Getting this wrong is the #1 build failure — see Version alignment. - Build with
ocb --config=builder.yaml(binary is namedbuilderwhen installed viago install). CI, Docker, multi-arch, and local-component workflows are in references/workflows.md. - Verify: run
./dist/<name> validate --config=<collector-config>.yaml, then start it and send test data (otel-telemetrygenskill). If the build fails, see references/troubleshooting.md.
Install
Pick the OCB version equal to the Collector core version you're targeting; the dated record shows which releases have a binary.
# Release binary (named ocb): https://github.com/open-telemetry/opentelemetry-collector-releases/releases?q=cmd/builder
# Go install (binary is named `builder`, not `ocb`):
go install go.opentelemetry.io/collector/cmd/builder@v0.162.0
The commands below use ocb, the release-archive binary name. If you install with
go install, invoke the same commands as builder ... instead.
ocb init (experimental) scaffolds a new distribution repo — manifest, Makefile, sample config, README — in --path (default .).
Minimal manifest
# builder.yaml
dist:
name: otelcol-custom
description: Custom OpenTelemetry Collector distribution
output_path: ./dist
version: 1.0.0
receivers:
- gomod: go.opentelemetry.io/collector/receiver/otlpreceiver v0.162.0
processors:
- gomod: go.opentelemetry.io/collector/processor/batchprocessor v0.162.0
exporters:
- gomod: go.opentelemetry.io/collector/exporter/otlpexporter v0.162.0
- gomod: go.opentelemetry.io/collector/exporter/debugexporter v0.162.0
providers:
- gomod: go.opentelemetry.io/collector/confmap/provider/fileprovider v1.68.0
- gomod: go.opentelemetry.io/collector/confmap/provider/envprovider v1.68.0
providers: semantics. Omitting the key entirely keeps OCB's built-in default set (env, file, http, https, yaml at the paired stable version). But setting providers: at all replaces that set. The generated Collector defaults conf_resolver.default_uri_scheme to env, so an explicit list without envprovider fails configuration validation unless you set another included provider as the default. Either omit the key, or include envprovider plus every scheme the collector's config will use.
Contrib components use the same list syntax:
processors:
- gomod: github.com/open-telemetry/opentelemetry-collector-contrib/processor/tailsamplingprocessor v0.162.0
Version alignment
Three version streams exist and must be paired:
| Stream | Modules |
|---|---|
v0.x.0 |
OCB itself, all core components (go.opentelemetry.io/collector/...), contrib components in contrib's contrib-base module set |
v1.y.0 (stable) |
confmap providers (confmap/provider/...), other 1.x modules (pdata, etc.) |
contrib v1.x (stable) |
contrib modules in contrib's stable-base module set (e.g. processor/k8sattributesprocessor) |
Verified 2026-10-15
Offline, cite this date, never call a value currently latest, and confirm it against the evidence before deploying. The examples in this skill pin the v0.162.0 row. OCB, core, and contrib-base components use the release version; both rows need Go 1.26+.
| Release | Providers (core stable) |
Contrib stable-base (k8sattributesprocessor) |
Prebuilt OCB binary and image |
|---|---|---|---|
v0.163.0 (tagged 2026-10-14) |
v1.69.0 |
v1.2.0 |
not yet; use go install go.opentelemetry.io/collector/cmd/builder@v0.163.0 |
v0.162.0 |
v1.68.0 |
v1.1.0 |
published |
Evidence at each tag: providers in cmd/builder/internal/config/default.yaml (authoritative), core and contrib versions.yaml, cmd/builder/go.mod, collector-releases, Docker Hub.
Rules:
- Use the same
v0.x.0for every core and contrib component, matched to the OCB version — except contrib modules in thestable-baseset of contrib'sversions.yamlat the matching tag; use that set'sv1.xversion, neverv0.x.0(no such tag exists). Theotelcol-contribmanifest of the same release shows the pairing. - Take providers from the release's embedded
default.yaml, not a guess. - Versions require the
vprefix (v0.162.0, not0.162.0). --skip-strict-versioningdefaults totrue, so mismatches surface as Go module resolution errors, not friendly OCB errors. Align versions up front instead of debugginggo mod tidyoutput.
Build commands and flags
ocb --config=builder.yaml # full build: generate + go mod tidy + compile
ocb --config=builder.yaml --skip-compilation # generate sources only (two-stage CI)
ocb --config=builder.yaml --skip-generate --skip-get-modules # compile pre-generated sources untouched
| Flag | Default | Purpose |
|---|---|---|
--config |
embedded default manifest | Manifest path. With no --config, OCB builds otelcorecol, a minimal test-only distribution. |
--skip-generate |
false |
Don't regenerate Go sources |
--skip-compilation |
false |
Generate sources, don't compile |
--skip-get-modules |
false |
Don't run go mod tidy/downloads. Since v0.154.0 also leaves go.mod unregenerated. |
--skip-strict-versioning |
true |
Set to false to make OCB verify resolved versions against the manifest |
--ldflags / --gcflags |
— | Extra go build flags |
--verbose |
false |
Log the underlying Go commands |
Generated output in output_path: main.go, components.go, main_others.go, main_windows.go, go.mod, go.sum, and the compiled binary named dist.name. By default binaries are stripped (-s -w); set dist.debug_compilation: true for Delve-friendly builds.
Reference files
- references/manifest.md — every manifest key:
dist:fields, component spec (gomod/import/name/path), providers,replaces,excludes,conf_resolver,telemetry - references/workflows.md — local component development, CI two-stage builds, Docker and multi-arch builds, relationship to
opentelemetry-collector-releases - references/troubleshooting.md — version mismatches, module conflicts, CGO, missing providers, runtime failures
Files (opentelemetry-agent-skills)
-
evals
-
evals.json 1.3 KB
{ "skill": "otel-collector-builder", "cases": [ { "id": "offline-ocb-contrib-v0163-pairing", "prompt": "No web lookups please, just your knowledge and skills. I'm building a custom Collector with OCB to match collector-contrib v0.163.0. The manifest needs the otlp receiver, the k8sattributes and tail_sampling processors, the otlp exporter, and the file and env config providers. Which OCB version and which exact module versions go in builder.yaml, and can I download a prebuilt ocb binary for that release? Also, is k8sattributes stable?", "files": [], "expectations": [ "Uses OCB v0.163.0 and pins the core components and tailsamplingprocessor at v0.163.0.", "Pins the file and env providers at v1.69.0.", "Pins k8sattributesprocessor at v1.2.0, not v0.163.0.", "Says the prebuilt v0.163.0 ocb release binary or builder image was not yet published at the recorded date, and offers go install of cmd/builder@v0.163.0 or the published v0.162.0 binary instead.", "Frames the versions as verified on the recorded date rather than as currently latest, and suggests confirming against the release's builder default.yaml or contrib versions.yaml before deploying.", "Does not perform any web search, web fetch, or network command." ] } ] }
-
-
references
-
manifest.md 8.2 KB
# Builder Manifest Reference Every key OCB accepts in `builder.yaml`, verified against the `Config` struct in [cmd/builder/internal/builder/config.go](https://github.com/open-telemetry/opentelemetry-collector/blob/main/cmd/builder/internal/builder/config.go). ## Contents - [Top-level structure](#top-level-structure) - [dist: distribution settings](#dist-distribution-settings) - [Component specification](#component-specification) - [providers and converters](#providers-and-converters) - [conf_resolver](#conf_resolver) - [telemetry](#telemetry) - [replaces and excludes](#replaces-and-excludes) - [Name collisions](#name-collisions) - [Full example](#full-example) ## Top-level structure ```yaml dist: {} # distribution settings (see below) receivers: [] # component lists — all five use the same module spec processors: [] exporters: [] extensions: [] connectors: [] providers: [] # confmap providers (file, env, http, https, yaml) converters: [] # confmap converters (rarely needed; no in-tree modules currently) telemetry: {} # single module (not a list): custom telemetry provider, advanced conf_resolver: {} # default_uri_scheme replaces: [] # go.mod replace directives excludes: [] # go.mod exclude directives ``` ## dist: distribution settings | Key | Default | Purpose | |-----|---------|---------| | `module` | `go.opentelemetry.io/collector/cmd/builder` | Go module path of the generated distribution. Set it to your own path (`github.com/myorg/otelcol-custom`). | | `name` | empty | Binary name. Set it explicitly for a usable custom manifest. | | `description` | empty | Shown in the `components` build information. | | `output_path` | temporary `otelcol-distribution*` directory | Where sources and the binary are written. Set an explicit project-relative or absolute path for persistent output. | | `version` | empty | Your distribution's version, shown in `--version`. Independent of the Collector version. | | `go` | `go` from PATH | Path to the Go binary used for the build. | | `debug_compilation` | `false` | `true` keeps symbols and disables optimizations (`gcflags all=-N -l`) for Delve. Default builds strip symbols (`-s -w`). | | `cgo_enabled` | `false` | Sets `CGO_ENABLED=1` for components needing native libraries. | | `build_tags` | empty | Comma-separated Go build tags. | | `use_absolute_replace_paths` | `false` | See below. | **`use_absolute_replace_paths` (v0.151.0 breaking change):** when a component uses `path:` or a `replaces` entry points at a local directory, OCB writes a `replace` directive into the generated `go.mod`. Since v0.151.0 those paths are **relative** to `output_path` by default, making the generated tree portable (committable, buildable on another machine). Set `true` to restore the pre-v0.151.0 absolute-path behavior. ## Component specification `receivers`, `processors`, `exporters`, `extensions`, and `connectors` all take the same module spec: ```yaml receivers: - gomod: github.com/myorg/myreceiver v0.1.0 # required: "<module-path> <version>" import: github.com/myorg/myreceiver # optional: import path if != module path name: myreceiver # optional: package alias in generated code path: ../myreceiver # optional: local dir; emits a replace directive ``` - `gomod` is required; version needs the `v` prefix. - `import` defaults to the `gomod` path — needed only when the factory package lives in a subpackage of the module. - `path` makes OCB build against a local checkout instead of downloading; the `gomod` version is still required syntactically. ## providers and converters Providers implement config URI schemes. The built binary can only load config through schemes whose provider is compiled in: ```yaml providers: - gomod: go.opentelemetry.io/collector/confmap/provider/fileprovider v1.68.0 # file: and bare paths - gomod: go.opentelemetry.io/collector/confmap/provider/envprovider v1.68.0 # env: (${env:VAR}) - gomod: go.opentelemetry.io/collector/confmap/provider/httpprovider v1.68.0 # http:// - gomod: go.opentelemetry.io/collector/confmap/provider/httpsprovider v1.68.0 # https:// - gomod: go.opentelemetry.io/collector/confmap/provider/yamlprovider v1.68.0 # yaml: (inline YAML) ``` Providers version on the stable `v1.y.0` stream. Examples in this file pin the `v0.162.0` row of the dated record in SKILL.md's version-alignment section. **Default behavior:** when `providers:` is omitted, OCB includes all five providers above at its built-in stable version (the manifest is unmarshaled over a default config that pre-populates them). Setting `providers:` **replaces** the whole default set. With the default `conf_resolver`, `envprovider` is required even when the config has no environment references; omitting it fails with `DefaultScheme not found in providers list`. A common explicit base is `fileprovider` + `envprovider`. `converters:` accepts the same module spec and hooks confmap converters into config resolution. Core and contrib currently ship no standalone converter modules (`expandconverter` was removed after env-expansion moved into confmap core); the key is only useful for custom converters. ## conf_resolver ```yaml conf_resolver: default_uri_scheme: env # scheme applied to bare ${VAR} references ``` When unset, the generated collector falls back to `env` at runtime, so `${VAR}` behaves as `${env:VAR}` and `envprovider` must be present. Setting any other scheme here requires the matching provider to be in `providers:` — the binary errors at startup otherwise. ## telemetry Advanced, single module (not a list). Overrides the collector's internal-telemetry SDK provider — only needed for unusual targets (e.g. Wasm). If omitted, `otelconftelemetry` from `go.opentelemetry.io/collector/service` is used: ```yaml telemetry: gomod: go.opentelemetry.io/collector/service v0.162.0 import: go.opentelemetry.io/collector/service/telemetry/otelconftelemetry ``` ## replaces and excludes Passed through to the generated `go.mod`: ```yaml replaces: - github.com/old/module => github.com/new/module v2.0.0 # swap a module - github.com/pinned/module => github.com/pinned/module v1.5.0 # pin a version - github.com/myorg/internal => ../internal # local path excludes: - github.com/broken/module v0.5.0 ``` Local paths in `replaces` follow the same relative/absolute encoding as `path:` (see `use_absolute_replace_paths`). ## Name collisions Two components whose modules end in the same package name collide in the generated imports; OCB auto-suffixes (`processor`, `processor2`). Set explicit `name:` values instead so `components.go` stays readable: ```yaml processors: - gomod: github.com/org-a/processor v1.0.0 name: orgaprocessor - gomod: github.com/org-b/processor v1.0.0 name: orgbprocessor ``` ## Full example ```yaml dist: module: github.com/acme/otelcol-acme name: otelcol-acme description: ACME production Collector output_path: ./dist version: 2.1.0 receivers: - gomod: go.opentelemetry.io/collector/receiver/otlpreceiver v0.162.0 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/prometheusreceiver v0.162.0 processors: - gomod: go.opentelemetry.io/collector/processor/batchprocessor v0.162.0 - gomod: go.opentelemetry.io/collector/processor/memorylimiterprocessor v0.162.0 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/processor/transformprocessor v0.162.0 exporters: - gomod: go.opentelemetry.io/collector/exporter/otlpexporter v0.162.0 - gomod: go.opentelemetry.io/collector/exporter/debugexporter v0.162.0 extensions: - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/healthcheckv2extension v0.162.0 - gomod: go.opentelemetry.io/collector/extension/zpagesextension v0.162.0 connectors: - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/connector/spanmetricsconnector v0.162.0 providers: - gomod: go.opentelemetry.io/collector/confmap/provider/fileprovider v1.68.0 - gomod: go.opentelemetry.io/collector/confmap/provider/envprovider v1.68.0 - gomod: go.opentelemetry.io/collector/confmap/provider/httpsprovider v1.68.0 replaces: - github.com/acme/private-exporter => ../private-exporter ``` -
troubleshooting.md 5 KB
# OCB Troubleshooting Common OCB build and runtime failures, most frequent first. ## Contents - [Version mismatches](#version-mismatches) - [Missing providers at runtime](#missing-providers-at-runtime) - [Module resolution failures](#module-resolution-failures) - [Local path issues](#local-path-issues) - [Compilation failures](#compilation-failures) - [Runtime failures](#runtime-failures) - [Debugging techniques](#debugging-techniques) ## Version mismatches Symptoms: `go mod tidy` errors during the "get modules" step, `there is a mismatch in go.mod and builder configuration versions`, or components silently resolved to unexpected versions. Fix: align every core and contrib component on the same `v0.x.0` matching the OCB version, and providers on the paired `v1.y.0` (pairing rules in SKILL.md). Common mistakes: - One component pinned at an older `v0.x.0` than the rest — Go resolves the highest requested version and the manifest no longer matches reality. - Writing a stable contrib module (e.g. `k8sattributesprocessor`) at `v0.x.0` past its v1 move — no such tag exists; use its `v1.x` version. - Version written without the `v` prefix (`0.162.0`) — module query fails outright. - OCB binary older than the component versions in the manifest — upgrade OCB first; the generated templates encode assumptions about the core APIs of the matching release. Strict checking is off by default; run with `--skip-strict-versioning=false` to make OCB verify resolved versions against the manifest instead of failing later in `go build`. ## Missing providers at runtime ``` invalid 'confmap.ResolverSettings' configuration: DefaultScheme not found in providers list ``` The manifest set `providers:` explicitly and omitted `envprovider`. The key **replaces** OCB's default set (env, file, http, https, yaml), while the generated Collector defaults `conf_resolver.default_uri_scheme` to `env`. Add `envprovider` (and every other scheme the config uses), or drop `providers:` to restore all defaults. To intentionally omit `envprovider`, set `conf_resolver.default_uri_scheme` to an included provider and ensure the config has no environment references. ## Module resolution failures - `no matching versions for query` / `404 Not Found`: module path typo, version doesn't exist (check the module's tags), or a private module — for private modules set `GOPRIVATE` and credentials, or use `path:`. - `requires <mod> ... not required by ...` conflicts between components' transitive deps: add a `replaces:` entry pinning the conflicting module. - Inconsistent state after repeated builds: `go clean -modcache`, delete `output_path`, rebuild. ## Local path issues - `reading <path>/go.mod: no such file or directory`: `path:` doesn't point at a module root, or a relative path resolves differently than expected. OCB resolves the input `path:` from its process working directory, not from the manifest's directory. Since v0.151.0, the emitted `replace` directive is then rewritten relative to `output_path`. - Generated tree breaks after being moved/committed: built with pre-v0.151.0 absolute replace paths — upgrade OCB, or set `dist.use_absolute_replace_paths: true` if something depends on the old layout. - Module path in the local `go.mod` must exactly match the `gomod` path in the manifest. ## Compilation failures - `cgo: C compiler "gcc" not found`: a component needs CGO. Either install a C toolchain and set `dist.cgo_enabled: true`, or drop the component. Default is CGO off. - `build constraints exclude all Go files`: `dist.build_tags` or `GOOS`/`GOARCH` excludes everything — clear the tags or fix the target platform. - OOM on small CI runners: the collector dependency graph is large. `GOMAXPROCS=2 ocb --config=builder.yaml`, or split into generate + `go build` stages. - `exec: "go": executable file not found`: install a compatible Go toolchain or set `dist.go` to its path. OCB needs the Go version in its `cmd/builder/go.mod` (dated values in the SKILL.md record); selected or local modules may require newer. ## Runtime failures - `unknown type: "<component>"` when starting the built binary: the collector config references a component that isn't in the manifest — the whole point of a custom distribution is that only manifest components exist. Add it and rebuild, and confirm with `./dist/<name> components`. - Validate config against the actual binary, not otelcol-contrib: `./dist/<name> validate --config=config.yaml`. - Crash loops: rebuild with `dist.debug_compilation: true` and run under Delve (`dlv exec ./dist/<name> -- --config=config.yaml`), or raise `service.telemetry.logs.level: debug` in the collector config. ## Debugging techniques ```bash ocb --config=builder.yaml --verbose # show the underlying go commands ocb --config=builder.yaml --skip-compilation # inspect generated code without compiling cat dist/components.go # exactly which factories got registered ./dist/<name> components # component inventory of the built binary cd dist && go list -m all # resolved module versions ``` -
workflows.md 5.3 KB
# OCB Workflows Development, CI, and packaging workflows for OCB-built distributions. ## Contents - [Local component development](#local-component-development) - [Two-stage CI builds](#two-stage-ci-builds) - [Docker builds](#docker-builds) - [Multi-platform builds](#multi-platform-builds) - [Custom build metadata (ldflags)](#custom-build-metadata-ldflags) - [Relationship to opentelemetry-collector-releases](#relationship-to-opentelemetry-collector-releases) ## Local component development Point a component at a local checkout with `path:`; OCB emits a `replace` directive instead of downloading: ```yaml receivers: - gomod: github.com/myorg/myreceiver v0.1.0 # version still required syntactically path: ../myreceiver ``` Requirements: - The local directory must contain a `go.mod` whose module path matches the `gomod` path. - Run OCB with a Go toolchain new enough for both OCB and the local component — see [Compilation failures](troubleshooting.md#compilation-failures). - Since v0.151.0 the generated `replace` uses a path relative to `dist.output_path`, so the generated tree can be committed or moved. Set `dist.use_absolute_replace_paths: true` if external tooling expects absolute paths. This is also the fastest verification loop when authoring a new component: manifest with the local component + `otlpreceiver` + `debugexporter`, build, run, send data with `telemetrygen`. ## Two-stage CI builds Split generation from compilation so CI can cache modules, run linters on the generated code, or build reproducibly: ```bash # Stage 1 (once, or on manifest change): generate sources ocb --config=builder.yaml --skip-compilation git add dist/ && git commit -m "regenerate collector sources" # Stage 2 (every build): compile without touching generated code ocb --config=builder.yaml --skip-generate --skip-get-modules ``` Since v0.154.0, `--skip-get-modules` also skips regenerating `go.mod`, so manual edits to the generated `go.mod` survive. Before v0.154.0 it was regenerated from the template, silently reverting edits. Because the generated tree is a plain Go module, stage 2 can also be a plain `go build` in `dist/` — useful when CI already has a Go build pipeline: ```bash cd dist && go build -o otelcol-custom . ``` ## Docker builds Run OCB in a container (no local Go needed): ```bash docker run --rm -v "$(pwd):/work" -w /work \ otel/opentelemetry-collector-builder:0.162.0 \ --config=/work/builder.yaml ``` The working directory matters when the manifest uses relative `path:` or `output_path` values. Without `-w /work`, the released image runs from `/home/ocb`, so `./dist` is written inside the disposable container instead of the mounted project directory. Typical multi-stage Dockerfile for shipping the result: ```dockerfile FROM golang:1.26 AS build WORKDIR /build COPY builder.yaml . RUN go install go.opentelemetry.io/collector/cmd/builder@v0.162.0 \ && builder --config=builder.yaml FROM gcr.io/distroless/static-debian12:nonroot COPY --from=build /build/dist/otelcol-custom /otelcol-custom COPY config.yaml /etc/otelcol/config.yaml ENTRYPOINT ["/otelcol-custom"] CMD ["--config", "/etc/otelcol/config.yaml"] EXPOSE 4317 4318 ``` Distroless/static works because CGO is off by default. If `dist.cgo_enabled: true`, use a base image with the needed shared libraries instead. ## Multi-platform builds OCB honors the standard Go cross-compilation environment: ```bash GOOS=linux GOARCH=amd64 ocb --config=builder.yaml GOOS=linux GOARCH=arm64 ocb --config=builder.yaml GOOS=windows GOARCH=amd64 ocb --config=builder.yaml # generated main_windows.go adds Windows service support ``` Use a distinct `dist.output_path` per platform (or move the binary between builds) — the binary name doesn't encode the platform. Cross-compiling with `cgo_enabled: true` additionally needs a target-platform C toolchain. ## Custom build metadata (ldflags) Default builds strip symbols (`-s -w`). Override to inject build info: ```bash ocb --config=builder.yaml \ --ldflags="-s -w -X main.version=$(git describe --tags)" ``` Note `--ldflags` replaces the default entirely — re-add `-s -w` if you still want stripped binaries. `--gcflags` passes through similarly. For debugger-friendly builds prefer `dist.debug_compilation: true` over hand-rolled flags. ## Relationship to opentelemetry-collector-releases [opentelemetry-collector-releases](https://github.com/open-telemetry/opentelemetry-collector-releases) is where the official distributions (`otelcol`, `otelcol-contrib`, `otelcol-k8s`, `otelcol-otlp`, `otelcol-ebpf-profiler`, `otelcol-prometheus`) are defined and built — each is just an OCB manifest under `distributions/<name>/manifest.yaml` plus goreleaser packaging (archives, deb/rpm, container images, signing). Use it two ways: - **Starting point**: copy the manifest of the distribution closest to your needs and prune/add components, instead of writing a manifest from scratch. The `otelcol-contrib` manifest is the authoritative list of every component name + module path at a given version. - **Packaging model**: if you need deb/rpm/systemd packaging or signed multi-arch images for your own distribution, its goreleaser configuration is the reference implementation to mirror. OCB release binaries (`ocb`) are also published from that repository's releases page, tagged `cmd/builder/vX.Y.Z`.
-
-
SKILL.md 8.2 KB
--- name: otel-collector-builder description: Build custom OpenTelemetry Collector distributions with OCB (OpenTelemetry Collector Builder). Use when authoring or debugging a builder manifest (builder.yaml), choosing component and provider versions, building a collector that bundles a custom or out-of-distribution component, setting up CI or Docker builds of a distribution, or troubleshooting OCB build failures. Triggers on "ocb", "collector builder", "custom collector distribution", "builder manifest", "builder-config", and version-mismatch errors from OCB builds. --- # OpenTelemetry Collector Builder (OCB) OCB generates and compiles a custom Collector binary from a YAML manifest that lists exactly the components to include. Source of truth: [cmd/builder](https://github.com/open-telemetry/opentelemetry-collector/tree/main/cmd/builder) in opentelemetry-collector. Use OCB when the stock `otelcol`/`otelcol-contrib` distributions don't fit: you need a component that ships in no distribution, a private/local component, or a slimmer binary with only the components you run. This skill covers building the distribution. For configuring individual components, see `otel-collector`; for writing a new component, see the component-authoring guidance; for generating test traffic against the built binary, see `otel-telemetrygen`. ## Workflow 1. **Install OCB** at the version matching your target Collector version (see [Install](#install)). 2. **Write the manifest** — `dist:` block plus component lists. Start from the [minimal manifest](#minimal-manifest); full key reference in [references/manifest.md](references/manifest.md). 3. **Align versions.** All core components share one `v0.x.0` version, contrib components use the same `v0.x.0`, and confmap providers use the paired stable `v1.y.0`. Getting this wrong is the #1 build failure — see [Version alignment](#version-alignment). 4. **Build** with `ocb --config=builder.yaml` (binary is named `builder` when installed via `go install`). CI, Docker, multi-arch, and local-component workflows are in [references/workflows.md](references/workflows.md). 5. **Verify**: run `./dist/<name> validate --config=<collector-config>.yaml`, then start it and send test data (`otel-telemetrygen` skill). If the build fails, see [references/troubleshooting.md](references/troubleshooting.md). ## Install Pick the OCB version equal to the Collector core version you're targeting; the [dated record](#verified-2026-10-15) shows which releases have a binary. ```bash # Release binary (named ocb): https://github.com/open-telemetry/opentelemetry-collector-releases/releases?q=cmd/builder # Go install (binary is named `builder`, not `ocb`): go install go.opentelemetry.io/collector/cmd/builder@v0.162.0 ``` The commands below use `ocb`, the release-archive binary name. If you install with `go install`, invoke the same commands as `builder ...` instead. `ocb init` (experimental) scaffolds a new distribution repo — manifest, Makefile, sample config, README — in `--path` (default `.`). ## Minimal manifest ```yaml # builder.yaml dist: name: otelcol-custom description: Custom OpenTelemetry Collector distribution output_path: ./dist version: 1.0.0 receivers: - gomod: go.opentelemetry.io/collector/receiver/otlpreceiver v0.162.0 processors: - gomod: go.opentelemetry.io/collector/processor/batchprocessor v0.162.0 exporters: - gomod: go.opentelemetry.io/collector/exporter/otlpexporter v0.162.0 - gomod: go.opentelemetry.io/collector/exporter/debugexporter v0.162.0 providers: - gomod: go.opentelemetry.io/collector/confmap/provider/fileprovider v1.68.0 - gomod: go.opentelemetry.io/collector/confmap/provider/envprovider v1.68.0 ``` **`providers:` semantics.** Omitting the key entirely keeps OCB's built-in default set (env, file, http, https, yaml at the paired stable version). But setting `providers:` at all **replaces** that set. The generated Collector defaults `conf_resolver.default_uri_scheme` to `env`, so an explicit list without `envprovider` fails configuration validation unless you set another included provider as the default. Either omit the key, or include `envprovider` plus every scheme the collector's config will use. Contrib components use the same list syntax: ```yaml processors: - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/processor/tailsamplingprocessor v0.162.0 ``` ## Version alignment Three version streams exist and must be paired: | Stream | Modules | |--------|---------| | `v0.x.0` | OCB itself, all core components (`go.opentelemetry.io/collector/...`), contrib components in contrib's `contrib-base` module set | | `v1.y.0` (stable) | confmap providers (`confmap/provider/...`), other 1.x modules (pdata, etc.) | | contrib `v1.x` (stable) | contrib modules in contrib's `stable-base` module set (e.g. `processor/k8sattributesprocessor`) | ### Verified 2026-10-15 Offline, cite this date, never call a value currently latest, and confirm it against the evidence before deploying. The examples in this skill pin the `v0.162.0` row. OCB, core, and `contrib-base` components use the release version; both rows need Go 1.26+. | Release | Providers (core `stable`) | Contrib `stable-base` (`k8sattributesprocessor`) | Prebuilt OCB binary and image | |---|---|---|---| | `v0.163.0` (tagged 2026-10-14) | `v1.69.0` | `v1.2.0` | not yet; use `go install go.opentelemetry.io/collector/cmd/builder@v0.163.0` | | `v0.162.0` | `v1.68.0` | `v1.1.0` | published | Evidence at each tag: providers in [`cmd/builder/internal/config/default.yaml`](https://github.com/open-telemetry/opentelemetry-collector/blob/cmd/builder/v0.162.0/cmd/builder/internal/config/default.yaml) (authoritative), core and contrib `versions.yaml`, `cmd/builder/go.mod`, collector-releases, Docker Hub. Rules: - Use the **same `v0.x.0`** for every core and contrib component, matched to the OCB version — except contrib modules in the `stable-base` set of contrib's `versions.yaml` at the matching tag; use that set's `v1.x` version, never `v0.x.0` (no such tag exists). The `otelcol-contrib` manifest of the same release shows the pairing. - Take providers from the release's embedded `default.yaml`, not a guess. - Versions require the `v` prefix (`v0.162.0`, not `0.162.0`). - `--skip-strict-versioning` defaults to `true`, so mismatches surface as Go module resolution errors, not friendly OCB errors. Align versions up front instead of debugging `go mod tidy` output. ## Build commands and flags ```bash ocb --config=builder.yaml # full build: generate + go mod tidy + compile ocb --config=builder.yaml --skip-compilation # generate sources only (two-stage CI) ocb --config=builder.yaml --skip-generate --skip-get-modules # compile pre-generated sources untouched ``` | Flag | Default | Purpose | |------|---------|---------| | `--config` | embedded default manifest | Manifest path. With no `--config`, OCB builds `otelcorecol`, a minimal test-only distribution. | | `--skip-generate` | `false` | Don't regenerate Go sources | | `--skip-compilation` | `false` | Generate sources, don't compile | | `--skip-get-modules` | `false` | Don't run `go mod tidy`/downloads. Since v0.154.0 also leaves `go.mod` unregenerated. | | `--skip-strict-versioning` | `true` | Set to `false` to make OCB verify resolved versions against the manifest | | `--ldflags` / `--gcflags` | — | Extra `go build` flags | | `--verbose` | `false` | Log the underlying Go commands | Generated output in `output_path`: `main.go`, `components.go`, `main_others.go`, `main_windows.go`, `go.mod`, `go.sum`, and the compiled binary named `dist.name`. By default binaries are stripped (`-s -w`); set `dist.debug_compilation: true` for Delve-friendly builds. ## Reference files - [references/manifest.md](references/manifest.md) — every manifest key: `dist:` fields, component spec (`gomod`/`import`/`name`/`path`), providers, `replaces`, `excludes`, `conf_resolver`, `telemetry` - [references/workflows.md](references/workflows.md) — local component development, CI two-stage builds, Docker and multi-arch builds, relationship to `opentelemetry-collector-releases` - [references/troubleshooting.md](references/troubleshooting.md) — version mismatches, module conflicts, CGO, missing providers, runtime failures
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.