OpenTelemetry Collector (in front of the plugin)
hermes-otel exports OTLP with headers: fixed ones from the config, or ones a
headers_helper command mints. Some
destinations cannot be reached that way: Azure Monitor's OTLP endpoints want a
Microsoft Entra bearer token, AWS wants a SigV4 signature on every request,
Google Cloud wants OAuth. The answer is the same for all of them: run an
OpenTelemetry Collector next to
Hermes, point the plugin at it with the generic otlp type,
and let the Collector's exporter do the auth. The repo ships one such Collector
as docker-compose/collector/ with a target per destination, plus a default
target that prints every span, metric and log record to docker logs
(#368).
docker compose -f docker-compose/collector/docker-compose.yaml up -d # COLLECTOR_TARGET=debug
docker logs -f hermes-otel-collector
backends:
- type: otlp
name: collector
endpoint: http://localhost:4448/v1/traces # /v1/metrics and /v1/logs are derived
metrics: true # the otlp default, spelled out
logs: true # the otlp default, spelled out
capture_logs: true # log export is off until this is set
The compose file publishes only the Collector's OTLP/HTTP receiver (host port
4448). A type: otlp entry can also use OTLP/gRPC (protocol: grpc), but this
stack does not open a gRPC port.
Targets
COLLECTOR_TARGET picks a file under docker-compose/collector/targets/,
merged on top of the base config as a second --config flag. Credentials come
from the environment; the compose header lists every variable.
| Target | Where the signals go | Credentials | Status (2026-10-11, contrib 0.162.0) |
|---|---|---|---|
debug (default) | the container's stdout, COLLECTOR_DEBUG_VERBOSITY = basic / normal / detailed | none | verified with one Hermes turn: Traces batches of 4 + 1 spans, a Metrics batch of 24 metrics, Logs batches with each record's resource, scope and body |
otlphttp | any OTLP/HTTP backend at OTLP_TARGET_ENDPOINT (one of the repo's stacks via host.docker.internal, or a vendor) | none; copy the file to add a header | verified into otel-desktop-viewer: one turn added 1 trace / 5 spans, 26 log records and 74 metric data points, no errors on either side |
azuremonitor | Azure Monitor / Application Insights via azure_monitor (beta: traces, metrics, logs), with cumulative_to_delta on metrics | APPLICATIONINSIGHTS_CONNECTION_STRING | documented, not verified (needs an Azure subscription; #228) |
aws | X-Ray (awsxray, beta), CloudWatch metrics as EMF (awsemf, beta), CloudWatch Logs (awscloudwatchlogs, alpha) | AWS_REGION, the SDK's key variables, AWS_LOG_GROUP | documented, not verified (needs an AWS account) |
googlecloud | Cloud Trace, Monitoring and Logging via googlecloud (beta) | GOOGLE_CLOUD_PROJECT, GCP_CREDENTIALS_FILE | documented, not verified (needs a GCP project) |
All five configurations pass the image's validate command; the folder's
README
has the command.
What to know
- One hop removed. The plugin's
debug.logrecords the Collector's 200 (export collector: N span(s) -> SUCCESS) whatever happens next. Exporter errors, retries and drops are indocker logs hermes-otel-collectoronly. - Temporality. The plugin emits cumulative metrics. Application Insights
expects delta, so the
azuremonitortarget converts; AWS and Google Cloud take cumulative. Datadog (#226) has the same requirement if you add a target. - Env substitution is for values.
${env:X}works in a header's value, not its name; a target that needs a custom header name is a copied file. - Ports 4448 (OTLP/HTTP) and 13133 (health) collide with nothing else in the repo. The image is distroless: check health from the host.
When not to use it
Every backend with its own page here takes the plugin's OTLP/HTTP directly, and
the explicit types (overview) add the headers, paths and
signal defaults each one needs. A token that merely expires (a Google Cloud access
token, a vault-issued OIDC token, a rotated key) no longer needs it either: a
backend entry's headers_helper runs a
command that mints the headers and re-runs it on a 401/403. Reach for the
Collector when the destination needs a signature over the request (AWS SigV4),
when you need processing the plugin does not do
(sampling, redaction beyond content_capture, temporality conversion), or when
you want to see the raw export without a backend at all.