From 1b538930aeca6eef2c81acec9e05512cb8f4a925 Mon Sep 17 00:00:00 2001 From: Corentin Leruth Date: Fri, 2 Aug 2024 08:52:43 +0200 Subject: [PATCH] add support for per-signal urls --- src/client-ocurl/common_.ml | 26 ++++- src/client-ocurl/config.ml | 59 ++++++++-- src/client-ocurl/config.mli | 28 ++++- .../opentelemetry_client_ocurl.ml | 20 +--- .../opentelemetry_client_ocurl.mli | 6 -- tests/ocurl/test_get_url.expected | 67 +++++++++++- tests/ocurl/test_get_url.ml | 102 ++++++++++++++++-- 7 files changed, 262 insertions(+), 46 deletions(-) diff --git a/src/client-ocurl/common_.ml b/src/client-ocurl/common_.ml index f688ff2b..9388497b 100644 --- a/src/client-ocurl/common_.ml +++ b/src/client-ocurl/common_.ml @@ -15,12 +15,30 @@ let debug_ = let default_url = "http://localhost:4318" -let url = - ref (try Sys.getenv "OTEL_EXPORTER_OTLP_ENDPOINT" with _ -> default_url) +let make_get_from_env env_name = + let value = ref None in + fun () -> + match !value with + | None -> + value := Sys.getenv_opt env_name; + !value + | Some value -> Some value -let get_url () = !url +let get_url_from_env = make_get_from_env "OTEL_EXPORTER_OTLP_ENDPOINT" -let set_url s = url := s +let get_url_traces_from_env = + make_get_from_env "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT" + +let get_url_metrics_from_env = + make_get_from_env "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT" + +let get_url_logs_from_env = make_get_from_env "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT" + +let remove_trailing_slash url = + if url <> "" && String.get url (String.length url - 1) = '/' then + String.sub url 0 (String.length url - 1) + else + url let parse_headers s = let parse_header s = diff --git a/src/client-ocurl/config.ml b/src/client-ocurl/config.ml index 2ea68fb7..1ca45a54 100644 --- a/src/client-ocurl/config.ml +++ b/src/client-ocurl/config.ml @@ -2,7 +2,9 @@ open Common_ type t = { debug: bool; - url: string; + url_traces: string; + url_metrics: string; + url_logs: string; headers: (string * string) list; batch_timeout_ms: int; bg_threads: int; @@ -16,7 +18,9 @@ let pp out self = let ppheaders = Format.pp_print_list pp_header in let { debug; - url; + url_traces; + url_metrics; + url_logs; headers; batch_timeout_ms; bg_threads; @@ -27,18 +31,53 @@ let pp out self = self in Format.fprintf out - "{@[ debug=%B;@ url=%S;@ headers=%a;@ batch_timeout_ms=%d; bg_threads=%d;@ \ - ticker_thread=%B;@ ticker_interval_ms=%d;@ self_trace=%B @]}" - debug url ppheaders headers batch_timeout_ms bg_threads ticker_thread - ticker_interval_ms self_trace + "{@[ debug=%B;@ url_traces=%S;@ url_metrics=%S;@ url_logs=%S;@ \ + headers=%a;@ batch_timeout_ms=%d; bg_threads=%d;@ ticker_thread=%B;@ \ + ticker_interval_ms=%d;@ self_trace=%B @]}" + debug url_traces url_metrics url_logs ppheaders headers batch_timeout_ms + bg_threads ticker_thread ticker_interval_ms self_trace -let make ?(debug = !debug_) ?(url = get_url ()) ?(headers = get_headers ()) - ?(batch_timeout_ms = 2_000) ?(bg_threads = 4) ?(ticker_thread = true) - ?(ticker_interval_ms = 500) ?(self_trace = false) () : t = +let make ?(debug = !debug_) ?url ?url_traces ?url_metrics ?url_logs + ?(headers = get_headers ()) ?(batch_timeout_ms = 2_000) ?(bg_threads = 4) + ?(ticker_thread = true) ?(ticker_interval_ms = 500) ?(self_trace = false) () + : t = let bg_threads = max 1 (min bg_threads 32) in + + let url_traces, url_metrics, url_logs = + let base_url = + match url with + | None -> Option.value (get_url_from_env ()) ~default:default_url + | Some url -> remove_trailing_slash url + in + let url_traces = + match url_traces with + | None -> + Option.value + (get_url_traces_from_env ()) + ~default:(base_url ^ "/v1/traces") + | Some url -> url + in + let url_metrics = + match url_metrics with + | None -> + Option.value + (get_url_metrics_from_env ()) + ~default:(base_url ^ "/v1/metrics") + | Some url -> url + in + let url_logs = + match url_logs with + | None -> + Option.value (get_url_logs_from_env ()) ~default:(base_url ^ "/v1/logs") + | Some url -> url + in + url_traces, url_metrics, url_logs + in { debug; - url; + url_traces; + url_metrics; + url_logs; headers; batch_timeout_ms; bg_threads; diff --git a/src/client-ocurl/config.mli b/src/client-ocurl/config.mli index 07b34c43..b24e350d 100644 --- a/src/client-ocurl/config.mli +++ b/src/client-ocurl/config.mli @@ -2,9 +2,9 @@ type t = private { debug: bool; - url: string; - (** Url of the endpoint. Default is "http://localhost:4318", - or "OTEL_EXPORTER_OTLP_ENDPOINT" if set. *) + url_traces: string; (** Url to send traces *) + url_metrics: string; (** Url to send metrics*) + url_logs: string; (** Url to send logs *) headers: (string * string) list; (** API headers sent to the endpoint. Default is none or "OTEL_EXPORTER_OTLP_HEADERS" if set. *) @@ -39,6 +39,9 @@ type t = private { val make : ?debug:bool -> ?url:string -> + ?url_traces:string -> + ?url_metrics:string -> + ?url_logs:string -> ?headers:(string * string) list -> ?batch_timeout_ms:int -> ?bg_threads:int -> @@ -48,6 +51,25 @@ val make : unit -> t (** Make a configuration. + + @param url base url used to construct per-signal urls. Per-signal url options take precedence over this base url. + Default is "http://localhost:4318", or "OTEL_EXPORTER_OTLP_ENDPOINT" if set. + + Example of constrcuted per-singal urls with the base url http://localhost:4318 + - Traces: http://localhost:4318/v1/traces + - Metrics: http://localhost:4318/v1/metrics + - Logs: http://localhost:4318/v1/logs + + Use per-signal url options if different urls are needed for each signal type. + + @param url_traces url to send traces, or "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT" if set. + The url is used as-is without any modification. + + @param url_metrics url to send metrics, or "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT" if set. + The url is used as-is without any modification. + + @param url_logs url to send logs, or "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT" if set. + The url is used as-is without any modification. *) val pp : Format.formatter -> t -> unit diff --git a/src/client-ocurl/opentelemetry_client_ocurl.ml b/src/client-ocurl/opentelemetry_client_ocurl.ml index 9d858544..0cf23dea 100644 --- a/src/client-ocurl/opentelemetry_client_ocurl.ml +++ b/src/client-ocurl/opentelemetry_client_ocurl.ml @@ -145,8 +145,7 @@ end = struct mutable send_threads: Thread.t array; (** Threads that send data via http *) } - let send_http_ ~stop ~config (client : Curl.t) encoder ~path ~encode x : unit - = + let send_http_ ~stop ~config (client : Curl.t) encoder ~url ~encode x : unit = let@ _sc = Self_trace.with_ ~kind:Span.Span_kind_producer "otel-ocurl.send-http" in @@ -160,15 +159,7 @@ end = struct Pbrt.Encoder.to_string encoder in - let url = - let url = config.Config.url in - if url <> "" && String.get url (String.length url - 1) = '/' then - String.sub url 0 (String.length url - 1) - else - url - in - let url = url ^ path in - if !debug_ || config.debug then + if !debug_ || config.Config.debug then Printf.eprintf "opentelemetry: send http POST to %s (%dB)\n%!" url (String.length data); let headers = @@ -227,7 +218,7 @@ end = struct let x = Logs_service.default_export_logs_service_request ~resource_logs:l () in - send_http_ ~stop ~config client encoder ~path:"/v1/logs" + send_http_ ~stop ~config client encoder ~url:config.Config.url_logs ~encode:Logs_service.encode_pb_export_logs_service_request x let send_metrics_http ~stop ~config curl encoder @@ -242,7 +233,7 @@ end = struct Metrics_service.default_export_metrics_service_request ~resource_metrics:l () in - send_http_ ~stop ~config curl encoder ~path:"/v1/metrics" + send_http_ ~stop ~config curl encoder ~url:config.Config.url_metrics ~encode:Metrics_service.encode_pb_export_metrics_service_request x let send_traces_http ~stop ~config curl encoder @@ -256,7 +247,7 @@ end = struct let x = Trace_service.default_export_trace_service_request ~resource_spans:l () in - send_http_ ~stop ~config curl encoder ~path:"/v1/traces" + send_http_ ~stop ~config curl encoder ~url:config.Config.url_traces ~encode:Trace_service.encode_pb_export_trace_service_request x let[@inline] send_event (self : t) ev : unit = B_queue.push self.q ev @@ -514,7 +505,6 @@ let setup_ ?(stop = Atomic.make false) ?(config : Config.t = Config.make ()) () let ((module B) as backend) = create_backend ~stop ~config () in Opentelemetry.Collector.set_backend backend; - if config.url <> get_url () then set_url config.url; Atomic.set Self_trace.enabled config.self_trace; if config.ticker_thread then ( diff --git a/src/client-ocurl/opentelemetry_client_ocurl.mli b/src/client-ocurl/opentelemetry_client_ocurl.mli index a2c01177..8a963692 100644 --- a/src/client-ocurl/opentelemetry_client_ocurl.mli +++ b/src/client-ocurl/opentelemetry_client_ocurl.mli @@ -3,12 +3,6 @@ https://opentelemetry.io/docs/reference/specification/protocol/exporter/ *) -val get_url : unit -> string - -val set_url : string -> unit -(** Url of the endpoint. Default is "http://localhost:4318", - or "OTEL_EXPORTER_OTLP_ENDPOINT" if set. *) - val get_headers : unit -> (string * string) list val set_headers : (string * string) list -> unit diff --git a/tests/ocurl/test_get_url.expected b/tests/ocurl/test_get_url.expected index 0b9a4214..56d92a58 100644 --- a/tests/ocurl/test_get_url.expected +++ b/tests/ocurl/test_get_url.expected @@ -1 +1,66 @@ -ocurl url = http://localhost:3000 +--- default_url --- +url_traces = http://localhost:4318/v1/traces +url_metrics = http://localhost:4318/v1/metrics +url_logs = http://localhost:4318/v1/logs +------ + +--- base_url_from_config --- +url_traces = http://localhost:3000/v1/traces +url_metrics = http://localhost:3000/v1/metrics +url_logs = http://localhost:3000/v1/logs +------ + +--- base_url_from_env --- +url_traces = http://localhost:5000/v1/traces +url_metrics = http://localhost:5000/v1/metrics +url_logs = http://localhost:5000/v1/logs +------ + +--- base_url_from_both_config_and_env --- +url_traces = http://localhost:3000/v1/traces +url_metrics = http://localhost:3000/v1/metrics +url_logs = http://localhost:3000/v1/logs +------ + +--- override_trace_url_from_config --- +url_traces = http://localhost:3001/send/traces +url_metrics = http://localhost:3000/v1/metrics +url_logs = http://localhost:3000/v1/logs +------ + +--- override_trace_url_from_config --- +url_traces = http://localhost:3001/send/traces +url_metrics = http://localhost:5000/v1/metrics +url_logs = http://localhost:5000/v1/logs +------ + +--- override_trace_url_from_both_config_and_env --- +url_traces = http://localhost:3001/send/traces/config +url_metrics = http://localhost:5000/v1/metrics +url_logs = http://localhost:5000/v1/logs +------ + +--- set_all_in_config --- +url_traces = http://localhost:3001/send/traces +url_metrics = http://localhost:3002/send/metrics +url_logs = http://localhost:3003/send/logs +------ + +--- set_all_in_config --- +url_traces = http://localhost:3001/send/traces +url_metrics = http://localhost:3002/send/metrics +url_logs = http://localhost:3003/send/logs +------ + +--- remove_trailing_slash_config --- +url_traces = http://localhost:3001/send/traces +url_metrics = http://localhost:3002/send/metrics +url_logs = http://localhost:3003/send/logs +------ + +--- remove_trailing_slash_config --- +url_traces = http://localhost:3001/send/traces +url_metrics = http://localhost:3002/send/metrics +url_logs = http://localhost:3003/send/logs +------ + diff --git a/tests/ocurl/test_get_url.ml b/tests/ocurl/test_get_url.ml index 1e142015..2fe651c4 100644 --- a/tests/ocurl/test_get_url.ml +++ b/tests/ocurl/test_get_url.ml @@ -1,9 +1,97 @@ -let url = "http://localhost:3000" +open Opentelemetry_client_ocurl -let ocurl () = - let config = Opentelemetry_client_ocurl.Config.make ~url () in - Opentelemetry_client_ocurl.with_setup ~config () @@ fun () -> - let url = Opentelemetry_client_ocurl.get_url () in - print_endline @@ Printf.sprintf "ocurl url = %s" url +let test_urls ~name config = + Printf.printf "--- %s ---\n" name; + Printf.printf "url_traces = %s\n" config.Config.url_traces; + Printf.printf "url_metrics = %s\n" config.Config.url_metrics; + Printf.printf "url_logs = %s\n" config.Config.url_logs; + print_endline "------\n" -let () = ocurl () +let default_url () = + let config = Config.make () in + test_urls ~name:"default_url" config + +let base_url_from_config () = + let config = Config.make ~url:"http://localhost:3000" () in + test_urls ~name:"base_url_from_config" config + +let base_url_from_env () = + Unix.putenv "OTEL_EXPORTER_OTLP_ENDPOINT" "http://localhost:5000"; + let config = Config.make () in + test_urls ~name:"base_url_from_env" config + +let base_url_from_both_config_and_env () = + (* url from config should take precedence *) + Unix.putenv "OTEL_EXPORTER_OTLP_ENDPOINT" "http://localhost:5000"; + let config = Config.make ~url:"http://localhost:3000" () in + test_urls ~name:"base_url_from_both_config_and_env" config + +let override_trace_url_from_config () = + let config = + Config.make ~url:"http://localhost:3000" + ~url_traces:"http://localhost:3001/send/traces" () + in + test_urls ~name:"override_trace_url_from_config" config + +let override_trace_url_from_env () = + Unix.putenv "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT" + "http://localhost:3001/send/traces"; + let config = Config.make () in + test_urls ~name:"override_trace_url_from_config" config + +let override_trace_url_from_both_config_and_env () = + Unix.putenv "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT" + "http://localhost:3001/send/traces/env"; + let config = + Config.make ~url_traces:"http://localhost:3001/send/traces/config" () + in + test_urls ~name:"override_trace_url_from_both_config_and_env" config + +let set_all_in_config () = + let config = + Config.make ~url_traces:"http://localhost:3001/send/traces" + ~url_metrics:"http://localhost:3002/send/metrics" + ~url_logs:"http://localhost:3003/send/logs" () + in + test_urls ~name:"set_all_in_config" config + +let set_all_in_env () = + Unix.putenv "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT" + "http://localhost:3001/send/traces"; + Unix.putenv "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT" + "http://localhost:3002/send/metrics"; + Unix.putenv "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT" + "http://localhost:3003/send/logs"; + let config = Config.make () in + test_urls ~name:"set_all_in_config" config + +let remove_trailing_slash_config () = + let config = Config.make ~url:"http://localhost:3000/" () in + test_urls ~name:"remove_trailing_slash_config" config + +let remove_trailing_slash_env () = + Unix.putenv "OTEL_EXPORTER_OTLP_ENDPOINT" "http://localhost:3000/"; + let config = Config.make () in + test_urls ~name:"remove_trailing_slash_config" config + +let () = default_url () + +let () = base_url_from_config () + +let () = base_url_from_env () + +let () = base_url_from_both_config_and_env () + +let () = override_trace_url_from_config () + +let () = override_trace_url_from_env () + +let () = override_trace_url_from_both_config_and_env () + +let () = set_all_in_config () + +let () = set_all_in_env () + +let () = remove_trailing_slash_config () + +let () = remove_trailing_slash_env ()