From d8e69f07dc01915aac3cbd24658ef6e3baefa2a5 Mon Sep 17 00:00:00 2001 From: Miroslav Zagorac Date: Tue, 27 Jan 2026 13:02:59 +0100 Subject: [PATCH] MINOR: otel: test: added test and benchmark suite for the OTel filter Added a test suite under addons/otel/test/ for the OpenTelemetry filter. Five scenarios exercise different filter capabilities: standalone (sa) covers all hook points including idle-timeout heartbeats, metrics and log records; compact (cmp) covers the full request/response lifecycle with ACL-based error handling; context (ctx) tests explicit inject/extract propagation through numbered context variables; frontend/backend (fe/be) tests distributed tracing across two HAProxy instances; and empty tests bare filter initialisation with no active scopes. A performance benchmarking script (test-speed.sh) uses wrk to measure throughput and latency at different rate-limit settings (100% through 0%, disabled, and filter-off). Each scenario includes comprehensive YAML exporter definitions covering OTLP file/gRPC/HTTP, ostream, memory, Zipkin, and Elasticsearch backends. --- addons/otel/test/be/haproxy.cfg | 19 +++ addons/otel/test/be/otel.cfg | 61 +++++++ addons/otel/test/be/otel.yml | 246 ++++++++++++++++++++++++++++ addons/otel/test/cmp/haproxy.cfg | 22 +++ addons/otel/test/cmp/otel.cfg | 81 +++++++++ addons/otel/test/cmp/otel.yml | 246 ++++++++++++++++++++++++++++ addons/otel/test/copy-yml.sh | 24 +++ addons/otel/test/ctx/haproxy.cfg | 28 ++++ addons/otel/test/ctx/otel.cfg | 196 ++++++++++++++++++++++ addons/otel/test/ctx/otel.yml | 246 ++++++++++++++++++++++++++++ addons/otel/test/empty/haproxy.cfg | 19 +++ addons/otel/test/empty/otel.cfg | 2 + addons/otel/test/empty/otel.yml | 246 ++++++++++++++++++++++++++++ addons/otel/test/fe/haproxy.cfg | 19 +++ addons/otel/test/fe/otel.cfg | 73 +++++++++ addons/otel/test/fe/otel.yml | 246 ++++++++++++++++++++++++++++ addons/otel/test/haproxy-common.cfg | 19 +++ addons/otel/test/index.html | 1 + addons/otel/test/run-cmp.sh | 16 ++ addons/otel/test/run-ctx.sh | 16 ++ addons/otel/test/run-fe-be.sh | 50 ++++++ addons/otel/test/run-sa.sh | 16 ++ addons/otel/test/sa/haproxy.cfg | 28 ++++ addons/otel/test/sa/otel.cfg | 180 ++++++++++++++++++++ addons/otel/test/sa/otel.yml | 246 ++++++++++++++++++++++++++++ addons/otel/test/test-speed.sh | 157 ++++++++++++++++++ 26 files changed, 2503 insertions(+) create mode 100644 addons/otel/test/be/haproxy.cfg create mode 100644 addons/otel/test/be/otel.cfg create mode 100644 addons/otel/test/be/otel.yml create mode 100644 addons/otel/test/cmp/haproxy.cfg create mode 100644 addons/otel/test/cmp/otel.cfg create mode 100644 addons/otel/test/cmp/otel.yml create mode 100755 addons/otel/test/copy-yml.sh create mode 100644 addons/otel/test/ctx/haproxy.cfg create mode 100644 addons/otel/test/ctx/otel.cfg create mode 100644 addons/otel/test/ctx/otel.yml create mode 100644 addons/otel/test/empty/haproxy.cfg create mode 100644 addons/otel/test/empty/otel.cfg create mode 100644 addons/otel/test/empty/otel.yml create mode 100644 addons/otel/test/fe/haproxy.cfg create mode 100644 addons/otel/test/fe/otel.cfg create mode 100644 addons/otel/test/fe/otel.yml create mode 100644 addons/otel/test/haproxy-common.cfg create mode 100644 addons/otel/test/index.html create mode 100755 addons/otel/test/run-cmp.sh create mode 100755 addons/otel/test/run-ctx.sh create mode 100755 addons/otel/test/run-fe-be.sh create mode 100755 addons/otel/test/run-sa.sh create mode 100644 addons/otel/test/sa/haproxy.cfg create mode 100644 addons/otel/test/sa/otel.cfg create mode 100644 addons/otel/test/sa/otel.yml create mode 100755 addons/otel/test/test-speed.sh diff --git a/addons/otel/test/be/haproxy.cfg b/addons/otel/test/be/haproxy.cfg new file mode 100644 index 000000000..3860f9f62 --- /dev/null +++ b/addons/otel/test/be/haproxy.cfg @@ -0,0 +1,19 @@ +global + stats socket /tmp/haproxy-be.sock mode 666 level admin + +listen stats + mode http + bind *:8002 + stats uri / + stats admin if TRUE + stats refresh 10s + +frontend otel-test-be-frontend + bind *:11080 + default_backend servers-backend + + # OTel filter + filter opentelemetry id otel-test-be config be/otel.cfg + +backend servers-backend + server server-1 127.0.0.1:8000 diff --git a/addons/otel/test/be/otel.cfg b/addons/otel/test/be/otel.cfg new file mode 100644 index 000000000..1f26f4698 --- /dev/null +++ b/addons/otel/test/be/otel.cfg @@ -0,0 +1,61 @@ +[otel-test-be] + otel-instrumentation otel-test-instrumentation + config be/otel.yml +# log localhost:514 local7 debug + option dontlog-normal + option hard-errors + no option disabled + + scopes frontend_http_request + scopes backend_tcp_request + scopes backend_http_request + scopes client_session_end + + scopes server_session_start + scopes tcp_response + scopes http_response + scopes server_session_end + + otel-scope frontend_http_request + extract "otel-ctx" use-headers + span "HAProxy session" parent "otel-ctx" root + baggage "haproxy_id" var(sess.otel.uuid) + span "Client session" parent "HAProxy session" + span "Frontend HTTP request" parent "Client session" + attribute "http.method" method + attribute "http.url" url + attribute "http.version" str("HTTP/") req.ver + otel-event on-frontend-http-request + + otel-scope backend_tcp_request + span "Backend TCP request" parent "Frontend HTTP request" + finish "Frontend HTTP request" + otel-event on-backend-tcp-request + + otel-scope backend_http_request + span "Backend HTTP request" parent "Backend TCP request" + finish "Backend TCP request" + otel-event on-backend-http-request + + otel-scope client_session_end + finish "Client session" + otel-event on-client-session-end + + otel-scope server_session_start + span "Server session" parent "HAProxy session" + finish "Backend HTTP request" + otel-event on-server-session-start + + otel-scope tcp_response + span "TCP response" parent "Server session" + otel-event on-tcp-response + + otel-scope http_response + span "HTTP response" parent "TCP response" + attribute "http.status_code" status + finish "TCP response" + otel-event on-http-response + + otel-scope server_session_end + finish * + otel-event on-server-session-end diff --git a/addons/otel/test/be/otel.yml b/addons/otel/test/be/otel.yml new file mode 100644 index 000000000..374b87187 --- /dev/null +++ b/addons/otel/test/be/otel.yml @@ -0,0 +1,246 @@ +exporters: + exporter_traces_otlp_file: + type: otlp_file + thread_name: "OTLP/file trace" + file_pattern: "__be_traces_log-%F-%N" + alias_pattern: "__traces_log-latest" + flush_interval: 30000000 + flush_count: 256 + file_size: 134217728 + rotate_size: 5 + + exporter_traces_otlp_grpc: + type: otlp_grpc + thread_name: "OTLP/gRPC trace" + endpoint: "http://localhost:4317/v1/traces" + use_ssl_credentials: false +# ssl_credentials_cacert_path: "" +# ssl_credentials_cacert_as_string: "" +# ssl_client_key_path: "" +# ssl_client_key_string: "" +# ssl_client_cert_path: "" +# ssl_client_cert_string: "" +# timeout: 10 +# user_agent: "" +# max_threads: 0 +# compression: "" +# max_concurrent_requests: 0 + + exporter_traces_otlp_http: + type: otlp_http + thread_name: "OTLP/HTTP trace" + endpoint: "http://localhost:4318/v1/traces" + content_type: json + json_bytes_mapping: hexid + debug: false + timeout: 10 + http_headers: + - X-OTel-Header-1: "OTLP HTTP traces test header #1" + - X-OTel-Header-2: "OTLP HTTP traces test header #2" + max_concurrent_requests: 64 + max_requests_per_connection: 8 + ssl_insecure_skip_verify: true +# ssl_ca_cert_path: "" +# ssl_ca_cert_string: "" +# ssl_client_key_path: "" +# ssl_client_key_string: "" +# ssl_client_cert_path: "" +# ssl_client_cert_string: "" +# ssl_min_tls: "" +# ssl_max_tls: "" +# ssl_cipher: "" +# ssl_cipher_suite: "" +# compression: "" + + exporter_traces_dev_null: + type: ostream + filename: /dev/null + + exporter_traces_ostream: + type: ostream + filename: __be_traces + + exporter_traces_memory: + type: memory + buffer_size: 256 + + exporter_traces_zipkin: + type: zipkin + endpoint: "http://localhost:9411/api/v2/spans" + format: json + service_name: "zipkin-service" +# ipv4: "" +# ipv6: "" + + exporter_metrics_otlp_file: + type: otlp_file + thread_name: "OTLP/file metr" + file_pattern: "__be_metrics_log-%F-%N" + alias_pattern: "__metrics_log-latest" + flush_interval: 30000000 + flush_count: 256 + file_size: 134217728 + rotate_size: 5 + + exporter_metrics_otlp_grpc: + type: otlp_grpc + thread_name: "OTLP/gRPC metr" + endpoint: "http://localhost:4317/v1/metrics" + use_ssl_credentials: false + + exporter_metrics_otlp_http: + type: otlp_http + thread_name: "OTLP/HTTP metr" + endpoint: "http://localhost:4318/v1/metrics" + content_type: json + debug: false + timeout: 10 + http_headers: + - X-OTel-Header-1: "OTLP HTTP metrics test header #1" + - X-OTel-Header-2: "OTLP HTTP metrics test header #2" + max_concurrent_requests: 64 + max_requests_per_connection: 8 + ssl_insecure_skip_verify: true + + exporter_metrics_dev_null: + type: ostream + filename: /dev/null + + exporter_metrics_ostream: + type: ostream + filename: __be_metrics + + exporter_metrics_memory: + type: memory + buffer_size: 256 + + exporter_logs_otlp_file: + type: otlp_file + thread_name: "OTLP/file logs" + file_pattern: "__be_logs_log-%F-%N" + alias_pattern: "__logs_log-latest" + flush_interval: 30000000 + flush_count: 256 + file_size: 134217728 + rotate_size: 5 + + exporter_logs_otlp_grpc: + type: otlp_grpc + thread_name: "OTLP/gRPC logs" + endpoint: "http://localhost:4317/v1/logs" + use_ssl_credentials: false + + exporter_logs_otlp_http: + type: otlp_http + thread_name: "OTLP/HTTP logs" + endpoint: "http://localhost:4318/v1/logs" + content_type: json + debug: false + timeout: 10 + http_headers: + - X-OTel-Header-1: "OTLP HTTP logs test header #1" + - X-OTel-Header-2: "OTLP HTTP logs test header #2" + max_concurrent_requests: 64 + max_requests_per_connection: 8 + ssl_insecure_skip_verify: true + + exporter_logs_dev_null: + type: ostream + filename: /dev/null + + exporter_logs_ostream: + type: ostream + filename: __be_logs + + exporter_logs_elasticsearch: + type: elasticsearch + host: localhost + port: 9200 + index: logs + response_timeout: 30 + debug: false + http_headers: + - X-OTel-Header-1: "Elasticsearch logs test header #1" + - X-OTel-Header-2: "Elasticsearch logs test header #2" + +readers: + reader_metrics: + thread_name: "reader metr" + export_interval: 10000 + export_timeout: 5000 + +samplers: + sampler_traces: +# type: always_on +# type: always_off +# type: trace_id_ratio_based +# ratio: 1.0 + type: parent_based + delegate: always_on + +processors: + processor_traces_batch: + type: batch + thread_name: "proc/batch trac" + # Note: when the queue is half full, a preemptive notification is sent + # to start the export call. + max_queue_size: 2048 + # Time interval (in ms) between two consecutive exports + schedule_delay: 5000 + # Export 'max_export_batch_size' after every `schedule_delay' milliseconds. + max_export_batch_size: 512 + + processor_traces_single: + type: single + + processor_logs_batch: + type: batch + thread_name: "proc/batch logs" + max_queue_size: 2048 + schedule_delay: 5000 + max_export_batch_size: 512 + + processor_logs_single: + type: single + +providers: + provider_traces: + resources: + - service.version: "1.0.0" + - service.instance.id: "id-be" + - service.name: "be" + - service.namespace: "HAProxy traces test" + + provider_metrics: + resources: + - service.version: "1.0.0" + - service.instance.id: "id-be" + - service.name: "be" + - service.namespace: "HAProxy metrics test" + + provider_logs: + resources: + - service.version: "1.0.0" + - service.instance.id: "id-be" + - service.name: "be" + - service.namespace: "HAProxy logs test" + +signals: + traces: + scope_name: "HAProxy OTEL - traces" + exporters: exporter_traces_otlp_http + samplers: sampler_traces + processors: processor_traces_batch + providers: provider_traces + + metrics: + scope_name: "HAProxy OTEL - metrics" + exporters: exporter_metrics_otlp_http + readers: reader_metrics + providers: provider_metrics + + logs: + scope_name: "HAProxy OTEL - logs" + exporters: exporter_logs_otlp_http + processors: processor_logs_batch + providers: provider_logs diff --git a/addons/otel/test/cmp/haproxy.cfg b/addons/otel/test/cmp/haproxy.cfg new file mode 100644 index 000000000..c2b1b0cf6 --- /dev/null +++ b/addons/otel/test/cmp/haproxy.cfg @@ -0,0 +1,22 @@ +global + stats socket /tmp/haproxy.sock mode 666 level admin + +listen stats + mode http + bind *:8001 + stats uri / + stats admin if TRUE + stats refresh 10s + +frontend otel-test-cmp-frontend + bind *:10080 + default_backend servers-backend + + # ACL used to distinguish successful from error responses + acl acl-http-status-ok status 100:399 + + # OTel filter + filter opentelemetry id otel-test-cmp config cmp/otel.cfg + +backend servers-backend + server server-1 127.0.0.1:8000 diff --git a/addons/otel/test/cmp/otel.cfg b/addons/otel/test/cmp/otel.cfg new file mode 100644 index 000000000..582ff68ef --- /dev/null +++ b/addons/otel/test/cmp/otel.cfg @@ -0,0 +1,81 @@ +[otel-test-cmp] + otel-instrumentation otel-test-instrumentation + config cmp/otel.yml +# log localhost:514 local7 debug + option dontlog-normal + option hard-errors + no option disabled + rate-limit 100.0 + + scopes client_session_start + scopes frontend_tcp_request + scopes frontend_http_request + scopes backend_tcp_request + scopes backend_http_request + scopes server_unavailable + + scopes server_session_start + scopes tcp_response + scopes http_response http_response-error server_session_end client_session_end + + otel-scope client_session_start + span "HAProxy session" root + baggage "haproxy_id" var(sess.otel.uuid) + span "Client session" parent "HAProxy session" + otel-event on-client-session-start + + otel-scope frontend_tcp_request + span "Frontend TCP request" parent "Client session" + otel-event on-frontend-tcp-request + + otel-scope frontend_http_request + span "Frontend HTTP request" parent "Frontend TCP request" + attribute "http.method" method + attribute "http.url" url + attribute "http.version" str("HTTP/") req.ver + finish "Frontend TCP request" + otel-event on-frontend-http-request + + otel-scope backend_tcp_request + span "Backend TCP request" parent "Frontend HTTP request" + finish "Frontend HTTP request" + otel-event on-backend-tcp-request + + otel-scope backend_http_request + span "Backend HTTP request" parent "Backend TCP request" + finish "Backend TCP request" + otel-event on-backend-http-request + + otel-scope server_unavailable + span "HAProxy session" + status "error" str("503 Service Unavailable") + finish * + otel-event on-server-unavailable + + otel-scope server_session_start + span "Server session" parent "HAProxy session" + finish "Backend HTTP request" + otel-event on-server-session-start + + otel-scope tcp_response + span "TCP response" parent "Server session" + otel-event on-tcp-response + + otel-scope http_response + span "HTTP response" parent "TCP response" + attribute "http.status_code" status + finish "TCP response" + otel-event on-http-response + + otel-scope http_response-error + span "HTTP response" + status "error" str("!acl-http-status-ok") + otel-event on-http-response if !acl-http-status-ok + + otel-scope server_session_end + finish "HTTP response" "Server session" + otel-event on-http-response + + otel-scope client_session_end + finish "*" + otel-event on-http-response diff --git a/addons/otel/test/cmp/otel.yml b/addons/otel/test/cmp/otel.yml new file mode 100644 index 000000000..2cd1ea60f --- /dev/null +++ b/addons/otel/test/cmp/otel.yml @@ -0,0 +1,246 @@ +exporters: + exporter_traces_otlp_file: + type: otlp_file + thread_name: "OTLP/file trace" + file_pattern: "__cmp_traces_log-%F-%N" + alias_pattern: "__traces_log-latest" + flush_interval: 30000000 + flush_count: 256 + file_size: 134217728 + rotate_size: 5 + + exporter_traces_otlp_grpc: + type: otlp_grpc + thread_name: "OTLP/gRPC trace" + endpoint: "http://localhost:4317/v1/traces" + use_ssl_credentials: false +# ssl_credentials_cacert_path: "" +# ssl_credentials_cacert_as_string: "" +# ssl_client_key_path: "" +# ssl_client_key_string: "" +# ssl_client_cert_path: "" +# ssl_client_cert_string: "" +# timeout: 10 +# user_agent: "" +# max_threads: 0 +# compression: "" +# max_concurrent_requests: 0 + + exporter_traces_otlp_http: + type: otlp_http + thread_name: "OTLP/HTTP trace" + endpoint: "http://localhost:4318/v1/traces" + content_type: json + json_bytes_mapping: hexid + debug: false + timeout: 10 + http_headers: + - X-OTel-Header-1: "OTLP HTTP traces test header #1" + - X-OTel-Header-2: "OTLP HTTP traces test header #2" + max_concurrent_requests: 64 + max_requests_per_connection: 8 + ssl_insecure_skip_verify: true +# ssl_ca_cert_path: "" +# ssl_ca_cert_string: "" +# ssl_client_key_path: "" +# ssl_client_key_string: "" +# ssl_client_cert_path: "" +# ssl_client_cert_string: "" +# ssl_min_tls: "" +# ssl_max_tls: "" +# ssl_cipher: "" +# ssl_cipher_suite: "" +# compression: "" + + exporter_traces_dev_null: + type: ostream + filename: /dev/null + + exporter_traces_ostream: + type: ostream + filename: __cmp_traces + + exporter_traces_memory: + type: memory + buffer_size: 256 + + exporter_traces_zipkin: + type: zipkin + endpoint: "http://localhost:9411/api/v2/spans" + format: json + service_name: "zipkin-service" +# ipv4: "" +# ipv6: "" + + exporter_metrics_otlp_file: + type: otlp_file + thread_name: "OTLP/file metr" + file_pattern: "__cmp_metrics_log-%F-%N" + alias_pattern: "__metrics_log-latest" + flush_interval: 30000000 + flush_count: 256 + file_size: 134217728 + rotate_size: 5 + + exporter_metrics_otlp_grpc: + type: otlp_grpc + thread_name: "OTLP/gRPC metr" + endpoint: "http://localhost:4317/v1/metrics" + use_ssl_credentials: false + + exporter_metrics_otlp_http: + type: otlp_http + thread_name: "OTLP/HTTP metr" + endpoint: "http://localhost:4318/v1/metrics" + content_type: json + debug: false + timeout: 10 + http_headers: + - X-OTel-Header-1: "OTLP HTTP metrics test header #1" + - X-OTel-Header-2: "OTLP HTTP metrics test header #2" + max_concurrent_requests: 64 + max_requests_per_connection: 8 + ssl_insecure_skip_verify: true + + exporter_metrics_dev_null: + type: ostream + filename: /dev/null + + exporter_metrics_ostream: + type: ostream + filename: __cmp_metrics + + exporter_metrics_memory: + type: memory + buffer_size: 256 + + exporter_logs_otlp_file: + type: otlp_file + thread_name: "OTLP/file logs" + file_pattern: "__cmp_logs_log-%F-%N" + alias_pattern: "__logs_log-latest" + flush_interval: 30000000 + flush_count: 256 + file_size: 134217728 + rotate_size: 5 + + exporter_logs_otlp_grpc: + type: otlp_grpc + thread_name: "OTLP/gRPC logs" + endpoint: "http://localhost:4317/v1/logs" + use_ssl_credentials: false + + exporter_logs_otlp_http: + type: otlp_http + thread_name: "OTLP/HTTP logs" + endpoint: "http://localhost:4318/v1/logs" + content_type: json + debug: false + timeout: 10 + http_headers: + - X-OTel-Header-1: "OTLP HTTP logs test header #1" + - X-OTel-Header-2: "OTLP HTTP logs test header #2" + max_concurrent_requests: 64 + max_requests_per_connection: 8 + ssl_insecure_skip_verify: true + + exporter_logs_dev_null: + type: ostream + filename: /dev/null + + exporter_logs_ostream: + type: ostream + filename: __cmp_logs + + exporter_logs_elasticsearch: + type: elasticsearch + host: localhost + port: 9200 + index: logs + response_timeout: 30 + debug: false + http_headers: + - X-OTel-Header-1: "Elasticsearch logs test header #1" + - X-OTel-Header-2: "Elasticsearch logs test header #2" + +readers: + reader_metrics: + thread_name: "reader metr" + export_interval: 10000 + export_timeout: 5000 + +samplers: + sampler_traces: +# type: always_on +# type: always_off +# type: trace_id_ratio_based +# ratio: 1.0 + type: parent_based + delegate: always_on + +processors: + processor_traces_batch: + type: batch + thread_name: "proc/batch trac" + # Note: when the queue is half full, a preemptive notification is sent + # to start the export call. + max_queue_size: 2048 + # Time interval (in ms) between two consecutive exports + schedule_delay: 5000 + # Export 'max_export_batch_size' after every `schedule_delay' milliseconds. + max_export_batch_size: 512 + + processor_traces_single: + type: single + + processor_logs_batch: + type: batch + thread_name: "proc/batch logs" + max_queue_size: 2048 + schedule_delay: 5000 + max_export_batch_size: 512 + + processor_logs_single: + type: single + +providers: + provider_traces: + resources: + - service.version: "1.0.0" + - service.instance.id: "id-cmp" + - service.name: "cmp" + - service.namespace: "HAProxy traces test" + + provider_metrics: + resources: + - service.version: "1.0.0" + - service.instance.id: "id-cmp" + - service.name: "cmp" + - service.namespace: "HAProxy metrics test" + + provider_logs: + resources: + - service.version: "1.0.0" + - service.instance.id: "id-cmp" + - service.name: "cmp" + - service.namespace: "HAProxy logs test" + +signals: + traces: + scope_name: "HAProxy OTEL - traces" + exporters: exporter_traces_otlp_http + samplers: sampler_traces + processors: processor_traces_batch + providers: provider_traces + + metrics: + scope_name: "HAProxy OTEL - metrics" + exporters: exporter_metrics_otlp_http + readers: reader_metrics + providers: provider_metrics + + logs: + scope_name: "HAProxy OTEL - logs" + exporters: exporter_logs_otlp_http + processors: processor_logs_batch + providers: provider_logs diff --git a/addons/otel/test/copy-yml.sh b/addons/otel/test/copy-yml.sh new file mode 100755 index 000000000..1a4115e40 --- /dev/null +++ b/addons/otel/test/copy-yml.sh @@ -0,0 +1,24 @@ +#!/bin/sh -u +# +# Copyright 2026 HAProxy Technologies, Miroslav Zagorac +# +SH_FILE="${1:-}" + SH_EXT="${2:-}" + + +if test ${#} -ne 2; then + echo + echo "usage: $(basename "${0}") input-file test-name" + echo + exit 64 +fi + +sed ' + s/^\( *\)\(filename:\)\( *\)_\(_[a-z]*\)/\1\2\3__'"${SH_EXT}"'\4/g + s/^\( *\)\(file_pattern:\)\( *\)"_\(_[a-z]*_[^"]*\)"/\1\2\3"__'"${SH_EXT}"'\4"/g + s/^\( *\)\(- service.instance.id:\)\( *\).*/\1\2\3"id-'"${SH_EXT}"'"/g + s/^\( *\)\(- service.name:\)\( *\).*/\1\2\3"'"${SH_EXT}"'"/g + s/^\( *\)\(- service.namespace:\)\( *\)\("otelc\)/\1\2\3"HAProxy/g + s/^\( *\)\(scope_name:\)\( *\)"OTEL C wrapper /\1\2 "HAProxy OTEL /g + s/^\( *\)\(exporters:\)\( *\)\(exporter_[a-z]*_\).*/\1\2\3\4otlp_http/g +' "${SH_FILE}" diff --git a/addons/otel/test/ctx/haproxy.cfg b/addons/otel/test/ctx/haproxy.cfg new file mode 100644 index 000000000..5d817c77f --- /dev/null +++ b/addons/otel/test/ctx/haproxy.cfg @@ -0,0 +1,28 @@ +global + stats socket /tmp/haproxy.sock mode 666 level admin + +listen stats + mode http + bind *:8001 + stats uri / + stats admin if TRUE + stats refresh 10s + +frontend otel-test-ctx-frontend + bind *:10080 + default_backend servers-backend + + # ACL used to distinguish successful from error responses + acl acl-http-status-ok status 100:399 + + # OTel filter + filter opentelemetry id otel-test-ctx config ctx/otel.cfg + + # run response scopes for successful responses + http-response otel-group otel-test-ctx http_response_group if acl-http-status-ok + + # run after-response scopes for error responses + http-after-response otel-group otel-test-ctx http_after_response_group if !acl-http-status-ok + +backend servers-backend + server server-1 127.0.0.1:8000 diff --git a/addons/otel/test/ctx/otel.cfg b/addons/otel/test/ctx/otel.cfg new file mode 100644 index 000000000..fba37b192 --- /dev/null +++ b/addons/otel/test/ctx/otel.cfg @@ -0,0 +1,196 @@ +[otel-test-ctx] + otel-instrumentation otel-test-instrumentation + debug-level 0x77f + log localhost:514 local7 debug + config ctx/otel.yml + option dontlog-normal + option hard-errors + no option disabled + rate-limit 100.0 + + groups http_response_group + groups http_after_response_group + + scopes client_session_start_1 + scopes client_session_start_2 + scopes frontend_tcp_request + scopes http_wait_request + scopes http_body_request + scopes frontend_http_request + scopes switching_rules_request + scopes backend_tcp_request + scopes backend_http_request + scopes process_server_rules_request + scopes http_process_request + scopes tcp_rdp_cookie_request + scopes process_sticking_rules_request + scopes client_session_end + scopes server_unavailable + + scopes server_session_start + scopes tcp_response + scopes http_wait_response + scopes process_store_rules_response + scopes http_response http_response-error + scopes server_session_end + + otel-group http_response_group + scopes http_response_1 + scopes http_response_2 + + otel-scope http_response_1 + span "HTTP response" + event "event_1" "hdr.content" res.hdr("content-type") str("; length: ") res.hdr("content-length") str(" bytes") + + otel-scope http_response_2 + span "HTTP response" + event "event_2" "hdr.date" res.hdr("date") str(" / ") res.hdr("last-modified") + + otel-group http_after_response_group + scopes http_after_response + + otel-scope http_after_response + span "HAProxy response" parent "HAProxy session" + status "error" str("http.status_code") status + + otel-scope client_session_start_1 + span "HAProxy session" root + inject "otel_ctx_1" use-headers use-vars + baggage "haproxy_id" var(sess.otel.uuid) + otel-event on-client-session-start + + otel-scope client_session_start_2 + extract "otel_ctx_1" use-vars + span "Client session" parent "otel_ctx_1" + inject "otel_ctx_2" use-headers use-vars + otel-event on-client-session-start + + otel-scope frontend_tcp_request + extract "otel_ctx_2" use-vars + span "Frontend TCP request" parent "otel_ctx_2" + inject "otel_ctx_3" use-headers use-vars + otel-event on-frontend-tcp-request + + otel-scope http_wait_request + extract "otel_ctx_3" use-vars + span "HTTP wait request" parent "otel_ctx_3" + inject "otel_ctx_4" use-headers use-vars + finish "Frontend TCP request" "otel_ctx_3" + otel-event on-http-wait-request + + otel-scope http_body_request + extract "otel_ctx_4" use-vars + span "HTTP body request" parent "otel_ctx_4" + inject "otel_ctx_5" use-headers use-vars + finish "HTTP wait request" "otel_ctx_4" + otel-event on-http-body-request + + otel-scope frontend_http_request + extract "otel_ctx_5" use-vars + span "Frontend HTTP request" parent "otel_ctx_5" + attribute "http.method" method + attribute "http.url" url + attribute "http.version" str("HTTP/") req.ver + inject "otel_ctx_6" use-headers use-vars + finish "HTTP body request" "otel_ctx_5" + otel-event on-frontend-http-request + + otel-scope switching_rules_request + extract "otel_ctx_6" use-vars + span "Switching rules request" parent "otel_ctx_6" + inject "otel_ctx_7" use-headers use-vars + finish "Frontend HTTP request" "otel_ctx_6" + otel-event on-switching-rules-request + + otel-scope backend_tcp_request + extract "otel_ctx_7" use-vars + span "Backend TCP request" parent "otel_ctx_7" + inject "otel_ctx_8" use-headers use-vars + finish "Switching rules request" "otel_ctx_7" + otel-event on-backend-tcp-request + + otel-scope backend_http_request + extract "otel_ctx_8" use-vars + span "Backend HTTP request" parent "otel_ctx_8" + inject "otel_ctx_9" use-headers use-vars + finish "Backend TCP request" "otel_ctx_8" + otel-event on-backend-http-request + + otel-scope process_server_rules_request + extract "otel_ctx_9" use-vars + span "Process server rules request" parent "otel_ctx_9" + inject "otel_ctx_10" use-headers use-vars + finish "Backend HTTP request" "otel_ctx_9" + otel-event on-process-server-rules-request + + otel-scope http_process_request + extract "otel_ctx_10" use-vars + span "HTTP process request" parent "otel_ctx_10" + inject "otel_ctx_11" use-headers use-vars + finish "Process server rules request" "otel_ctx_10" + otel-event on-http-process-request + + otel-scope tcp_rdp_cookie_request + extract "otel_ctx_11" use-vars + span "TCP RDP cookie request" parent "otel_ctx_11" + inject "otel_ctx_12" use-headers use-vars + finish "HTTP process request" "otel_ctx_11" + otel-event on-tcp-rdp-cookie-request + + otel-scope process_sticking_rules_request + extract "otel_ctx_12" use-vars + span "Process sticking rules request" parent "otel_ctx_12" + inject "otel_ctx_13" use-headers use-vars + finish "TCP RDP cookie request" "otel_ctx_12" + otel-event on-process-sticking-rules-request + + otel-scope client_session_end + finish "Client session" "otel_ctx_2" + otel-event on-client-session-end + + otel-scope server_unavailable + finish * + otel-event on-server-unavailable + + otel-scope server_session_start + span "Server session" parent "otel_ctx_1" + inject "otel_ctx_14" use-vars + extract "otel_ctx_13" use-vars + finish "Process sticking rules request" "otel_ctx_13" + otel-event on-server-session-start + + otel-scope tcp_response + extract "otel_ctx_14" use-vars + span "TCP response" parent "otel_ctx_14" + inject "otel_ctx_15" use-vars + otel-event on-tcp-response + + otel-scope http_wait_response + extract "otel_ctx_15" use-vars + span "HTTP wait response" parent "otel_ctx_15" + inject "otel_ctx_16" use-headers use-vars + finish "TCP response" "otel_ctx_15" + otel-event on-http-wait-response + + otel-scope process_store_rules_response + extract "otel_ctx_16" use-vars + span "Process store rules response" parent "otel_ctx_16" + inject "otel_ctx_17" use-headers use-vars + finish "HTTP wait response" "otel_ctx_16" + otel-event on-process-store-rules-response + + otel-scope http_response + extract "otel_ctx_17" use-vars + span "HTTP response" parent "otel_ctx_17" + attribute "http.status_code" status + finish "Process store rules response" "otel_ctx_17" + otel-event on-http-response + + otel-scope http_response-error + span "HTTP response" + status "error" str("!acl-http-status-ok") + otel-event on-http-response if !acl-http-status-ok + + otel-scope server_session_end + finish * + otel-event on-server-session-end diff --git a/addons/otel/test/ctx/otel.yml b/addons/otel/test/ctx/otel.yml new file mode 100644 index 000000000..56b96f391 --- /dev/null +++ b/addons/otel/test/ctx/otel.yml @@ -0,0 +1,246 @@ +exporters: + exporter_traces_otlp_file: + type: otlp_file + thread_name: "OTLP/file trace" + file_pattern: "__ctx_traces_log-%F-%N" + alias_pattern: "__traces_log-latest" + flush_interval: 30000000 + flush_count: 256 + file_size: 134217728 + rotate_size: 5 + + exporter_traces_otlp_grpc: + type: otlp_grpc + thread_name: "OTLP/gRPC trace" + endpoint: "http://localhost:4317/v1/traces" + use_ssl_credentials: false +# ssl_credentials_cacert_path: "" +# ssl_credentials_cacert_as_string: "" +# ssl_client_key_path: "" +# ssl_client_key_string: "" +# ssl_client_cert_path: "" +# ssl_client_cert_string: "" +# timeout: 10 +# user_agent: "" +# max_threads: 0 +# compression: "" +# max_concurrent_requests: 0 + + exporter_traces_otlp_http: + type: otlp_http + thread_name: "OTLP/HTTP trace" + endpoint: "http://localhost:4318/v1/traces" + content_type: json + json_bytes_mapping: hexid + debug: false + timeout: 10 + http_headers: + - X-OTel-Header-1: "OTLP HTTP traces test header #1" + - X-OTel-Header-2: "OTLP HTTP traces test header #2" + max_concurrent_requests: 64 + max_requests_per_connection: 8 + ssl_insecure_skip_verify: true +# ssl_ca_cert_path: "" +# ssl_ca_cert_string: "" +# ssl_client_key_path: "" +# ssl_client_key_string: "" +# ssl_client_cert_path: "" +# ssl_client_cert_string: "" +# ssl_min_tls: "" +# ssl_max_tls: "" +# ssl_cipher: "" +# ssl_cipher_suite: "" +# compression: "" + + exporter_traces_dev_null: + type: ostream + filename: /dev/null + + exporter_traces_ostream: + type: ostream + filename: __ctx_traces + + exporter_traces_memory: + type: memory + buffer_size: 256 + + exporter_traces_zipkin: + type: zipkin + endpoint: "http://localhost:9411/api/v2/spans" + format: json + service_name: "zipkin-service" +# ipv4: "" +# ipv6: "" + + exporter_metrics_otlp_file: + type: otlp_file + thread_name: "OTLP/file metr" + file_pattern: "__ctx_metrics_log-%F-%N" + alias_pattern: "__metrics_log-latest" + flush_interval: 30000000 + flush_count: 256 + file_size: 134217728 + rotate_size: 5 + + exporter_metrics_otlp_grpc: + type: otlp_grpc + thread_name: "OTLP/gRPC metr" + endpoint: "http://localhost:4317/v1/metrics" + use_ssl_credentials: false + + exporter_metrics_otlp_http: + type: otlp_http + thread_name: "OTLP/HTTP metr" + endpoint: "http://localhost:4318/v1/metrics" + content_type: json + debug: false + timeout: 10 + http_headers: + - X-OTel-Header-1: "OTLP HTTP metrics test header #1" + - X-OTel-Header-2: "OTLP HTTP metrics test header #2" + max_concurrent_requests: 64 + max_requests_per_connection: 8 + ssl_insecure_skip_verify: true + + exporter_metrics_dev_null: + type: ostream + filename: /dev/null + + exporter_metrics_ostream: + type: ostream + filename: __ctx_metrics + + exporter_metrics_memory: + type: memory + buffer_size: 256 + + exporter_logs_otlp_file: + type: otlp_file + thread_name: "OTLP/file logs" + file_pattern: "__ctx_logs_log-%F-%N" + alias_pattern: "__logs_log-latest" + flush_interval: 30000000 + flush_count: 256 + file_size: 134217728 + rotate_size: 5 + + exporter_logs_otlp_grpc: + type: otlp_grpc + thread_name: "OTLP/gRPC logs" + endpoint: "http://localhost:4317/v1/logs" + use_ssl_credentials: false + + exporter_logs_otlp_http: + type: otlp_http + thread_name: "OTLP/HTTP logs" + endpoint: "http://localhost:4318/v1/logs" + content_type: json + debug: false + timeout: 10 + http_headers: + - X-OTel-Header-1: "OTLP HTTP logs test header #1" + - X-OTel-Header-2: "OTLP HTTP logs test header #2" + max_concurrent_requests: 64 + max_requests_per_connection: 8 + ssl_insecure_skip_verify: true + + exporter_logs_dev_null: + type: ostream + filename: /dev/null + + exporter_logs_ostream: + type: ostream + filename: __ctx_logs + + exporter_logs_elasticsearch: + type: elasticsearch + host: localhost + port: 9200 + index: logs + response_timeout: 30 + debug: false + http_headers: + - X-OTel-Header-1: "Elasticsearch logs test header #1" + - X-OTel-Header-2: "Elasticsearch logs test header #2" + +readers: + reader_metrics: + thread_name: "reader metr" + export_interval: 10000 + export_timeout: 5000 + +samplers: + sampler_traces: +# type: always_on +# type: always_off +# type: trace_id_ratio_based +# ratio: 1.0 + type: parent_based + delegate: always_on + +processors: + processor_traces_batch: + type: batch + thread_name: "proc/batch trac" + # Note: when the queue is half full, a preemptive notification is sent + # to start the export call. + max_queue_size: 2048 + # Time interval (in ms) between two consecutive exports + schedule_delay: 5000 + # Export 'max_export_batch_size' after every `schedule_delay' milliseconds. + max_export_batch_size: 512 + + processor_traces_single: + type: single + + processor_logs_batch: + type: batch + thread_name: "proc/batch logs" + max_queue_size: 2048 + schedule_delay: 5000 + max_export_batch_size: 512 + + processor_logs_single: + type: single + +providers: + provider_traces: + resources: + - service.version: "1.0.0" + - service.instance.id: "id-ctx" + - service.name: "ctx" + - service.namespace: "HAProxy traces test" + + provider_metrics: + resources: + - service.version: "1.0.0" + - service.instance.id: "id-ctx" + - service.name: "ctx" + - service.namespace: "HAProxy metrics test" + + provider_logs: + resources: + - service.version: "1.0.0" + - service.instance.id: "id-ctx" + - service.name: "ctx" + - service.namespace: "HAProxy logs test" + +signals: + traces: + scope_name: "HAProxy OTEL - traces" + exporters: exporter_traces_otlp_http + samplers: sampler_traces + processors: processor_traces_batch + providers: provider_traces + + metrics: + scope_name: "HAProxy OTEL - metrics" + exporters: exporter_metrics_otlp_http + readers: reader_metrics + providers: provider_metrics + + logs: + scope_name: "HAProxy OTEL - logs" + exporters: exporter_logs_otlp_http + processors: processor_logs_batch + providers: provider_logs diff --git a/addons/otel/test/empty/haproxy.cfg b/addons/otel/test/empty/haproxy.cfg new file mode 100644 index 000000000..a71413670 --- /dev/null +++ b/addons/otel/test/empty/haproxy.cfg @@ -0,0 +1,19 @@ +global + stats socket /tmp/haproxy.sock mode 666 level admin + +listen stats + mode http + bind *:8001 + stats uri / + stats admin if TRUE + stats refresh 10s + +frontend otel-test-empty + bind *:10080 + default_backend servers-backend + + # OTel filter + filter opentelemetry id otel-test-empty config empty/otel.cfg + +backend servers-backend + server server-1 127.0.0.1:8000 diff --git a/addons/otel/test/empty/otel.cfg b/addons/otel/test/empty/otel.cfg new file mode 100644 index 000000000..35089361e --- /dev/null +++ b/addons/otel/test/empty/otel.cfg @@ -0,0 +1,2 @@ +otel-instrumentation otel-test-instrumentation + config empty/otel.yml diff --git a/addons/otel/test/empty/otel.yml b/addons/otel/test/empty/otel.yml new file mode 100644 index 000000000..1c8281fbe --- /dev/null +++ b/addons/otel/test/empty/otel.yml @@ -0,0 +1,246 @@ +exporters: + exporter_traces_otlp_file: + type: otlp_file + thread_name: "OTLP/file trace" + file_pattern: "__empty_traces_log-%F-%N" + alias_pattern: "__traces_log-latest" + flush_interval: 30000000 + flush_count: 256 + file_size: 134217728 + rotate_size: 5 + + exporter_traces_otlp_grpc: + type: otlp_grpc + thread_name: "OTLP/gRPC trace" + endpoint: "http://localhost:4317/v1/traces" + use_ssl_credentials: false +# ssl_credentials_cacert_path: "" +# ssl_credentials_cacert_as_string: "" +# ssl_client_key_path: "" +# ssl_client_key_string: "" +# ssl_client_cert_path: "" +# ssl_client_cert_string: "" +# timeout: 10 +# user_agent: "" +# max_threads: 0 +# compression: "" +# max_concurrent_requests: 0 + + exporter_traces_otlp_http: + type: otlp_http + thread_name: "OTLP/HTTP trace" + endpoint: "http://localhost:4318/v1/traces" + content_type: json + json_bytes_mapping: hexid + debug: false + timeout: 10 + http_headers: + - X-OTel-Header-1: "OTLP HTTP traces test header #1" + - X-OTel-Header-2: "OTLP HTTP traces test header #2" + max_concurrent_requests: 64 + max_requests_per_connection: 8 + ssl_insecure_skip_verify: true +# ssl_ca_cert_path: "" +# ssl_ca_cert_string: "" +# ssl_client_key_path: "" +# ssl_client_key_string: "" +# ssl_client_cert_path: "" +# ssl_client_cert_string: "" +# ssl_min_tls: "" +# ssl_max_tls: "" +# ssl_cipher: "" +# ssl_cipher_suite: "" +# compression: "" + + exporter_traces_dev_null: + type: ostream + filename: /dev/null + + exporter_traces_ostream: + type: ostream + filename: __empty_traces + + exporter_traces_memory: + type: memory + buffer_size: 256 + + exporter_traces_zipkin: + type: zipkin + endpoint: "http://localhost:9411/api/v2/spans" + format: json + service_name: "zipkin-service" +# ipv4: "" +# ipv6: "" + + exporter_metrics_otlp_file: + type: otlp_file + thread_name: "OTLP/file metr" + file_pattern: "__empty_metrics_log-%F-%N" + alias_pattern: "__metrics_log-latest" + flush_interval: 30000000 + flush_count: 256 + file_size: 134217728 + rotate_size: 5 + + exporter_metrics_otlp_grpc: + type: otlp_grpc + thread_name: "OTLP/gRPC metr" + endpoint: "http://localhost:4317/v1/metrics" + use_ssl_credentials: false + + exporter_metrics_otlp_http: + type: otlp_http + thread_name: "OTLP/HTTP metr" + endpoint: "http://localhost:4318/v1/metrics" + content_type: json + debug: false + timeout: 10 + http_headers: + - X-OTel-Header-1: "OTLP HTTP metrics test header #1" + - X-OTel-Header-2: "OTLP HTTP metrics test header #2" + max_concurrent_requests: 64 + max_requests_per_connection: 8 + ssl_insecure_skip_verify: true + + exporter_metrics_dev_null: + type: ostream + filename: /dev/null + + exporter_metrics_ostream: + type: ostream + filename: __empty_metrics + + exporter_metrics_memory: + type: memory + buffer_size: 256 + + exporter_logs_otlp_file: + type: otlp_file + thread_name: "OTLP/file logs" + file_pattern: "__empty_logs_log-%F-%N" + alias_pattern: "__logs_log-latest" + flush_interval: 30000000 + flush_count: 256 + file_size: 134217728 + rotate_size: 5 + + exporter_logs_otlp_grpc: + type: otlp_grpc + thread_name: "OTLP/gRPC logs" + endpoint: "http://localhost:4317/v1/logs" + use_ssl_credentials: false + + exporter_logs_otlp_http: + type: otlp_http + thread_name: "OTLP/HTTP logs" + endpoint: "http://localhost:4318/v1/logs" + content_type: json + debug: false + timeout: 10 + http_headers: + - X-OTel-Header-1: "OTLP HTTP logs test header #1" + - X-OTel-Header-2: "OTLP HTTP logs test header #2" + max_concurrent_requests: 64 + max_requests_per_connection: 8 + ssl_insecure_skip_verify: true + + exporter_logs_dev_null: + type: ostream + filename: /dev/null + + exporter_logs_ostream: + type: ostream + filename: __empty_logs + + exporter_logs_elasticsearch: + type: elasticsearch + host: localhost + port: 9200 + index: logs + response_timeout: 30 + debug: false + http_headers: + - X-OTel-Header-1: "Elasticsearch logs test header #1" + - X-OTel-Header-2: "Elasticsearch logs test header #2" + +readers: + reader_metrics: + thread_name: "reader metr" + export_interval: 10000 + export_timeout: 5000 + +samplers: + sampler_traces: +# type: always_on +# type: always_off +# type: trace_id_ratio_based +# ratio: 1.0 + type: parent_based + delegate: always_on + +processors: + processor_traces_batch: + type: batch + thread_name: "proc/batch trac" + # Note: when the queue is half full, a preemptive notification is sent + # to start the export call. + max_queue_size: 2048 + # Time interval (in ms) between two consecutive exports + schedule_delay: 5000 + # Export 'max_export_batch_size' after every `schedule_delay' milliseconds. + max_export_batch_size: 512 + + processor_traces_single: + type: single + + processor_logs_batch: + type: batch + thread_name: "proc/batch logs" + max_queue_size: 2048 + schedule_delay: 5000 + max_export_batch_size: 512 + + processor_logs_single: + type: single + +providers: + provider_traces: + resources: + - service.version: "1.0.0" + - service.instance.id: "id-empty" + - service.name: "empty" + - service.namespace: "HAProxy traces test" + + provider_metrics: + resources: + - service.version: "1.0.0" + - service.instance.id: "id-empty" + - service.name: "empty" + - service.namespace: "HAProxy metrics test" + + provider_logs: + resources: + - service.version: "1.0.0" + - service.instance.id: "id-empty" + - service.name: "empty" + - service.namespace: "HAProxy logs test" + +signals: + traces: + scope_name: "HAProxy OTEL - traces" + exporters: exporter_traces_otlp_http + samplers: sampler_traces + processors: processor_traces_batch + providers: provider_traces + + metrics: + scope_name: "HAProxy OTEL - metrics" + exporters: exporter_metrics_otlp_http + readers: reader_metrics + providers: provider_metrics + + logs: + scope_name: "HAProxy OTEL - logs" + exporters: exporter_logs_otlp_http + processors: processor_logs_batch + providers: provider_logs diff --git a/addons/otel/test/fe/haproxy.cfg b/addons/otel/test/fe/haproxy.cfg new file mode 100644 index 000000000..1d25db195 --- /dev/null +++ b/addons/otel/test/fe/haproxy.cfg @@ -0,0 +1,19 @@ +global + stats socket /tmp/haproxy-fe.sock mode 666 level admin + +listen stats + mode http + bind *:8001 + stats uri / + stats admin if TRUE + stats refresh 10s + +frontend otel-test-fe-frontend + bind *:10080 + default_backend servers-backend + + # OTel filter + filter opentelemetry id otel-test-fe config fe/otel.cfg + +backend servers-backend + server server-1 127.0.0.1:11080 diff --git a/addons/otel/test/fe/otel.cfg b/addons/otel/test/fe/otel.cfg new file mode 100644 index 000000000..7eb1a560e --- /dev/null +++ b/addons/otel/test/fe/otel.cfg @@ -0,0 +1,73 @@ +[otel-test-fe] + otel-instrumentation otel-test-instrumentation + config fe/otel.yml +# log localhost:514 local7 debug + option dontlog-normal + option hard-errors + no option disabled + rate-limit 100.0 + + scopes client_session_start + scopes frontend_tcp_request + scopes frontend_http_request + scopes backend_tcp_request + scopes backend_http_request + scopes client_session_end + + scopes server_session_start + scopes tcp_response + scopes http_response + scopes server_session_end + + otel-scope client_session_start + span "HAProxy session" root + baggage "haproxy_id" var(sess.otel.uuid) + span "Client session" parent "HAProxy session" + otel-event on-client-session-start + + otel-scope frontend_tcp_request + span "Frontend TCP request" parent "Client session" + otel-event on-frontend-tcp-request + + otel-scope frontend_http_request + span "Frontend HTTP request" parent "Frontend TCP request" + attribute "http.method" method + attribute "http.url" url + attribute "http.version" str("HTTP/") req.ver + finish "Frontend TCP request" + otel-event on-frontend-http-request + + otel-scope backend_tcp_request + span "Backend TCP request" parent "Frontend HTTP request" + finish "Frontend HTTP request" + otel-event on-backend-tcp-request + + otel-scope backend_http_request + span "Backend HTTP request" parent "Backend TCP request" + finish "Backend TCP request" + span "HAProxy session" + inject "otel-ctx" use-headers + otel-event on-backend-http-request + + otel-scope client_session_end + finish "Client session" + otel-event on-client-session-end + + otel-scope server_session_start + span "Server session" parent "HAProxy session" + finish "Backend HTTP request" + otel-event on-server-session-start + + otel-scope tcp_response + span "TCP response" parent "Server session" + otel-event on-tcp-response + + otel-scope http_response + span "HTTP response" parent "TCP response" + attribute "http.status_code" status + finish "TCP response" + otel-event on-http-response + + otel-scope server_session_end + finish * + otel-event on-server-session-end diff --git a/addons/otel/test/fe/otel.yml b/addons/otel/test/fe/otel.yml new file mode 100644 index 000000000..89e25f757 --- /dev/null +++ b/addons/otel/test/fe/otel.yml @@ -0,0 +1,246 @@ +exporters: + exporter_traces_otlp_file: + type: otlp_file + thread_name: "OTLP/file trace" + file_pattern: "__fe_traces_log-%F-%N" + alias_pattern: "__traces_log-latest" + flush_interval: 30000000 + flush_count: 256 + file_size: 134217728 + rotate_size: 5 + + exporter_traces_otlp_grpc: + type: otlp_grpc + thread_name: "OTLP/gRPC trace" + endpoint: "http://localhost:4317/v1/traces" + use_ssl_credentials: false +# ssl_credentials_cacert_path: "" +# ssl_credentials_cacert_as_string: "" +# ssl_client_key_path: "" +# ssl_client_key_string: "" +# ssl_client_cert_path: "" +# ssl_client_cert_string: "" +# timeout: 10 +# user_agent: "" +# max_threads: 0 +# compression: "" +# max_concurrent_requests: 0 + + exporter_traces_otlp_http: + type: otlp_http + thread_name: "OTLP/HTTP trace" + endpoint: "http://localhost:4318/v1/traces" + content_type: json + json_bytes_mapping: hexid + debug: false + timeout: 10 + http_headers: + - X-OTel-Header-1: "OTLP HTTP traces test header #1" + - X-OTel-Header-2: "OTLP HTTP traces test header #2" + max_concurrent_requests: 64 + max_requests_per_connection: 8 + ssl_insecure_skip_verify: true +# ssl_ca_cert_path: "" +# ssl_ca_cert_string: "" +# ssl_client_key_path: "" +# ssl_client_key_string: "" +# ssl_client_cert_path: "" +# ssl_client_cert_string: "" +# ssl_min_tls: "" +# ssl_max_tls: "" +# ssl_cipher: "" +# ssl_cipher_suite: "" +# compression: "" + + exporter_traces_dev_null: + type: ostream + filename: /dev/null + + exporter_traces_ostream: + type: ostream + filename: __fe_traces + + exporter_traces_memory: + type: memory + buffer_size: 256 + + exporter_traces_zipkin: + type: zipkin + endpoint: "http://localhost:9411/api/v2/spans" + format: json + service_name: "zipkin-service" +# ipv4: "" +# ipv6: "" + + exporter_metrics_otlp_file: + type: otlp_file + thread_name: "OTLP/file metr" + file_pattern: "__fe_metrics_log-%F-%N" + alias_pattern: "__metrics_log-latest" + flush_interval: 30000000 + flush_count: 256 + file_size: 134217728 + rotate_size: 5 + + exporter_metrics_otlp_grpc: + type: otlp_grpc + thread_name: "OTLP/gRPC metr" + endpoint: "http://localhost:4317/v1/metrics" + use_ssl_credentials: false + + exporter_metrics_otlp_http: + type: otlp_http + thread_name: "OTLP/HTTP metr" + endpoint: "http://localhost:4318/v1/metrics" + content_type: json + debug: false + timeout: 10 + http_headers: + - X-OTel-Header-1: "OTLP HTTP metrics test header #1" + - X-OTel-Header-2: "OTLP HTTP metrics test header #2" + max_concurrent_requests: 64 + max_requests_per_connection: 8 + ssl_insecure_skip_verify: true + + exporter_metrics_dev_null: + type: ostream + filename: /dev/null + + exporter_metrics_ostream: + type: ostream + filename: __fe_metrics + + exporter_metrics_memory: + type: memory + buffer_size: 256 + + exporter_logs_otlp_file: + type: otlp_file + thread_name: "OTLP/file logs" + file_pattern: "__fe_logs_log-%F-%N" + alias_pattern: "__logs_log-latest" + flush_interval: 30000000 + flush_count: 256 + file_size: 134217728 + rotate_size: 5 + + exporter_logs_otlp_grpc: + type: otlp_grpc + thread_name: "OTLP/gRPC logs" + endpoint: "http://localhost:4317/v1/logs" + use_ssl_credentials: false + + exporter_logs_otlp_http: + type: otlp_http + thread_name: "OTLP/HTTP logs" + endpoint: "http://localhost:4318/v1/logs" + content_type: json + debug: false + timeout: 10 + http_headers: + - X-OTel-Header-1: "OTLP HTTP logs test header #1" + - X-OTel-Header-2: "OTLP HTTP logs test header #2" + max_concurrent_requests: 64 + max_requests_per_connection: 8 + ssl_insecure_skip_verify: true + + exporter_logs_dev_null: + type: ostream + filename: /dev/null + + exporter_logs_ostream: + type: ostream + filename: __fe_logs + + exporter_logs_elasticsearch: + type: elasticsearch + host: localhost + port: 9200 + index: logs + response_timeout: 30 + debug: false + http_headers: + - X-OTel-Header-1: "Elasticsearch logs test header #1" + - X-OTel-Header-2: "Elasticsearch logs test header #2" + +readers: + reader_metrics: + thread_name: "reader metr" + export_interval: 10000 + export_timeout: 5000 + +samplers: + sampler_traces: +# type: always_on +# type: always_off +# type: trace_id_ratio_based +# ratio: 1.0 + type: parent_based + delegate: always_on + +processors: + processor_traces_batch: + type: batch + thread_name: "proc/batch trac" + # Note: when the queue is half full, a preemptive notification is sent + # to start the export call. + max_queue_size: 2048 + # Time interval (in ms) between two consecutive exports + schedule_delay: 5000 + # Export 'max_export_batch_size' after every `schedule_delay' milliseconds. + max_export_batch_size: 512 + + processor_traces_single: + type: single + + processor_logs_batch: + type: batch + thread_name: "proc/batch logs" + max_queue_size: 2048 + schedule_delay: 5000 + max_export_batch_size: 512 + + processor_logs_single: + type: single + +providers: + provider_traces: + resources: + - service.version: "1.0.0" + - service.instance.id: "id-fe" + - service.name: "fe" + - service.namespace: "HAProxy traces test" + + provider_metrics: + resources: + - service.version: "1.0.0" + - service.instance.id: "id-fe" + - service.name: "fe" + - service.namespace: "HAProxy metrics test" + + provider_logs: + resources: + - service.version: "1.0.0" + - service.instance.id: "id-fe" + - service.name: "fe" + - service.namespace: "HAProxy logs test" + +signals: + traces: + scope_name: "HAProxy OTEL - traces" + exporters: exporter_traces_otlp_http + samplers: sampler_traces + processors: processor_traces_batch + providers: provider_traces + + metrics: + scope_name: "HAProxy OTEL - metrics" + exporters: exporter_metrics_otlp_http + readers: reader_metrics + providers: provider_metrics + + logs: + scope_name: "HAProxy OTEL - logs" + exporters: exporter_logs_otlp_http + processors: processor_logs_batch + providers: provider_logs diff --git a/addons/otel/test/haproxy-common.cfg b/addons/otel/test/haproxy-common.cfg new file mode 100644 index 000000000..d66d73429 --- /dev/null +++ b/addons/otel/test/haproxy-common.cfg @@ -0,0 +1,19 @@ +global +# nbthread 1 + insecure-fork-wanted + maxconn 5000 + hard-stop-after 10s +# log localhost:514 local7 debug +# debug + +defaults +# log global +# option httplog +# option dontlognull +# option httpclose + mode http + retries 3 + maxconn 4000 + timeout connect 5000 + timeout client 50000 + timeout server 50000 diff --git a/addons/otel/test/index.html b/addons/otel/test/index.html new file mode 100644 index 000000000..09ed6fa3d --- /dev/null +++ b/addons/otel/test/index.html @@ -0,0 +1 @@ +

Did I err?

diff --git a/addons/otel/test/run-cmp.sh b/addons/otel/test/run-cmp.sh new file mode 100755 index 000000000..9815b09bb --- /dev/null +++ b/addons/otel/test/run-cmp.sh @@ -0,0 +1,16 @@ +#!/bin/sh -u +# +# Copyright 2026 HAProxy Technologies, Miroslav Zagorac +# +SH_ARG_HAPROXY="${1:-$(realpath -L ${PWD}/../../../haproxy)}" +SH_ARG_PIDFILE="${2:-haproxy.pid}" + SH_ARGS="-f haproxy-common.cfg -f cmp/haproxy.cfg -p "${SH_ARG_PIDFILE}"" + SH_LOG_DIR="_logs" + SH_LOG="${SH_LOG_DIR}/_log-$(basename "${0}" .sh)-$(date +%s)" + + +test -x "${SH_ARG_HAPROXY}" || exit 1 +mkdir -p "${SH_LOG_DIR}" || exit 2 + +echo "executing: ${SH_ARG_HAPROXY} ${SH_ARGS}" >${SH_LOG} +"${SH_ARG_HAPROXY}" ${SH_ARGS} >>"${SH_LOG}" 2>&1 diff --git a/addons/otel/test/run-ctx.sh b/addons/otel/test/run-ctx.sh new file mode 100755 index 000000000..70cb87a2d --- /dev/null +++ b/addons/otel/test/run-ctx.sh @@ -0,0 +1,16 @@ +#!/bin/sh -u +# +# Copyright 2026 HAProxy Technologies, Miroslav Zagorac +# +SH_ARG_HAPROXY="${1:-$(realpath -L ${PWD}/../../../haproxy)}" +SH_ARG_PIDFILE="${2:-haproxy.pid}" + SH_ARGS="-f haproxy-common.cfg -f ctx/haproxy.cfg -p "${SH_ARG_PIDFILE}"" + SH_LOG_DIR="_logs" + SH_LOG="${SH_LOG_DIR}/_log-$(basename "${0}" .sh)-$(date +%s)" + + +test -x "${SH_ARG_HAPROXY}" || exit 1 +mkdir -p "${SH_LOG_DIR}" || exit 2 + +echo "executing: ${SH_ARG_HAPROXY} ${SH_ARGS}" >${SH_LOG} +"${SH_ARG_HAPROXY}" ${SH_ARGS} >>"${SH_LOG}" 2>&1 diff --git a/addons/otel/test/run-fe-be.sh b/addons/otel/test/run-fe-be.sh new file mode 100755 index 000000000..1248338ed --- /dev/null +++ b/addons/otel/test/run-fe-be.sh @@ -0,0 +1,50 @@ +#!/bin/sh -u +# +# Copyright 2026 HAProxy Technologies, Miroslav Zagorac +# +SH_ARG_HAPROXY="${1:-$(realpath -L ${PWD}/../../../haproxy)}" +SH_ARG_PIDFILE="${2:-haproxy.pid}" + SH_ARGS_FE="-f haproxy-common.cfg -f fe/haproxy.cfg -p "${SH_ARG_PIDFILE}"" + SH_ARGS_BE="-f haproxy-common.cfg -f be/haproxy.cfg -p "${SH_ARG_PIDFILE}"" + SH_TIME="$(date +%s)" + SH_LOG_DIR="_logs" + SH_LOG_FE="${SH_LOG_DIR}/_log-$(basename "${0}" fe-be.sh)fe-${SH_TIME}" + SH_LOG_BE="${SH_LOG_DIR}/_log-$(basename "${0}" fe-be.sh)be-${SH_TIME}" + + +__exit () +{ + test -z "${2}" && { + echo + echo "Script killed!" + + echo "Waiting for jobs to complete..." + pkill --signal SIGUSR1 haproxy + wait + } + + test -n "${1}" && { + echo + echo "${1}" + echo + } + + exit ${2:-100} +} + + +trap __exit INT TERM + +test -x "${SH_ARG_HAPROXY}" || __exit "${SH_ARG_HAPROXY}: executable does not exist" 1 +mkdir -p "${SH_LOG_DIR}" || __exit "${SH_ARG_HAPROXY}: cannot create log directory" 2 + +echo "\n------------------------------------------------------------------------" +echo "--- executing: ${SH_ARG_HAPROXY} ${SH_ARGS_BE}" >${SH_LOG_BE} +"${SH_ARG_HAPROXY}" ${SH_ARGS_BE} >>"${SH_LOG_BE}" 2>&1 & + +echo "--- executing: ${SH_ARG_HAPROXY} ${SH_ARGS_FE}" >${SH_LOG_FE} +"${SH_ARG_HAPROXY}" ${SH_ARGS_FE} >>"${SH_LOG_FE}" 2>&1 & +echo "------------------------------------------------------------------------\n" + +echo "Press CTRL-C to quit..." +wait diff --git a/addons/otel/test/run-sa.sh b/addons/otel/test/run-sa.sh new file mode 100755 index 000000000..27849c678 --- /dev/null +++ b/addons/otel/test/run-sa.sh @@ -0,0 +1,16 @@ +#!/bin/sh -u +# +# Copyright 2026 HAProxy Technologies, Miroslav Zagorac +# +SH_ARG_HAPROXY="${1:-$(realpath -L ${PWD}/../../../haproxy)}" +SH_ARG_PIDFILE="${2:-haproxy.pid}" + SH_ARGS="-f haproxy-common.cfg -f sa/haproxy.cfg -p "${SH_ARG_PIDFILE}"" + SH_LOG_DIR="_logs" + SH_LOG="${SH_LOG_DIR}/_log-$(basename "${0}" .sh)-$(date +%s)" + + +test -x "${SH_ARG_HAPROXY}" || exit 1 +mkdir -p "${SH_LOG_DIR}" || exit 2 + +echo "executing: ${SH_ARG_HAPROXY} ${SH_ARGS}" >${SH_LOG} +"${SH_ARG_HAPROXY}" ${SH_ARGS} >>"${SH_LOG}" 2>&1 diff --git a/addons/otel/test/sa/haproxy.cfg b/addons/otel/test/sa/haproxy.cfg new file mode 100644 index 000000000..8b62b7bfe --- /dev/null +++ b/addons/otel/test/sa/haproxy.cfg @@ -0,0 +1,28 @@ +global + stats socket /tmp/haproxy.sock mode 666 level admin + +listen stats + mode http + bind *:8001 + stats uri / + stats admin if TRUE + stats refresh 10s + +frontend otel-test-sa-frontend + bind *:10080 + default_backend servers-backend + + # ACL used to distinguish successful from error responses + acl acl-http-status-ok status 100:399 + + # OTel filter + filter opentelemetry id otel-test-sa config sa/otel.cfg + + # run response scopes for successful responses + http-response otel-group otel-test-sa http_response_group if acl-http-status-ok + + # run after-response scopes for error responses + http-after-response otel-group otel-test-sa http_after_response_group if !acl-http-status-ok + +backend servers-backend + server server-1 127.0.0.1:8000 diff --git a/addons/otel/test/sa/otel.cfg b/addons/otel/test/sa/otel.cfg new file mode 100644 index 000000000..147222b5f --- /dev/null +++ b/addons/otel/test/sa/otel.cfg @@ -0,0 +1,180 @@ +[otel-test-sa] + otel-instrumentation otel-test-instrumentation + debug-level 0x77f + log localhost:514 local7 debug + config sa/otel.yml + option dontlog-normal + option hard-errors + no option disabled + rate-limit 100.0 + + groups http_response_group + groups http_after_response_group + + scopes on_stream_start + scopes on_stream_stop + scopes on_idle_timeout + + scopes client_session_start + scopes frontend_tcp_request + scopes http_wait_request + scopes http_body_request + scopes frontend_http_request + scopes switching_rules_request + scopes backend_tcp_request + scopes backend_http_request + scopes process_server_rules_request + scopes http_process_request + scopes tcp_rdp_cookie_request + scopes process_sticking_rules_request + scopes client_session_end + scopes server_unavailable + + scopes server_session_start + scopes tcp_response + scopes http_wait_response + scopes process_store_rules_response + scopes http_response http_response-error + scopes server_session_end + + otel-group http_response_group + scopes http_response_1 + scopes http_response_2 + + otel-scope http_response_1 + span "HTTP response" + event "event_content" "hdr.content" res.hdr("content-type") str("; length: ") res.hdr("content-length") str(" bytes") + + otel-scope http_response_2 + span "HTTP response" + event "event_date" "hdr.date" res.hdr("date") str(" / ") res.hdr("last-modified") + + otel-group http_after_response_group + scopes http_after_response + + otel-scope http_after_response + span "HAProxy response" parent "HAProxy session" + status "error" str("http.status_code: ") status + + otel-scope on_stream_start + span "HAProxy session" root + baggage "haproxy_id" var(sess.otel.uuid) + event "event_ip" "src" src str(":") src_port + event "event_be" "be" be_id str(" ") be_name + event "event_ip" "dst" dst str(":") dst_port + event "event_fe" "fe" fe_id str(" ") fe_name + acl acl-test-src-ip src 127.0.0.1 + otel-event on-stream-start if acl-test-src-ip + + otel-scope on_stream_stop + finish * + otel-event on-stream-stop + + otel-scope on_idle_timeout + idle-timeout 1s + span "heartbeat" parent "HAProxy session" + attribute "idle.elapsed" str("idle-check") + otel-event on-idle-timeout + + otel-scope client_session_start + span "Client session" parent "HAProxy session" + otel-event on-client-session-start + + otel-scope frontend_tcp_request + span "Frontend TCP request" parent "Client session" + otel-event on-frontend-tcp-request + + otel-scope http_wait_request + span "HTTP wait request" parent "Frontend TCP request" + finish "Frontend TCP request" + otel-event on-http-wait-request + + otel-scope http_body_request + span "HTTP body request" parent "HTTP wait request" + finish "HTTP wait request" + otel-event on-http-body-request + + otel-scope frontend_http_request + span "Frontend HTTP request" parent "HTTP body request" + attribute "http.method" method + attribute "http.url" url + attribute "http.version" str("HTTP/") req.ver + finish "HTTP body request" + otel-event on-frontend-http-request + + otel-scope switching_rules_request + span "Switching rules request" parent "Frontend HTTP request" + finish "Frontend HTTP request" + otel-event on-switching-rules-request + + otel-scope backend_tcp_request + span "Backend TCP request" parent "Switching rules request" + finish "Switching rules request" + otel-event on-backend-tcp-request + + otel-scope backend_http_request + span "Backend HTTP request" parent "Backend TCP request" + finish "Backend TCP request" + otel-event on-backend-http-request + + otel-scope process_server_rules_request + span "Process server rules request" parent "Backend HTTP request" + finish "Backend HTTP request" + otel-event on-process-server-rules-request + + otel-scope http_process_request + span "HTTP process request" parent "Process server rules request" + finish "Process server rules request" + otel-event on-http-process-request + + otel-scope tcp_rdp_cookie_request + span "TCP RDP cookie request" parent "HTTP process request" + finish "HTTP process request" + otel-event on-tcp-rdp-cookie-request + + otel-scope process_sticking_rules_request + span "Process sticking rules request" parent "TCP RDP cookie request" + finish "TCP RDP cookie request" + otel-event on-process-sticking-rules-request + + otel-scope client_session_end + finish "*req*" + otel-event on-client-session-end + + otel-scope server_unavailable + finish "*req*" "*res*" + otel-event on-server-unavailable + + otel-scope server_session_start + span "Server session" parent "HAProxy session" + finish "Process sticking rules request" + otel-event on-server-session-start + + otel-scope tcp_response + span "TCP response" parent "Server session" + otel-event on-tcp-response + + otel-scope http_wait_response + span "HTTP wait response" parent "TCP response" + finish "TCP response" + otel-event on-http-wait-response + + otel-scope process_store_rules_response + span "Process store rules response" parent "HTTP wait response" + finish "HTTP wait response" + otel-event on-process-store-rules-response + + otel-scope http_response + span "HTTP response" parent "Process store rules response" + attribute "http.status_code" status + finish "Process store rules response" + otel-event on-http-response + + otel-scope http_response-error + span "HTTP response" + status "error" str("http.status_code: ") status + otel-event on-http-response if !acl-http-status-ok + + otel-scope server_session_end + finish "*res*" + otel-event on-server-session-end diff --git a/addons/otel/test/sa/otel.yml b/addons/otel/test/sa/otel.yml new file mode 100644 index 000000000..1320b83c4 --- /dev/null +++ b/addons/otel/test/sa/otel.yml @@ -0,0 +1,246 @@ +exporters: + exporter_traces_otlp_file: + type: otlp_file + thread_name: "OTLP/file trace" + file_pattern: "__sa_traces_log-%F-%N" + alias_pattern: "__traces_log-latest" + flush_interval: 30000000 + flush_count: 256 + file_size: 134217728 + rotate_size: 5 + + exporter_traces_otlp_grpc: + type: otlp_grpc + thread_name: "OTLP/gRPC trace" + endpoint: "http://localhost:4317/v1/traces" + use_ssl_credentials: false +# ssl_credentials_cacert_path: "" +# ssl_credentials_cacert_as_string: "" +# ssl_client_key_path: "" +# ssl_client_key_string: "" +# ssl_client_cert_path: "" +# ssl_client_cert_string: "" +# timeout: 10 +# user_agent: "" +# max_threads: 0 +# compression: "" +# max_concurrent_requests: 0 + + exporter_traces_otlp_http: + type: otlp_http + thread_name: "OTLP/HTTP trace" + endpoint: "http://localhost:4318/v1/traces" + content_type: json + json_bytes_mapping: hexid + debug: false + timeout: 10 + http_headers: + - X-OTel-Header-1: "OTLP HTTP traces test header #1" + - X-OTel-Header-2: "OTLP HTTP traces test header #2" + max_concurrent_requests: 64 + max_requests_per_connection: 8 + ssl_insecure_skip_verify: true +# ssl_ca_cert_path: "" +# ssl_ca_cert_string: "" +# ssl_client_key_path: "" +# ssl_client_key_string: "" +# ssl_client_cert_path: "" +# ssl_client_cert_string: "" +# ssl_min_tls: "" +# ssl_max_tls: "" +# ssl_cipher: "" +# ssl_cipher_suite: "" +# compression: "" + + exporter_traces_dev_null: + type: ostream + filename: /dev/null + + exporter_traces_ostream: + type: ostream + filename: __sa_traces + + exporter_traces_memory: + type: memory + buffer_size: 256 + + exporter_traces_zipkin: + type: zipkin + endpoint: "http://localhost:9411/api/v2/spans" + format: json + service_name: "zipkin-service" +# ipv4: "" +# ipv6: "" + + exporter_metrics_otlp_file: + type: otlp_file + thread_name: "OTLP/file metr" + file_pattern: "__sa_metrics_log-%F-%N" + alias_pattern: "__metrics_log-latest" + flush_interval: 30000000 + flush_count: 256 + file_size: 134217728 + rotate_size: 5 + + exporter_metrics_otlp_grpc: + type: otlp_grpc + thread_name: "OTLP/gRPC metr" + endpoint: "http://localhost:4317/v1/metrics" + use_ssl_credentials: false + + exporter_metrics_otlp_http: + type: otlp_http + thread_name: "OTLP/HTTP metr" + endpoint: "http://localhost:4318/v1/metrics" + content_type: json + debug: false + timeout: 10 + http_headers: + - X-OTel-Header-1: "OTLP HTTP metrics test header #1" + - X-OTel-Header-2: "OTLP HTTP metrics test header #2" + max_concurrent_requests: 64 + max_requests_per_connection: 8 + ssl_insecure_skip_verify: true + + exporter_metrics_dev_null: + type: ostream + filename: /dev/null + + exporter_metrics_ostream: + type: ostream + filename: __sa_metrics + + exporter_metrics_memory: + type: memory + buffer_size: 256 + + exporter_logs_otlp_file: + type: otlp_file + thread_name: "OTLP/file logs" + file_pattern: "__sa_logs_log-%F-%N" + alias_pattern: "__logs_log-latest" + flush_interval: 30000000 + flush_count: 256 + file_size: 134217728 + rotate_size: 5 + + exporter_logs_otlp_grpc: + type: otlp_grpc + thread_name: "OTLP/gRPC logs" + endpoint: "http://localhost:4317/v1/logs" + use_ssl_credentials: false + + exporter_logs_otlp_http: + type: otlp_http + thread_name: "OTLP/HTTP logs" + endpoint: "http://localhost:4318/v1/logs" + content_type: json + debug: false + timeout: 10 + http_headers: + - X-OTel-Header-1: "OTLP HTTP logs test header #1" + - X-OTel-Header-2: "OTLP HTTP logs test header #2" + max_concurrent_requests: 64 + max_requests_per_connection: 8 + ssl_insecure_skip_verify: true + + exporter_logs_dev_null: + type: ostream + filename: /dev/null + + exporter_logs_ostream: + type: ostream + filename: __sa_logs + + exporter_logs_elasticsearch: + type: elasticsearch + host: localhost + port: 9200 + index: logs + response_timeout: 30 + debug: false + http_headers: + - X-OTel-Header-1: "Elasticsearch logs test header #1" + - X-OTel-Header-2: "Elasticsearch logs test header #2" + +readers: + reader_metrics: + thread_name: "reader metr" + export_interval: 10000 + export_timeout: 5000 + +samplers: + sampler_traces: +# type: always_on +# type: always_off +# type: trace_id_ratio_based +# ratio: 1.0 + type: parent_based + delegate: always_on + +processors: + processor_traces_batch: + type: batch + thread_name: "proc/batch trac" + # Note: when the queue is half full, a preemptive notification is sent + # to start the export call. + max_queue_size: 2048 + # Time interval (in ms) between two consecutive exports + schedule_delay: 5000 + # Export 'max_export_batch_size' after every `schedule_delay' milliseconds. + max_export_batch_size: 512 + + processor_traces_single: + type: single + + processor_logs_batch: + type: batch + thread_name: "proc/batch logs" + max_queue_size: 2048 + schedule_delay: 5000 + max_export_batch_size: 512 + + processor_logs_single: + type: single + +providers: + provider_traces: + resources: + - service.version: "1.0.0" + - service.instance.id: "id-sa" + - service.name: "sa" + - service.namespace: "HAProxy traces test" + + provider_metrics: + resources: + - service.version: "1.0.0" + - service.instance.id: "id-sa" + - service.name: "sa" + - service.namespace: "HAProxy metrics test" + + provider_logs: + resources: + - service.version: "1.0.0" + - service.instance.id: "id-sa" + - service.name: "sa" + - service.namespace: "HAProxy logs test" + +signals: + traces: + scope_name: "HAProxy OTEL - traces" + exporters: exporter_traces_otlp_http + samplers: sampler_traces + processors: processor_traces_batch + providers: provider_traces + + metrics: + scope_name: "HAProxy OTEL - metrics" + exporters: exporter_metrics_otlp_http + readers: reader_metrics + providers: provider_metrics + + logs: + scope_name: "HAProxy OTEL - logs" + exporters: exporter_logs_otlp_http + processors: processor_logs_batch + providers: provider_logs diff --git a/addons/otel/test/test-speed.sh b/addons/otel/test/test-speed.sh new file mode 100755 index 000000000..f71300dda --- /dev/null +++ b/addons/otel/test/test-speed.sh @@ -0,0 +1,157 @@ +#!/bin/sh -u +# + SH_ARG_CFG="${1:-}" + SH_ARG_DIR="${2:-${SH_ARG_CFG}}" + SH_LOG_DIR="_logs" +SH_HAPROXY_PIDFILE="${SH_LOG_DIR}/haproxy.pid" + SH_HTTPD_PIDFILE="${SH_LOG_DIR}/thttpd.pid" + SH_USAGE_MSG="usage: $(basename "${0}") cfg [dir]" + + +sh_exit () +{ + sh_backup_clean "${SH_ARG_DIR}" + + test -z "${2:-}" && { + echo + echo "Script killed!" + } + + test -n "${1:-}" && { + echo + echo "${1}" + echo + } + + exit ${2:-64} +} + +sh_backup_make() +{ + _arg_dir="${1}" + _var_file= + + for _var_file in haproxy.cfg otel.cfg otel.yml; do + test -e "${_arg_dir}/${_var_file}.orig" || cp -af "${_arg_dir}/${_var_file}" "${_arg_dir}/${_var_file}.orig" + done + + test "${_arg_dir}" = "fe" && sh_backup_make "be" +} + +sh_backup_clean() +{ + _arg_dir="${1}" + _var_file= + + for _var_file in haproxy.cfg otel.cfg otel.yml; do + test -e "${_arg_dir}/${_var_file}.orig" && mv "${_arg_dir}/${_var_file}.orig" "${_arg_dir}/${_var_file}" + done + + test "${_arg_dir}" = "fe" && sh_backup_clean "be" +} + +sh_httpd_run () +{ + + test -e "${SH_HTTPD_PIDFILE}" && return + + thttpd -p 8000 -d . -nos -nov -l /dev/null -i "${SH_HTTPD_PIDFILE}" +} + +sh_httpd_stop () +{ + test -e "${SH_HTTPD_PIDFILE}" || return + + kill -TERM "$(cat ${SH_HTTPD_PIDFILE})" + rm "${SH_HTTPD_PIDFILE}" +} + +sh_haproxy_run () +{ + _arg_cfg="${1}" + _arg_dir="${2}" + _arg_ratio="${3}" + _var_sed_haproxy= + _var_sed_otel= + _var_sed_yml="s/\(exporters: *exporter_[a-z]*_\).*/\1dev_null/g" + + if test "${_arg_ratio}" = "disabled"; then + _var_sed_otel="s/no \(option disabled\)/\1/" + elif test "${_arg_ratio}" = "off"; then + _var_sed_haproxy="s/^\(.* filter opentelemetry .*\)/#\1/g; s/^\(.* otel-group .*\)/#\1/g" + else + _var_sed_otel="s/\(rate-limit\) 100.0/\1 ${_arg_ratio}/" + fi + + sed "${_var_sed_haproxy}" "${_arg_dir}/haproxy.cfg.orig" > "${_arg_dir}/haproxy.cfg" + sed "${_var_sed_otel}" "${_arg_dir}/otel.cfg.orig" > "${_arg_dir}/otel.cfg" + sed "${_var_sed_yml}" "${_arg_dir}/otel.yml.orig" > "${_arg_dir}/otel.yml" + + if test "${_arg_dir}" = "fe"; then + sed "${_var_sed_yml}" "be/otel.yml.orig" > "be/otel.yml" + + if test "${_arg_ratio}" = "disabled" -o "${_arg_ratio}" = "off"; then + sed "${_var_sed_haproxy}" "be/haproxy.cfg.orig" > "be/haproxy.cfg" + sed "${_var_sed_otel}" "be/otel.cfg.orig" > "be/otel.cfg" + fi + fi + + ./run-${_arg_cfg}.sh "" "${SH_HAPROXY_PIDFILE}" & + sleep 5 +} + +sh_haproxy_stop () +{ + # HAProxy does not create a pidfile if it is not running in daemon mode, + # this is not used but is left regardless. + # + if test -e "${SH_HAPROXY_PIDFILE}"; then + kill -TERM "$(cat ${SH_HAPROXY_PIDFILE})" + rm "${SH_HAPROXY_PIDFILE}" + fi + + pkill --signal SIGUSR1 haproxy + wait +} + +sh_wrk_run () +{ + _arg_ratio="${1}" + + echo "--- rate-limit ${_arg_ratio} --------------------------------------------------" + wrk -c8 -d300 -t8 --latency http://localhost:10080/index.html + echo "----------------------------------------------------------------------" + echo + + sleep 10 +} + + +command -v thttpd >/dev/null 2>&1 || sh_exit "thttpd: command not found" 5 +command -v wrk >/dev/null 2>&1 || sh_exit "wrk: command not found" 6 + +mkdir -p "${SH_LOG_DIR}" || sh_exit "${SH_LOG_DIR}: Cannot create log directory" 1 + +if test "${SH_ARG_CFG}" = "all"; then + "${0}" sa sa > "${SH_LOG_DIR}/README-speed-sa" + "${0}" cmp cmp > "${SH_LOG_DIR}/README-speed-cmp" + "${0}" ctx ctx > "${SH_LOG_DIR}/README-speed-ctx" + "${0}" fe-be fe > "${SH_LOG_DIR}/README-speed-fe-be" + exit 0 +fi + +test -z "${SH_ARG_CFG}" -o -z "${SH_ARG_DIR}" && sh_exit "${SH_USAGE_MSG}" 4 +test -f "run-${SH_ARG_CFG}.sh" || sh_exit "run-${SH_ARG_CFG}.sh: No such configuration script" 2 +test -d "${SH_ARG_DIR}" || sh_exit "${SH_ARG_DIR}: No such directory" 3 + +trap sh_exit INT TERM + +sh_backup_make "${SH_ARG_DIR}" +sh_httpd_run +for _var_ratio in 100.0 75.0 50.0 25.0 10.0 2.5 0.0 disabled off; do + sh_haproxy_run "${SH_ARG_CFG}" "${SH_ARG_DIR}" "${_var_ratio}" + sh_wrk_run "${_var_ratio}" + sh_haproxy_stop +done +sh_httpd_stop +sh_exit "" 0