Telecraft

Catalogue

The Catalogue is the versioned inventory of otelcol component types: each component's identity, per-signal stability, and lifecycle. Telecraft generates it from the metadata.yaml files of opentelemetry-collector-contrib at a pinned release tag.

You can't curate the component list by hand. The only way a component enters a Catalogue is through the import pipeline, which walks an upstream source tree.

A Catalogue states what exists. What a Team can use is the Allow-list.

The (class, type) key

The primary key is the pair (class, type). type alone isn't unique, because the same type string appears in more than one class: kafka is both a receiver and an exporter.

class is one of five pipeline classes:

Class
receiver
processor
exporter
connector
extension

The import excludes upstream's helper classes, such as pkg, cmd, scraper, converter, and provider, and records them in its coverage report.

deprecated_type aliases resolve on every lookup, so a config that says spanmetrics still finds span_metrics.

Stability

Stability is per signal: one component can be beta for logs and alpha for profiles. A floor is judged per (component, signal), never per component.

Level Kind
development maturity rung
alpha maturity rung
beta maturity rung
stable maturity rung
deprecated lifecycle end-state
unmaintained lifecycle end-state

The maturity ladder is development < alpha < beta < stable. A Stability floor compares against that ladder. Lifecycle end-states have no rung; lifecycle findings judge them separately.

The six-level vocabulary is closed: an unknown level fails the load, so a new upstream level is noticed rather than passed through. The signal vocabulary is open: unknown signal names pass through, because upstream adds signals over time.

Artefact format

One Catalogue version is one JSON file. The encoding is deterministic: components in (class, type) order, object keys sorted, no timestamps. Importing the same tag twice produces byte-identical artefacts, and you can diff artefacts across an air gap.

Field Type Description
format_version integer The artefact format. The supported value is 1.
source object Where this Catalogue came from.
source.repository string The upstream repository identity, such as github.com/open-telemetry/opentelemetry-collector-contrib.
source.ref string The pinned release tag. This is the Catalogue's version.
source.commit string The commit that tag resolved to. Omitted when the import ran against a tree with no .git.
components array Every pipeline component type found at that tag.

Each entry of components:

Field Type Description
class string One of the five pipeline classes.
type string The component type.
deprecated_type string The historical alias, when upstream declares one. Omitted otherwise.
module string The Go module path from the component's sibling go.mod.
display_name string Upstream's display name. Omitted when absent.
description string Upstream's description. Omitted when absent.
stability object Map from signal name to level.
deprecation object Map from signal name to { "date", "migration" }, for deprecated signals. Omitted when empty.
{
  "format_version": 1,
  "source": {
    "repository": "github.com/open-telemetry/opentelemetry-collector-contrib",
    "ref": "v0.158.0",
    "commit": "9f0c1a2b3c4d5e6f708192a3b4c5d6e7f8091a2b"
  },
  "components": [
    {
      "class": "exporter",
      "type": "otlphttp",
      "module": "go.opentelemetry.io/collector/exporter/otlphttpexporter",
      "stability": {
        "logs": "beta",
        "metrics": "stable",
        "traces": "stable"
      }
    }
  ]
}

Artefact naming

An artefact is written as catalogue-<ref>.json, so versions sit side by side. A release tag containing / or \ can't name an artefact file and is rejected.

Writes are atomic: the bytes land in a temporary file, which is then renamed into place, so a reader never sees a half-written Catalogue. If the file already holds exactly those bytes, the write is skipped.

Load errors

Loading fails closed and returns nothing. An artefact travels: bundled in a release, downloaded, or carried across an air gap. A tampered or truncated artefact would corrupt every judgement made against it, so the load refuses on:

  • an unknown field, or trailing data after the document
  • a format_version other than 1
  • an empty source.repository or source.ref
  • no components at all
  • a component with a non-pipeline class, an empty type, or an empty module
  • a deprecated_type equal to the component's own type
  • a component with no stability, an empty signal name, or an unknown level
  • a signal marked deprecated with no deprecation notice, a notice for a signal that isn't deprecated, or a notice with no migration text
  • two components sharing the (class, type) key
  • a deprecated_type that's another component's real type, or claimed by two components

Importing with catalogue-import

catalogue-import -tag v0.158.0

writes catalogues/catalogue-v0.158.0.json and prints the coverage report. See the command line reference for every flag and exit code.

The fetch is a sparse, depth-1 git checkout of only the metadata.yaml and go.mod files, a few megabytes rather than the whole repository, into a temporary directory that's removed afterwards. The upstream tree is never vendored. Fetching happens at import time only, on your machine, and the artefact is what travels onward. Telecraft never fetches at runtime.

Import an already-fetched tree offline with -source:

catalogue-import -tag v0.158.0 -source /path/to/contrib

A tree copied without its .git, which is what an air-gap transfer usually produces, still imports. The artefact then records the tag alone, with no source commit.

Discovery

Discovery is by sibling go.mod, recursively, never by directory depth. Depth-based discovery would miss the contrib extensions nested a level deeper, such as extension/storage/filestorage.

A directory is a component candidate when it holds a go.mod. It enters the Catalogue when it also holds a metadata.yaml whose status.class is one of the five pipeline classes.

The import reads only the fields of upstream's metadata.yaml it needs and ignores the rest: type, deprecated_type, display_name, description, and the status block's class, stability, and deprecation. Upstream's stability map runs from level to signals; the import inverts it to signal to level. A signal listed under two levels fails the import.

Coverage report

The import prints an account of the whole tree, so nothing the walker saw goes unrecorded:

Section What it holds
found The count of components that entered the Catalogue, broken down by class.
excluded by class Parsed components whose class keeps them out, with the class recorded.
missing Directories under a component root that hold a Go module but no metadata.yaml.

A directory outside the component roots with no metadata.yaml is ordinary Go layout, not a gap, and isn't listed.

The import fails closed on anything malformed: a metadata.yaml that doesn't parse, a pipeline component without stability, or a duplicate (class, type) key. A gap is reported, never silently dropped.

Versions and activation

A Catalogue is versioned against one collector release tag. There's no partial upgrade: a Catalogue is the whole tag.

Installed catalogues are kept, never replaced. Re-importing the same tag is idempotent and leaves the existing artefact untouched. A different tag writes a new artefact beside the old one.

The active Catalogue is the version your estate has activated, recorded in activations.yaml beside teams.yaml. Authoring, the Palette and the Stability floors are all judged against it. Activating a version is explicit: you read an impact report first, and nothing changes until an operator confirms. See Activate a version for the task, and telecraft activate in the command line reference for the flags.

Evaluating a collector is the other half of the rule, and it does not use the active version. A collector is judged against the Catalogue for the version it actually runs, because Telecraft does not control collector binaries and the version is something it discovers. Where a collector runs a version you have not imported, the nearest older Catalogue judges it and the judgement says it is degraded: an older Catalogue describes components the collector still has and cannot describe ones added since. Where there is nothing older either, nothing is known, and the fix is to import the missing version.

Commands that judge authoring take the Catalogue from the estate, and each still accepts -catalogue to point at one artefact deliberately:

Command Used for
telecraft palette Validating entries and materialising the palette.
telecraft render The Allow-list block and Stability floors.
telecraft check library_drift detection, with -source.
telecraft snapshot The active version, marked as such among the installed set.

telecraft snapshot also takes -catalogues, a directory of installed artefacts. It reads every catalogue-*.json in that directory. The default is the catalogues/ directory under -estate, or the directory holding -catalogue where you gave one.

An Allow-list policy is bound to the Catalogue version it was validated against, because every entry must select at least one component in it. Activating a different Catalogue validates the policy again.