Skip to content

Components

Every built-in follows the config of the collector-contrib release in COLLECTOR_PIN (github.com/open-telemetry/opentelemetry-collector-contrib v0.130.0). The “Checks” column lists what OTEL107 reports beyond the TypeScript type. “Endpoints” is what collectorTopology() reports for the component.

ClassTypeChecksEndpoints
OtlpReceiverotlpat least one of protocols.grpc, protocols.httpeach enabled protocol’s endpoint, defaulting to localhost:4317 and localhost:4318
PrometheusReceiverprometheusscrape job names are unique; some scrape config or a target allocatorstatic scrape targets
HostMetricsReceiverhostmetricsat least one scrapernone
FileLogReceiverfileloginclude is not emptythe include globs
K8sClusterReceiverk8s_clusterdistribution is kubernetes or openshiftnone
KubeletStatsReceiverkubeletstatscert_file and key_file when auth_type is tls (the default); metric_groups is not emptyendpoint

k8s_cluster reads the whole cluster from the Kubernetes API, so run one instance per cluster: a single-replica Deployment, or several replicas that share a K8sLeaderElectorExtension (k8s_leader_elector, see Extensions below). In a per-node DaemonSet every node reports every object. kubeletstats reads the kubelet on its own node, so it belongs in the per-node agent, usually with auth_type: "serviceAccount" and endpoint: "https://${env:K8S_NODE_NAME}:10250". The otel lexicon sees the collector config but not how it is deployed, so it does not flag k8s_cluster in a DaemonSet; the k8s lexicon’s WK8603 does, reading the config together with the workload that runs it.

ClassTypeChecks
BatchProcessorbatchsend_batch_max_size is not below send_batch_size
MemoryLimiterProcessormemory_limiterlimit_mib or limit_percentage is set; spike limit below the limit; percentage within 1 to 100
ResourceProcessorresourceat least one action; each action has what its kind needs
AttributesProcessorattributesas resource, for actions
K8sAttributesProcessork8sattributesnone beyond the type
ResourceDetectionProcessorresourcedetectionat least one detector
FilterProcessorfilterat least one condition or include/exclude block; no empty condition; no signal mixing the two
TransformProcessortransformat least one statement; each group’s context fits its signal and the group has statements
RedactionProcessorredactionallow_all_keys or allowed_keys is set; allowed_keys is not set alongside allow_all_keys: true; no empty pattern; hash_function has something blocked to hash
TailSamplingProcessortail_samplingdecision_wait is set; policies is not empty; policy names are present and unique; each policy has the block its type names and what that block needs; and, drop and composite have sub-policies, and policy_order and rate_allocation name existing ones
ProbabilisticSamplerProcessorprobabilistic_samplersampling_percentage is set and within 0 to 100; sampling_precision within 1 to 14; attribute_source: record has a from_attribute; hash_seed only in hash_seed mode
DeltaToCumulativeProcessordeltatocumulativemax_stale is a positive duration; max_streams is a whole number, 0 or more

Put memory_limiter first in every pipeline; OTEL105 warns otherwise.

filter and transform take OTTL. The structure is typed (which signal, which context, which list) and each condition or statement stays a string that the collector parses when it loads the config, so a mistake in the OTTL itself shows up in otelcol validate, not in the build. filter also types the older include/exclude match blocks under metrics, logs and spans, so that imported configs using them type-check; a signal takes one form or the other, never both.

export const dropHealth = new FilterProcessor({
error_mode: "ignore",
traces: { span: ['attributes["http.route"] == "/healthz"'] },
logs: { log_record: ["severity_number < SEVERITY_NUMBER_INFO"] },
});
export const tidy = new TransformProcessor({
trace_statements: [
{ context: "span", conditions: ["kind == SPAN_KIND_SERVER"], statements: ['set(attributes["tier"], "edge")'] },
'delete_key(span.attributes, "http.request.header.cookie")',
],
});

A transform entry is either a group with an optional context, conditions, statements and error_mode, or a bare statement whose context the collector infers from its paths.

redaction works on span, span event, log and data point attributes, not resource attributes. With allow_all_keys unset or false, every key outside allowed_keys and ignored_keys is deleted, which is why OTEL107 asks for one of the two. Values that match blocked_values, and every value of a key that matches blocked_key_patterns, are masked as ****, or hashed when hash_function is set; allowed_values exempts a value. Patterns are Go regular expressions.

export const scrub = new RedactionProcessor({
allow_all_keys: true,
blocked_key_patterns: ["^gen_ai\\.(prompt|completion)"],
blocked_values: ["[0-9]{13,16}"],
hash_function: "sha3",
summary: "silent",
});

tail_sampling policies are a discriminated union on type (TailSamplingPolicy): the leaf types always_sample, latency, numeric_attribute, probabilistic, status_code, string_attribute, rate_limiting, span_count, trace_state, boolean_attribute and ottl_condition, plus and, drop and composite, whose sub-policies are leaf policies (and, for composite, and policies too). Each policy’s settings sit under the key its type names, as in the collector’s own config:

new TailSamplingProcessor({
decision_wait: "10s",
policies: [
{ name: "errors", type: "status_code", status_code: { status_codes: ["ERROR"] } },
{ name: "slow", type: "latency", latency: { threshold_ms: 2000 } },
{ name: "rest", type: "probabilistic", probabilistic: { sampling_percentage: 10 } },
],
});

Tail sampling needs every span of a trace in one collector. Run it on a gateway, and when the gateway has more than one replica put a loadbalancing exporter on the agents in front of it.

deltatocumulative turns delta metrics into cumulative ones by keeping a running total per stream, and passes cumulative metrics through. Put it in a metrics pipeline fed by a connector that emits deltas (sum, count, signaltometrics) when an exporter reads only cumulative data, such as prometheusremotewrite, which drops the rest. max_stale (default 5m) is how long a stream with no new samples is kept, and max_streams (default unlimited) caps how many are tracked; samples of streams past the cap are dropped. Because the totals live in one collector’s memory, every delta of a stream has to reach the same replica. The type follows config.go, factory.go and the README of processor/deltatocumulativeprocessor at collector-contrib v0.130.0, where it is alpha for metrics and ships in the otelcol-contrib and otelcol-k8s distributions. genAiPipeline({ deltaToCumulative }) inserts one for you; see GenAI pipeline.

ClassTypeChecksEndpoints
OtlpExporterotlpendpoint is setendpoint
OtlpHttpExporterotlphttpendpoint or a per-signal endpoint is setevery endpoint set
DebugExporterdebugnoneconsole
PrometheusExporterprometheusendpoint is setendpoint (the address Prometheus scrapes)
GoogleCloudExportergooglecloudnonegooglecloud://projects/<project>, plus any endpoint overrides
LoadBalancingExporterloadbalancingexactly one resolver; the chosen resolver has its hostnames, hostname or service; routing_key: attributes goes with routing_attributes; no protocol.otlp.endpointstatic hostnames; dns as hostname:port; k8s as service:port per port (default 4317); aws-cloud-map://namespace/service_name

The loadbalancing resolver (LoadBalancingResolver) is one of static (hostnames), dns (hostname, port), k8s (service as name or name.namespace, ports, return_hostnames) or aws_cloud_map; the type allows exactly one. protocol.otlp takes the otlp exporter’s settings without endpoint, which each backend fills in. loadBalancingEndpoints(resolver) returns the same backends collectorTopology() reports.

A connector is an exporter in one pipeline and a receiver in another. List the same entity in exporters of the pipeline that feeds it and in receivers of the pipeline it feeds. “Pairs” is the signal it reads and the signal it writes; OTEL112 checks pipelines against them.

ClassTypePairsChecks
SpanMetricsConnectorspanmetricstraces to metricsnot both histogram.explicit and histogram.exponential; events.enabled needs dimensions; no dimension repeats a default one (service.name, span.name, span.kind, status.code)
ServiceGraphConnectorservicegraphtraces to metricsnone beyond the type
RoutingConnectorroutingsame signal in and outtable is not empty; each route has a condition or a statement (not both) and at least one pipeline; the request context needs a condition
ForwardConnectorforwardsame signal in and outnone
CountConnectorcounttraces, metrics, logs or profiles to metricsmetric names are not empty; counts of metrics take no attributes
SumConnectorsumtraces, metrics or logs to metricsat least one metric; each has a source_attribute; sums of metrics take no attributes; at most one attribute, since the pinned release adds each value once per attribute
SignalToMetricsConnectorsignaltometricstraces, metrics, logs or profiles to metricsat least one metric; each has a name and exactly one of sum, gauge, histogram or exponential_histogram, with a value; histogram buckets increase; exponential_histogram.max_size is 2 to 16384; an attribute key is set, listed once, and has default_value or optional, not both; a gauge using ExtractGrokPatterns selects one key
import { OtlpReceiver, OtlpExporter, PrometheusExporter, SpanMetricsConnector, Pipeline } from "@intentius/chant-lexicon-otel";
export const otlp = new OtlpReceiver({ protocols: { grpc: { endpoint: "0.0.0.0:4317" } } });
export const tempo = new OtlpExporter({ name: "tempo", endpoint: "tempo:4317" });
export const prom = new PrometheusExporter({ endpoint: "0.0.0.0:8889" });
export const spanmetrics = new SpanMetricsConnector({ dimensions: [{ name: "http.route" }] });
export const traces = new Pipeline({ signal: "traces", receivers: [otlp], exporters: [tempo, spanmetrics] });
export const red = new Pipeline({ signal: "metrics", name: "red", receivers: [spanmetrics], exporters: [prom] });

signaltometrics builds metrics you name from spans, data points, logs or profiles. Each section (spans, datapoints, logs, profiles) is a list of metrics; each metric has a name, optional description and unit, attributes to split by, include_resource_attributes to keep, OTTL conditions (ORed), and exactly one metric type whose value is an OTTL value expression. A histogram takes optional buckets (plain numbers in the unit value returns, default SIGNAL_TO_METRICS_DEFAULT_BUCKETS) and an optional count expression. The TypeScript type allows one metric type per entry; OTEL107 catches the rest, such as an imported config with two. The type follows config/config.go and the README of connector/signaltometricsconnector at collector-contrib v0.130.0, where it is alpha for every signal and has no span event section. It emits delta temporality and aggregates only within each batch it receives, so an exporter that needs cumulative input wants deltatocumulative in front of it. signalToMetricsEntries(config) lists every entry with its signal and the metric types it names.

import { OtlpReceiver, PrometheusExporter, SignalToMetricsConnector, Pipeline } from "@intentius/chant-lexicon-otel";
export const otlp = new OtlpReceiver({ protocols: { grpc: { endpoint: "0.0.0.0:4317" } } });
export const prom = new PrometheusExporter({ endpoint: "0.0.0.0:8889" });
export const genai = new SignalToMetricsConnector({
name: "genai",
spans: [
{
name: "gen_ai.client.operation.duration",
unit: "s",
conditions: ['attributes["gen_ai.operation.name"] != nil'],
attributes: [{ key: "gen_ai.operation.name" }, { key: "gen_ai.request.model", default_value: "unknown" }],
histogram: { buckets: [0.01, 0.1, 1, 10], value: "Double(Microseconds(end_time - start_time)) / 1000000.0" },
},
],
});
export const traces = new Pipeline({ signal: "traces", receivers: [otlp], exporters: [genai] });
export const metrics = new Pipeline({ signal: "metrics", name: "genai", receivers: [genai], exporters: [prom] });

spanMetricsNames(connector, exporter?) returns the names Prometheus serves a spanmetrics connector’s metrics under, read from its namespace, dimensions and histogram unit, and from the prometheus exporter’s namespace and add_metric_suffixes when you pass it. The connector above gives traces_span_metrics_calls_total and traces_span_metrics_duration_milliseconds, with labels service_name, span_name, span_kind and status_code. A query, an SLO or a dashboard built from those names follows a renamed namespace; the grafana lexicon’s RedDashboard reads them this way.

serviceGraphNames(connector, exporter?) does the same for a servicegraph connector. Its names are fixed: traces_service_graph_request_total, traces_service_graph_request_failed_total, and the traces_service_graph_request_server_seconds and traces_service_graph_request_client_seconds histograms. Each carries client, server, connection_type and failed, plus client_<d> and server_<d> for each configured dimension. The prometheus lexicon’s PROM301 and the grafana lexicon’s GRAF118 read these names and the GenAI ones to check queries against the collector configs in the build.

routing names its target pipelines by id string (pipelines: ["traces/tenant-a"]), since those pipelines also list the connector and a const can’t refer to one declared after it.

ClassTypeEndpoints
HealthCheckExtensionhealth_checkendpoint + path, default localhost:13133/
PprofExtensionpprofendpoint, default localhost:1777
ZPagesExtensionzpagesendpoint, default localhost:55679
K8sLeaderElectorExtensionk8s_leader_electornone

k8s_leader_elector elects one leader among collector replicas through a Kubernetes Lease, so a k8s_cluster receiver that names it (k8s_leader_elector: elector.componentId) collects only in the replica holding the lease. lease_name and lease_namespace are required; auth_type defaults to serviceAccount, and lease_duration, renew_deadline and retry_period to 15s, 10s and 2s. OTEL107 checks that both lease fields are set, as the extension’s Validate does, and that lease_duration is greater than renew_deadline and renew_deadline greater than 1.2 times retry_period, which client-go’s leader elector otherwise rejects only when the collector starts. The type follows config.go, factory.go and the README of extension/k8sleaderelector at collector-contrib v0.130.0, where it is alpha and ships in the otelcol-contrib and otelcol-k8s distributions. The collector’s ServiceAccount needs access to leases in coordination.k8s.io in lease_namespace; the k8s lexicon’s OtelCollectorGateway adds that Role when its config enables the extension.

import { K8sClusterReceiver, K8sLeaderElectorExtension, OtlpExporter, Pipeline, Service } from "@intentius/chant-lexicon-otel";
export const elector = new K8sLeaderElectorExtension({ lease_name: "otel-k8s-cluster", lease_namespace: "observability" });
export const cluster = new K8sClusterReceiver({ auth_type: "serviceAccount", k8s_leader_elector: elector.componentId });
export const backend = new OtlpExporter({ endpoint: "backend.observability.svc:4317" });
export const metrics = new Pipeline({ signal: "metrics", receivers: [cluster], exporters: [backend] });
export const service = new Service({ extensions: [elector] });
ClassWhat it emits
Pipelineone entry under service.pipelines, id signal or signal/name
Serviceservice.extensions and service.telemetry; declare at most one

The settings many components share are exported as types: TLSClientSettings, TLSServerSettings, GRPCServerSettings, HTTPServerSettings, GRPCClientSettings, HTTPClientSettings, RetrySettings, QueueSettings, BatchSettings, ExporterHelperSettings, AttributeAction, and for the processors and receivers above OttlErrorMode, TransformStatementGroup, K8sAuthType and MetricToggle. Use them to type a nested block you declare as its own const.

QueueSettings.batch (flush_timeout, min_size, max_size, sizer) turns on batching inside an exporter’s sending_queue at collector v0.130.0, as an alternative to a batch processor in the pipeline. Setting it on an otlp or otlphttp exporter also satisfies OTEL125. The build rejects it on a disabled queue and when max_size is below min_size.

QueueSettings.block_on_overflow makes the sender wait when the queue is full instead of dropping data. It is the collector’s own field name; sending_queue.blocking is not a collector setting, and OTEL107 reports it (the collector would ignore it, so the queue would keep dropping).