Skip to content
WSLDeep Dive Published Updated 8 min readViews unavailable

OpenTelemetry Collector in WSL: Local Pipelines, Queues, and Loss Boundaries

Build a local OpenTelemetry Collector pipeline in WSL, verify OTLP ingestion, and reason about memory limits, queues, retries, and shutdown loss.

The OpenTelemetry Collector is a vendor-neutral service for receiving, processing, and exporting telemetry. Running a local Collector in WSL is useful for validating an application’s OTLP output, testing transformations, and understanding pipeline behavior before a deployment. It is not a production availability architecture. WSL distributions and their services stop when the VM or Windows host stops, and a local Collector’s queues, storage, and receiver endpoints must be configured deliberately.

A Collector configuration defines components and connects them in pipelines. A component must be included in the distribution binary and enabled in the service pipeline before it is active. Core and contrib builds do not necessarily contain the same receivers, processors, exporters, or extensions. Confirm the exact binary and version before diagnosing an “unknown component” error.

Start with a minimal loopback OTLP pipeline

Use the official Collector installation instructions for the selected distribution and architecture. Record the binary name, build distribution, version, and included components. Do not assume a configuration copied from a Kubernetes or vendor-specific package is portable to the core Collector. Keep the configuration in a Linux-side project directory and make every listener and exporter explicit.

A minimal traces pipeline for a local test can receive OTLP and write accepted spans to the debug exporter:

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 127.0.0.1:4317
      http:
        endpoint: 127.0.0.1:4318

exporters:
  debug:
    verbosity: basic

service:
  pipelines:
    traces:
      receivers: [otlp]
      exporters: [debug]

The example binds both protocols to Linux loopback, which is appropriate only for clients that can reach that interface. If a Windows process or another container is the client, establish the actual route and listener scope before changing the bind address. Do not expose a local test receiver broadly to make a connectivity problem disappear.

Start the selected binary with the config path as documented for that build, then inspect startup logs and listening sockets. A successful process start proves only that the configuration parsed and components initialized. Send a known test span from an OTLP client and verify the Collector reports it through the debug exporter. Also send a request to an unused port to confirm the client fails as expected rather than silently using a second endpoint.

Model the pipeline as explicit stages

Receivers accept telemetry; processors transform, filter, sample, or batch it; exporters send it to destinations. Extensions provide operational capabilities but do not automatically join data pipelines. A component that exists in the binary but is absent from service.pipelines is not a configured data path. Keep separate pipelines for traces, metrics, and logs unless the same components are intentionally supported for each signal.

The order of processors matters. Memory limiting should run early so the Collector can apply pressure controls before later processors accumulate more data. Filtering or sampling changes the data set; batching groups telemetry for export and can affect memory. Use the official processor guidance for component order and semantics. Do not copy a trace pipeline into metrics or logs without checking whether each processor supports that signal.

Configuration is an executable dependency graph. Validate component names against the chosen Collector distribution and version, then start the process in a disposable directory. Keep configuration values in version control only when they contain no secrets. Inject credentials and endpoints through a controlled environment mechanism, and avoid debug logging real payloads that may contain personal or business data.

Backpressure, retry, and queue semantics

An exporter may retry transient failures, but retry behavior is bounded by its configured policy and queue capacity. A queue can absorb a short destination outage; it is not infinite storage. When a receiver produces data faster than processors and exporters can complete it, memory pressure, refused requests, queue saturation, and dropped telemetry are possible. Monitor the Collector’s own internal telemetry and logs so the pipeline does not become a silent black hole.

An in-memory queue is lost when the process terminates. A persistent queue requires a storage extension and a writable storage path; it adds local state that must be protected, retained, and tested. Even a persistent queue does not by itself guarantee exactly-once delivery. A destination may accept data before the Collector observes an acknowledgment, leading to retries and duplicates. Consumers and exporters should be evaluated for their own idempotency and acknowledgment behavior.

Test failure paths in a lab: stop the destination, continue sending a bounded stream, observe retries and queue growth, restore the destination, and check whether the backlog drains. Then stop the Collector while data remains queued and inspect the expected loss or persistence behavior. Keep the test volume low enough to avoid filling the WSL VHDX. Record the queue settings, storage mode, restart result, and number of received/exported records.

Memory limiter thresholds and queue sizing should reflect measured payloads and process limits, not copied sample values. A memory limiter can refuse or drop data to protect the process; it does not increase WSL memory. WSL VM memory limits, application RSS, batch size, exporter queue capacity, and destination throughput interact. Change one setting at a time and observe both telemetry delivery and Collector health.

WSL networking and lifecycle boundaries

Test clients inside the same distro first, then test Windows or container clients as separate network paths. localhost forwarding behavior depends on WSL networking mode and host configuration. A successful client call from Linux does not prove that Windows can reach the receiver, and a Windows-side port check does not prove the Collector accepts OTLP with the expected protocol and content type.

If the Collector runs as a systemd service, define its user, config path, restart policy, and storage ownership explicitly. A service being enabled does not keep WSL awake. When the distribution stops, in-flight batches and volatile queues can be lost. If this Collector is part of an actual delivery path, move it to an always-on host and design monitoring, storage, upgrades, and recovery separately.

Use the Collector’s health and internal metrics where supported by the selected build. Compare accepted and exported records, queue depth, refused data, process memory, and exporter failures. A green process status is not equivalent to successful delivery. Likewise, a debug exporter in a local pipeline demonstrates the path to that exporter, not production destination credentials or durability.

Establish a measurable local acceptance test

Build a bounded test with a known number of spans, unique trace identifiers, and a small payload. Record how many the client attempted, how many the receiver accepted, and how many appeared at the exporter. Repeat under normal operation, an intentionally stopped destination, and a Collector restart. These counts identify whether loss occurred at client retry, receiver, processor, queue, or export boundary. Do not infer complete delivery from a single success log line.

Size local queues from measured average payload size and tolerated outage duration, then account for serialization overhead and process memory. A queue sized in item counts is not a byte-accurate disk or memory reservation. Persistent queue storage must have enough filesystem capacity and a recovery policy. In WSL, a growing VHDX can consume Windows disk space even when the Linux filesystem appears separate; monitor both layers during load tests.

The Collector’s own telemetry should be scraped or inspected separately from the application data being processed. This helps identify refused spans, queue saturation, exporter retries, and processor pressure without treating the application stream as its own health signal. If telemetry is exported to the same destination under test, provide a local or alternate diagnostic path so destination failure does not erase the evidence of failure.

Troubleshoot by stage

If startup fails, check YAML structure, component availability, and version-specific configuration fields. If the process starts but the receiver is unreachable, inspect bind address, port ownership, protocol, and WSL path. If it receives spans but exports none, verify the signal pipeline and exporter settings. If data is missing under load, inspect refusal counters, memory pressure, queue capacity, retry logs, and destination health before increasing limits.

Capture sanitized configuration, binary version, startup log, client protocol, and a small known test payload in a reproduction. Avoid dumping production telemetry in a public issue. For upgrades, compare component inventories and validate the config against the new binary in a separate process before replacing a running Collector.

Acceptance criteria

Accept the WSL lab when the Collector distribution and version are recorded, the config uses only available components, OTLP is bound to the intended interface, a known span reaches the expected exporter, and destination failure behavior is measured. Document whether queues are volatile or persistent, how shutdown affects outstanding data, and why WSL is or is not an appropriate runtime for the tested use case.

The Collector in WSL is an excellent pipeline test harness. It is not an availability guarantee, a universal exactly-once transport, or a replacement for production queue and storage design.

Related:

Sources:

Comments