Topology
collectorTopology(config) reads a collector config, declared or parsed from a YAML file, and returns where its telemetry goes. collectorTopologyOf(entities) does the same for declared entities, via the config the serializer would emit for them. Both return plain data with no chant types in it.
import { collectorTopologyOf } from "@intentius/chant-lexicon-otel";
const topology = collectorTopologyOf(buildResult.entities);for (const exporter of topology.exporters) { console.log(exporter.id, exporter.signals, exporter.endpoints);}interface CollectorTopology { pipelines: Array<{ id: string; signal: string; receivers: string[]; processors: string[]; exporters: string[] }>; components: Array<{ id: string; // "otlp/tempo" kind: "receiver" | "processor" | "exporter" | "connector" | "extension"; type: string; // "otlp" name?: string; // "tempo" builtin: boolean; schema?: { source: string; version: string; digest?: string }; endpoints: string[]; pipelines: string[]; // pipeline ids that use it (for a connector, on either side) }>; exporters: Array<{ id: string; type: string; endpoints: string[]; pipelines: string[]; signals: string[] }>; edges: Array<{ connector: string; from: string; fromSignal: string; to: string; toSignal: string }>; semconv: Array<{ namespace: string; // "gen_ai" source: string; // "github.com/open-telemetry/semantic-conventions" version: string; // "v1.41.1" digest?: string; components: string[]; // component ids whose config uses the namespace }>;}Connector edges
Section titled “Connector edges”edges has one entry per hop a connector makes from one pipeline to another: from is a pipeline that lists the connector as an exporter, to one that lists it as a receiver, each with its signal. A traces pipeline feeding a metrics pipeline through spanmetrics gives:
{ connector: "spanmetrics", from: "traces", fromSignal: "traces", to: "metrics/red", toSignal: "metrics" }Only pairs the connector supports are edges, so a count connector fed by traces and feeding both a metrics and a logs pipeline has one edge, to metrics. For a connector whose definition isn’t loaded, every (from, to) pair is reported. Connectors are not listed under exporters, which answers where telemetry leaves the collector.
endpoints are what the config states, with the collector’s defaults filled in where a component has one (an otlp receiver with an empty grpc block reports localhost:4317). A definition’s endpoints function decides them; a component with no loaded definition reports its endpoint key when it has one. The googlecloud exporter reports googlecloud://projects/<project>, since it sends to Google’s APIs rather than to an address in the config.
Semantic-convention pins
Section titled “Semantic-convention pins”A collector config names attributes (a spanmetrics dimension, a key an OTTL statement deletes) but can’t say which version of the semantic conventions those names come from. semconv answers that for the vocabularies this package pins: for each one the config uses, the pin this package follows and the components that use it. Today those are gen_ai, pinned by GENAI_SEMCONV_PIN, and k8s, pinned by SEMCONV_PIN (semantic-conventions v1.27.0, the newest release the Kubernetes components of contrib v0.130.0 import). A component uses one when any key or value in its config names a gen_ai. or k8s. attribute. The component types k8s_cluster and k8sattributes do not count. The GenAI preset and NodeAgent are the usual sources. semconv is empty when no pinned vocabulary appears. The serializer writes the same fact as a # chant: semconv line at the top of the YAML.
Parsing a built file and reading the declaration give the same topology, which the lexicon’s tests assert.