NAME
Punk::OpenTelemetry::Exporter - OTLP over HTTP
SYNOPSIS
my $exp = Punk::OpenTelemetry::Exporter->new(
endpoint => 'http://localhost:4318',
protocol => 'http/protobuf',
headers => { 'x-api-key' => $key },
);
my $bytes = $exp->encode(traces => $payload);
DESCRIPTION
The OTLP/HTTP transport: endpoint resolution, what a response means, the partial-success readers, Retry-After and the backoff policy.
The object is a blessed hash and stays one, with the keys new has always set. $e->{protocol} and $e->{stats}{dropped}++ are part of the interface, not an implementation detail that happened to be visible.
Endpoints
endpoint => 'http://collector:4318' # /v1/traces is APPENDED
endpoints => { traces => 'https://x/ingest' } # used EXACTLY as given
That asymmetry is in the spec and surprises everybody once. A per-signal endpoint keeps whatever path it has, because collectors are routinely deployed behind a path prefix and appending to it would break every one of them.
What a response means
2xx is success - unless the body carries a
partial_successnaming rejected spans, which is not a failure and not retryable, but has to be counted. Data silently disappearing while every dashboard stays green is the worst failure mode this component has.429, 502, 503, 504 are retryable, honouring
Retry-After.Everything else is permanent. Drop it, count it, and do not spend the next hour asking a collector that has already said no.
Backoff
Exponential from one second to a thirty second ceiling, with full jitter. The jitter is not decoration: a fleet of workers that all failed at the same moment and all back off by the same amount retries in a thundering herd, which is how a collector that was briefly slow stays down. backoff is pure, so the policy is tested directly rather than inferred from timings.
METHODS
new(%opt)
endpoint, endpoints, protocol (http/protobuf or http/json), headers, timeout (default 10), compression (none or gzip), max_retries (default 5), ua. An unknown protocol croaks here rather than at the first export. Without a ua one is built: Fetch->new at the configured timeout.
encode($signal, $payload)
The payload as bytes for the configured protocol.
backoff($attempt, $retry_after)
The delay before attempt $attempt. A Retry-After from the server wins outright.
stats
A copy of the counters: what was exported, rejected, dropped, retried, and how many attempts failed. A telemetry layer that cannot report its own losses is asking to be trusted for no reason.
SEE ALSO
Punk::OpenTelemetry::GRPC, the same job over gRPC, and Punk::OpenTelemetry::Encode, which renders what this sends. Punk::Plugin::OpenTelemetry is what drives it, and Punk::OpenTelemetry::Config documents the OTEL_EXPORTER_OTLP_* variables that configure it.
AUTHOR
LNATION <email@lnation.org>
LICENSE AND COPYRIGHT
This software is Copyright (c) 2026 by LNATION <email@lnation.org>.
This is free software, licensed under:
The Artistic License 2.0 (GPL Compatible)