Automated summary
This skill helps author, review, and debug OpenTelemetry Collector configurations, keeping track of how receivers, processors, exporters, and connectors must be wired into the service block.
Strengths
- Encodes the classic Collector traps: a component declared but never referenced in a pipeline, or a pipeline that does not match the signal
- Explicitly separates contrib-only components (prometheus, hostmetrics, filelog, tail_sampling, spanmetrics…) from core ones
- Enforces a meaningful processor order, with memory_limiter first and batch last
- Provides a three-question workflow (signals, sources, destinations) before any YAML is generated
Limitations
- The supplied content cuts off mid-way through the processor-ordering section, so details on batch and later processors are not covered
- The skill focuses on config structure and diagnosis; it does not address deployment, sizing, or resource allocation for the Collector
- Examples stay within what the named components describe, leaving multi-tenant setups and advanced routing uncovered
Reach for it whenever you need to generate or fix an otelcol config file, or work out why a Collector starts up but no data ever arrives.
Skip it for application-side instrumentation questions (OpenTelemetry SDKs) or for operating an observability backend, which fall outside Collector configuration.
Security analysis
SafeThis is a pure documentation/guidance skill for authoring OpenTelemetry Collector YAML configs. It contains no executable scripts, no curl|sh piping, no file deletion, no credential handling, and no instructions to disable safety controls. The only command mentioned is the benign `otelcol validate --config=...`, and it correctly recommends env-var expansion (`${env:VAR}`) for secrets rather than hard-coding them. With no declared tool permissions and no privileged operations, listing this poses no meaningful execution risk.
No concerns found
How this analysis is madeExamples
Write an otelcol-contrib config that receives OTLP traces and metrics from our services, adds hostmetrics, samples 10% of traces with tail_sampling, and exports to Tempo over OTLP plus Prometheus remote write.My Collector starts without errors but no traces reach Jaeger. Here is my config — tell me what's wrong: [paste config]Can I run this config with the core otel/opentelemetry-collector image, or do I need contrib? It uses the prometheus receiver, the transform processor and the spanmetrics connector.name: otel-collector-config description: >- Use when authoring, debugging, or reviewing an OpenTelemetry Collector (otelcol) configuration — defining receivers/processors/exporters/connectors, wiring service pipelines, choosing between the core and contrib distributions, or exporting to OTLP/Prometheus/Loki/Tempo/Mimir. Also use when a Collector starts but no data arrives, a component is rejected at startup, or metrics lack expected labels. Triggers on "otelcol", "otel collector config", "collector pipeline", "receivers/processors/exporters", "memory_limiter", "otlp exporter", "prometheusremotewrite", "spanmetrics", "tail_sampling".
OpenTelemetry Collector config — doctor
Generate correct configs from a plain-English description, and diagnose broken ones. The Collector is a small set of concepts with a lot of sharp edges; this skill encodes the edges so the output validates on the first try.
Mental model (get this right and everything follows)
A Collector config has four component blocks plus a service block that wires
them:
receivers: # where data comes IN (otlp, prometheus, hostmetrics, filelog, kafka…)
processors: # what happens in the MIDDLE, in order (memory_limiter, batch, transform…)
exporters: # where data goes OUT (otlp, otlphttp, debug, prometheus, prometheusremotewrite…)
connectors: # bridge one pipeline's OUTPUT into another's INPUT (spanmetrics, routing…)
extensions: # collector-level features, not in the data path (health_check, pprof, zpages…)
service:
extensions: [health_check]
pipelines:
traces: { receivers: [...], processors: [...], exporters: [...] }
metrics: { receivers: [...], processors: [...], exporters: [...] }
logs: { receivers: [...], processors: [...], exporters: [...] }
telemetry: { ... } # the Collector's OWN logs/metrics
The #1 rule everyone violates: defining a component under receivers: /
processors: / exporters: does nothing on its own. A component only runs
if it is referenced inside a service.pipelines.<signal> list. A config can be
"valid" yet do nothing because a pipeline was never wired. Always check the
service block last, and confirm every component you defined is actually used
(and every name used is actually defined — that one fails validation).
Pipelines are per-signal. traces, metrics, logs are separate
pipelines. A receiver/exporter must support the signal of the pipeline it sits
in (e.g. the prometheus receiver is metrics-only; putting it in a traces
pipeline fails). You may run multiple named pipelines of the same signal
(metrics/internal, metrics/app).
Workflow
1. Pin the three questions
- Signals? traces / metrics / logs (any subset).
- Sources (receivers)? app via OTLP? scrape Prometheus targets? host metrics? tail log files? Kafka?
- Destinations (exporters)? an OTLP backend (Tempo/Jaeger/vendor)? Prometheus (pull) or remote-write (push)? Loki? Mimir?
2. Choose the distribution — core vs contrib (this trips people constantly)
Many common components ship only in otelcol-contrib, not core otelcol:
prometheus receiver, hostmetrics, filelog, kafka, resourcedetection,
transform/filter (OTTL) processors, tail_sampling, the spanmetrics
connector, prometheusremotewrite/loki exporters. If the config uses any of
these, it needs the contrib image (otel/opentelemetry-collector-contrib)
or a custom build via the OpenTelemetry Collector Builder (ocb). Calling for a
contrib component on the core image is a startup crash, not a YAML error — flag it.
3. Order processors correctly (order is significant and load-bearing)
Processors run in the listed order. The canonical safe order:
processors: [memory_limiter, <resource/detection>, <sampling/filter/transform>, batch]
memory_limitergoes FIRST. It must see data before anything buffers it, otherwise it can't shed load. Puttingbatchbefore it defeats the purpose.batchgoes LAST (just before export) so it batches the final shape.tail_sampling(traces) must come beforebatch, and needs whole traces — don't shard the same trace across replicas without a load-balancing exporter in front.
4. Pick exporters deliberately
otlp= OTLP over gRPC (default 4317).otlphttp= OTLP over HTTP (4318). Match the backend's port/protocol.debugis the console exporter (useverbosity: detailedwhile debugging). The oldloggingexporter is removed/deprecated → usedebug.- Metrics to Prometheus:
prometheus= Collector exposes a/metricsendpoint for Prometheus to scrape (pull).prometheusremotewrite= Collector pushes to a remote-write endpoint (Mimir/Thanos/Cortex/Prometheus--web.enable-remote-write-receiver). Don't confuse pull vs push. - Loki: the dedicated
lokiexporter was removed from contrib — send OTLP to Loki's native OTLP endpoint viaotlphttp(endpoint: http://loki:3100/otlp). - Tempo/Jaeger: send via
otlp/otlphttp— thejaegerexporter is gone (Jaeger ingests OTLP natively). Thejaegerreceiver still exists (beta, in core+contrib) for ingesting legacy Jaeger-protocol spans during a migration; don't call it removed.
5. Always include the safety/ops basics
memory_limiterprocessor in every pipeline that can be flooded.health_checkextension (and wire it intoservice.extensions).- For secrets/endpoints use env expansion:
endpoint: ${env:OTLP_ENDPOINT}(note theenv:prefix — bare${VAR}is deprecated syntax). - Set
service.telemetry.logs.leveland, if needed, expose the Collector's own metrics.
6. Validate before declaring done
Never hand back a config you haven't validated. The Collector has a built-in validator that loads and type-checks the full config without starting it:
otelcol validate --config=config.yaml # core
otelcol-contrib validate --config=config.yaml # contrib
The bundled scripts/validate.sh wraps this (auto-detects the contrib binary,
falls back to a Docker run if no local binary). If otelcol isn't available,
say so explicitly rather than claiming the config is validated.
Fixing an existing config — run this checklist
When handed a broken or "it starts but nothing arrives" config, check in order:
- Unwired components — every receiver/processor/exporter defined but not referenced in any
service.pipelines.*? (silent no-op) - Undefined references — a name used in a pipeline that isn't defined above? (validation error)
- Signal mismatch — a metrics-only receiver in a traces pipeline, etc.
- core vs contrib — a contrib-only component on the core image? (crash on start)
- Processor order —
batchbeforememory_limiter?memory_limiternot first? - pull vs push exporter —
prometheuswhereprometheusremotewritewas meant (or vice-versa)? - Removed components —
loggingexporter (→debug),lokiexporter (→otlphttp),jaegerexporter (→otlp; the jaeger receiver is still fine), bare${VAR}env syntax (→${env:VAR}). - Endpoint/protocol — gRPC vs HTTP port mismatch (4317 vs 4318);
tls/insecureset correctly for the environment. - Endpoint binding — receiver bound to
localhostwhen traffic comes from other containers (needs0.0.0.0), or bound to0.0.0.0in a context where that's a security concern.
State the diagnosis as "what was wrong → why it failed → the fix", then output the corrected config and validate it.
The hard parts — get these right every time (see references/advanced.md)
A capable model already handles the basics above. These six are the ones it gets
inconsistently right; treat them as load-bearing and pull the exact patterns
from references/advanced.md:
- OTTL statement form (
transform/filterprocessors). The function syntax itself —set(attributes["x"], "y") where <cond>,delete_key(...),replace_pattern(...)— is usually recalled correctly. What isn't: there are two forms with different path syntax, and mixing them fails to parse. Flat list → prefix every path (span.attributes[...]); inside acontext: spanblock → write paths bare (attributes[...]). Pick one per statement list. Seereferences/advanced.md§1. Always seterror_mode; regexes are RE2 (no lookahead). - spanmetrics (and any connector) is wired in TWO pipelines — as an exporter in the source pipeline and a receiver in the destination pipeline. Wiring it once silently produces no metrics (or a validation error).
- Sampling must sit downstream of metric generation. If
tail_sampling(or any sampler) runs before thespanmetricsconnector, RED metrics are computed from only the surviving fraction — request rate is wrong by the sampling ratio and nothing looks broken. Fork instead: the ingest pipeline exports to[spanmetrics, forward/sampled]; a second traces pipeline receivesforward/sampled, appliestail_sampling, and exports to the trace backend. spanmetrics must see 100% of spans. resource_to_telemetry_conversionis a trade-off, not a default-on. Off (the default), resource attributes land only on thetarget_infoseries — sosum by (service_name)returns nothing and you must join (... * on (job, instance) group_left(service_name) target_info). On, it copies every resource attribute onto every series — includingk8s.pod.name,host.id,container.id, multiplying series count per pod. Rule: enable it only after dropping the high-cardinality resource attributes; otherwise leave it off and keeptarget_info: enabled: truefor the join. State which you chose and why.tail_samplingat >1 replica needs aloadbalancingtier keyed bytraceID, so all spans of a trace reach the same sampler instance. Tail-sampling directly behind a plain load balancer is broken sampling.tail_samplinggoes beforebatch.- Exporter reliability — and the queue key is per-exporter. Production exporters
need
retry_on_failureplus a queue, but the key differs:otlp/otlphttpusesending_queue(addstorage: file_storage/...when data loss is unacceptable), whileprometheusremotewriteusesremote_write_queueand rejectssending_queueat startup. If validation rejects a queue key, look up that exporter's own key — do not conclude the exporter has no queue and ship it with retry only. Defaults drop data on a transient backend blip. Durability differs too:remote_write_queueis memory-only (it takes nostorage:), so a restart loses the backlog — but that does not mean the exporter has no on-disk option.prometheusremotewritehas its ownwal:(directory,buffer_size,truncate_frequency). For survive-a-restart, usewalhere, or move the path tootlphttp+sending_queue.storageagainst an OTLP-capable backend.
When the request touches any of these, encode the pattern explicitly rather than trusting recall — that's the difference this skill is for.
References
references/components.md— curated catalog of the most-used receivers / processors / exporters / connectors with the gotcha for each, and the core-vs-contrib split.references/advanced.md— the hard parts in depth: OTTL patterns, spanmetrics dual-wiring,resource_to_telemetry_conversion, tail_sampling load-balancing topology, exporter reliability.examples/— a before/after pair (broken → corrected, validated) andspanmetrics-config.yaml, a validated advanced config (spanmetrics connector + OTTL + remote-write labels + retry/queue).
Output discipline
- Emit valid YAML only inside config blocks — no
...placeholders that won't parse. - Before emitting, cross-check every name in
service.pipelinesagainst the blocks above it. Connectors are the usual miss: they appear in two pipelines, so it's easy to referenceforward/xorspanmetricswithout ever declaring it underconnectors:. A config that needs a "one thing to fix before you deploy" footnote is a failed answer. - Comment the non-obvious lines (why
memory_limiteris first, why this exporter). - Prefer the smallest config that satisfies the request; don't bolt on components the user didn't ask for.
- If a component is contrib-only, say so and name the image/build needed.
From the file to a first result
The download contains exactly the content displayed on this page. This copy may differ from the latest version in the source repository.
View the source and supporting filesThis download contains SKILL.md only. Any scripts, references, templates and dependencies are not included. Get the required files from the source, preserving their directory structure, before continuing.
1. Download the file
Download SKILL.mdFrom the root of a test project, save the file as .skill-downloads/otel-collector-config-doctor-mrwakgit/SKILL.md, or use the command below. This folder is for inspecting the skill before installation.
Command for macOS/Linux or WSL: requires a POSIX shell and curl. On Windows without WSL, use the download button and create the folder manually.
mkdir -p '.skill-downloads/otel-collector-config-doctor-mrwakgit' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/otel-collector-config-doctor-mrwakgit/download' --output '.skill-downloads/otel-collector-config-doctor-mrwakgit/SKILL.md.part' && mv '.skill-downloads/otel-collector-config-doctor-mrwakgit/SKILL.md.part' '.skill-downloads/otel-collector-config-doctor-mrwakgit/SKILL.md'2. Check prerequisites
Read SKILL.md before using it. If it references scripts or external services, inspect them and prepare the required access in your test environment.
No recognized prerequisites section in this file. This does not mean it is self-contained: libraries, tools and access requirements may be mentioned elsewhere in the content or source repository.
The platforms on this page are catalog indications. The paths below follow tool documentation; they do not prove this skill has been run in those tools. No minimum tool version is confirmed for this listing.
3. Load the skill
After inspection, copy the complete folder into your project using one of the commands below, then open a new tool session. The command stops if a folder with the same name already exists: compare the files before replacing it.
Claude Code
test -f '.skill-downloads/otel-collector-config-doctor-mrwakgit/SKILL.md' && test -s '.skill-downloads/otel-collector-config-doctor-mrwakgit/SKILL.md' && mkdir -p '.claude/skills' && test ! -e '.claude/skills/otel-collector-config' && cp -R '.skill-downloads/otel-collector-config-doctor-mrwakgit' '.claude/skills/otel-collector-config'Cursor
test -f '.skill-downloads/otel-collector-config-doctor-mrwakgit/SKILL.md' && test -s '.skill-downloads/otel-collector-config-doctor-mrwakgit/SKILL.md' && mkdir -p '.cursor/skills' && test ! -e '.cursor/skills/otel-collector-config' && cp -R '.skill-downloads/otel-collector-config-doctor-mrwakgit' '.cursor/skills/otel-collector-config'Codex
test -f '.skill-downloads/otel-collector-config-doctor-mrwakgit/SKILL.md' && test -s '.skill-downloads/otel-collector-config-doctor-mrwakgit/SKILL.md' && mkdir -p '.agents/skills' && test ! -e '.agents/skills/otel-collector-config' && cp -R '.skill-downloads/otel-collector-config-doctor-mrwakgit' '.agents/skills/otel-collector-config'OpenSkills
OpenSkills must already be installed. The local install/read procedure is checked with OpenSkills 1.5.0, which requires Node.js ≥ 20.6.0. Catalog slugs are not resolved automatically.
Official OpenSkills installationopenskills install './.skill-downloads/otel-collector-config-doctor-mrwakgit'openskills read 'otel-collector-config-doctor-mrwakgit'Reading should display the installed file content and its base directory. It does not run the skill or install its dependencies.
For an agent that reads AGENTS.md, then sync the index. This command changes AGENTS.md: review the diff before using it.
openskills syncManual method or another tool: attach SKILL.md to a conversation, or open it in an agent that can read files. Include any required supporting resources. No universal folder is recognized by every tool.
4. Try a first task
Use a short, synthetic input: an API endpoint, a small document or an interface brief. In a new conversation, attach the file or give the agent its path, then adapt this request:
Read .skill-downloads/otel-collector-config-doctor-mrwakgit/SKILL.md and apply its instructions to this example: [describe a test input]. Identify any missing files, dependencies or access. Produce the result requested by the skill without inventing data or running unreviewed scripts.Expected result: output matching the skill instructions, or a precise list of missing prerequisites. A read confirmation alone does not validate a first use. If an external resource is unavailable, that path remains untested.
Configure a Chat Channel with SecretRefs
DevOps
Set up chat channels using non-interactive commands, with secrets only as SecretRefs. Covers gather, mutate, repair, and prove steps for reliable delivery.
Investigate ClickHouse CI Failures
DevOps
Investigate a ClickHouse CI failure end-to-end from a PR or S3 report URL. Fetches failed tests, classifies flaky vs real regression, and checks for existing issues/fixes.
Ansible PR Review
DevOps
Reviews an Ansible PR following the project's standardized process, including changelog checks, test coverage validation, and feedback tracking.