See HAProxy as a connected hop in your distributed traces, not just a black box between services. HAProxy 3.4 and later includes an OpenTelemetry filter that lets your load balancer participate directly in distributed traces, so New Relic can automatically map service relationships between your applications and the HAProxy entity in service maps — no manual configuration required.
This page shows you how to configure the HAProxy OTel filter, its exporter, and the OTel Collector so trace data reaches New Relic. For a look at how tracing works under the hood — extracting and propagating W3C Trace Context through HAProxy — see How it works below.
The frontend application sends a request with a W3C traceparent header.
HAProxy's OTel filter extracts the trace context, creates spans covering the request lifecycle, and injects updated trace context into the request forwarded to the backend.
The backend application receives the request with the propagated trace context and continues the trace.
The frontend, HAProxy, and backend export their spans to an OpenTelemetry Collector, which forwards them to New Relic.
New Relic uses these connected spans to create CALLS relationships:
You can mix instrumentation approaches. For example, an OTel SDK frontend can call through HAProxy to a New Relic APM agent backend, and the relationship chain appears correctly in New Relic.
HAProxy 3.4 or later with the OTel filter enabled. Refer to the HAProxy OTel installation guide for instructions on obtaining a distribution with OTel filter support.
OpenTelemetry Collector (OTel Collector Contrib or NRDOT) running on the same host or accessible from the HAProxy host
Instrumented applications sending requests through HAProxy, using any of the compatible instrumentation approaches listed above
Network access from the collector to New Relic's OTLP endpoint
The traces pipeline below is the same standard setup you would use for any service participating in distributed tracing — not a manual relationship configuration. Once tracing is active, New Relic automatically detects the connected spans and creates service relationships. There is no additional configuration needed for relationships to appear.
Add the filter opentelemetry directive to the frontend section of your haproxy.cfg. This tells HAProxy to apply the OTel filter to incoming requests:
frontend main
bind *:8080
default_backend app_servers
filter opentelemetry id otel config /etc/haproxy/otel.cfg
frontend stats
bind *:8404
stats enable
stats uri /stats
The config parameter points to a separate OTel filter configuration file that defines spans, context propagation, and exporter settings.
The stats frontend enables the HAProxy stats endpoint, which the OTel Collector's haproxyreceiver uses to collect performance metrics. Adjust the bind address and port if needed.
Create the OTel filter configuration file (for example, /etc/haproxy/otel.cfg):
[otel]
otel-instrumentation otel-inst
config /etc/haproxy/otel.yml default
no option disabled
rate-limit 100.0
scopes client_session_start
scopes frontend_http_request
scopes backend_http_request
scopes client_session_end
scopes server_session_start
scopes http_response
scopes server_session_end
otel-scope client_session_start
extract "-ctx" use-headers
span "HAProxy session" parent "-ctx" root
otel-event on-client-session-start
otel-scope frontend_http_request
span "Frontend HTTP request" parent "HAProxy session" kind server
Extracts the incoming W3C traceparent header (extract "-ctx" use-headers), linking HAProxy spans to the calling service's trace.
Creates spans for the full request lifecycle: session start, frontend request processing, backend request forwarding, response handling, and session end.
Injects updated trace context into requests sent to backends (inject "-ctx" use-headers), allowing downstream services to continue the trace.
Traces 100% of requests (rate-limit 100.0). Adjust this value to reduce trace volume in high-throughput environments.
중요
The id value in the filter opentelemetry directive in haproxy.cfg must match the section name in otel.cfg (for example, [otel]).
Create the filter exporter configuration file (for example, /etc/haproxy/otel.yml). This tells the HAProxy OTel filter where to send its trace data:
exporters:
exporter_traces:
type: otlp_grpc
endpoint:"http://localhost:4317/v1/traces"
processors:
processor_batch:
type: batch
providers:
provider_traces:
resources:
-service.name:"YOUR_HAPROXY_SERVICE_NAME"
signals:
traces:
default:
scope_name:"HAProxy OTel filter"
exporters: exporter_traces
processors: processor_batch
providers: provider_traces
Replace YOUR_HAPROXY_SERVICE_NAME with a name that identifies this HAProxy instance (for example, haproxy-prod-lb).
service.name is the standard OpenTelemetry resource attribute that identifies any service participating in distributed tracing — not just HAProxy. Every OTel-instrumented application sets it (via OTEL_SERVICE_NAME), and every New Relic APM agent has the equivalent (app_name). Without it, traces still flow and connect correctly, but spans appear as unknown_service in the UI, which makes them difficult to identify. For more details, see OpenTelemetry resources best practices.
This is a one-time configuration per HAProxy instance. When you add new backend or frontend applications, you don't need to change this file — relationships form automatically through trace context propagation.
The exporter sends traces via gRPC to localhost:4317, where the OTel Collector is listening. Adjust the endpoint if the collector runs on a different host.
Configure the OTel Collector to receive traces from the HAProxy OTel filter and metrics from the HAProxy stats endpoint, and to forward them to New Relic.
This collector configuration includes two pipelines:
Traces pipeline: Receives OTLP trace data from the HAProxy OTel filter and your instrumented applications via gRPC (port 4317) or HTTP (port 4318). This is the same standard traces pipeline you would use for any service sending OTLP data to New Relic.
Metrics pipeline: Uses the haproxyreceiver to collect performance metrics (sessions per second, request rates, backend health) from the HAProxy stats endpoint. These metrics create the HAProxy entity in New Relic with golden metrics.
Both pipelines share these processors:
resourcedetection: Adds host.name and host.id, which are standard resource attributes used to identify hosts across the OpenTelemetry ecosystem.
resource/haproxy: Adds the haproxy.addr attribute, which identifies this HAProxy instance and links the metrics and trace data together under the same HAProxy entity in New Relic.
The http://127.0.0.1:8404/stats value is the conventional HAProxy stats address used in HAProxy's official documentation and matches the haproxy.cfg from Step 1. This is a one-time, static value per HAProxy instance. When you add or remove backend and frontend applications, you don't need to change the collector configuration — relationships form automatically through trace context propagation. Only adjust the haproxy receiver endpoint and resource/haproxy value if your stats endpoint uses a different address, port, or URI — both must always match.
Set the required environment variables and start (or restart) the collector:
Restart HAProxy to load the OTel filter configuration:
bash
$
sudo systemctl restart haproxy
중요
The HAProxy binary must include the OTel filter. If you see errors like unknown keyword 'filter' or unknown keyword 'opentelemetry', your HAProxy build does not include the filter. Refer to the HAProxy OTel installation guide for a compatible distribution.
View your service relationships
Once HAProxy and the collector are running, generate some traffic through your instrumented applications. After a few minutes, verify data is arriving in New Relic:
-- Verify HAProxy trace spans
FROM Span SELECTcount(*)
WHERE service.name ='YOUR_HAPROXY_SERVICE_NAME'
SINCE 10 minutes ago
-- Verify HAProxy metrics
FROM Metric SELECTcount(*)
WHERE metricName LIKE'haproxy.%'
SINCE 10 minutes ago
After trace data is flowing, New Relic automatically creates CALLS relationships between your services and the HAProxy entity. It may take up to 10 minutes for relationships to appear.
WHERE source.entityName ='YOUR_HAPROXY_SERVICE_NAME'
OR target.entityName ='YOUR_HAPROXY_SERVICE_NAME'
SINCE 1day ago
Troubleshooting
Check for these startup errors:
Missing filter support: If you see unknown keyword 'filter' or unknown keyword 'opentelemetry', your HAProxy binary does not include the OTel filter. Refer to the HAProxy OTel installation guide.
Configuration file not found: If you see unable to load OTel configuration, check that the config path in the filter opentelemetry directive is correct and the file exists. Paths are relative to the HAProxy working directory.
Shared library errors: The OTel filter requires the OpenTelemetry C++ SDK shared libraries. Ensure they are installed and discoverable (for example, via LD_LIBRARY_PATH or ldconfig).
Work through these checks in order:
Verify HAProxy started without errors: sudo journalctl -u haproxy -n 50 --no-pager
Check that the OTel filter is loaded. Look for errors mentioning filter, opentelemetry, or otel in the HAProxy logs.
Verify the OTel Collector is running and listening on the port specified in otel.yml: sudo ss -tlnp | grep 4317
Confirm the otel.yml exporter endpoint matches the collector's gRPC listener address.
Check these possible causes:
Allow up to 10 minutes for relationships to appear after the first spans arrive.
Verify that your instrumented applications are sending traces through the collector. Both the HAProxy spans and the application spans must reach New Relic for relationships to form.
Check that your frontend applications propagate W3C traceparent headers. Without trace context propagation, HAProxy spans are not connected to the calling service.
Confirm both the resourcedetection and resource/haproxy processors are included in the collector traces pipeline. The host.id and haproxy.addr attributes are required for HAProxy entity identification.
Verify the metrics pipeline is running with the haproxy receiver. The metrics pipeline creates the HAProxy entity — without it, HAProxy appears as a generic service rather than a dedicated HAProxy entity.
Query to verify both HAProxy and application spans share trace IDs:
FROM Span SELECT uniques(service.name)
WHERE trace.id IN(
SELECT uniques(trace.id)FROM Span
WHERE service.name ='YOUR_HAPROXY_SERVICE_NAME'
SINCE 10 minutes ago LIMIT5
)
SINCE 10 minutes ago
You should see your HAProxy service name alongside your application service names.
Consider these possible causes:
Send traces from each instrumented application through the same OTel Collector (or directly to New Relic) so that span data for all services reaches the same account.
For applications using New Relic APM agents, verify that distributed tracing is enabled and the agent is connected.
For OTel SDK applications, verify the OTLP exporter is configured to send to the collector.
Allow additional time, since relationships for services with lower traffic volume may take longer to appear.
Next steps
Service maps — visual exploration of entity relationships