diff --git a/src/trace/opentelemetry_trace.ml b/src/trace/opentelemetry_trace.ml index 2c240842..c3ed6a02 100644 --- a/src/trace/opentelemetry_trace.ml +++ b/src/trace/opentelemetry_trace.ml @@ -21,15 +21,27 @@ end open Extensions -open struct - type state = { - clock: Opentelemetry_core.Clock.t; - exporter: OTEL.Exporter.t; - } +module Ambient_span_provider_ = struct + let get_current_span () = + match OTEL.Ambient_span.get () with + | None -> None + | Some sp -> Some (Span_otel sp) - let create_state ~(exporter : OTEL.Exporter.t) () : state = - let clock = OTEL.Clock.ptime_clock in - { clock; exporter } + let with_current_span_set_to () span f = + match span with + | Span_otel sp -> OTEL.Ambient_span.with_ambient sp (fun () -> f span) + | _ -> f span + + let callbacks : unit Trace.Ambient_span_provider.Callbacks.t = + { get_current_span; with_current_span_set_to } + + let provider = Trace.Ambient_span_provider.ASP_some ((), callbacks) +end + +let ambient_span_provider = Ambient_span_provider_.provider + +open struct + type state = unit (* sanity check: otrace meta-map must be the same as hmap *) let () = ignore (fun (k : _ Hmap.key) : _ Ambient_context.Context.key -> k) @@ -38,9 +50,9 @@ open struct let k_span_ctx : OTEL.Span_ctx.t Ambient_context.Context.key = OTEL.Span_ctx.k_ambient - let enter_span (self : state) ~__FUNCTION__ ~__FILE__ ~__LINE__ ~level:_ - ~params:_ ~(data : (_ * Trace.user_data) list) ~parent name : Trace.span = - let start_time = OTEL.Clock.now self.clock in + let enter_span () ~__FUNCTION__ ~__FILE__ ~__LINE__ ~level:_ ~params:_ + ~(data : (_ * Trace.user_data) list) ~parent name : Trace.span = + let start_time = OTEL.Clock.now_main () in let trace_id, parent_id = match parent with | Trace.P_some (Span_otel sp) -> @@ -93,13 +105,15 @@ open struct Span_otel otel_sp - let exit_span (self : state) sp = + let exit_span () sp = match sp with | Span_otel span when OTEL.Span.is_not_dummy span -> (* emit the span after setting the end timestamp *) - let end_time = OTEL.Clock.now self.clock in + let end_time = OTEL.Clock.now_main () in OTEL.Proto.Trace.span_set_end_time_unix_nano span end_time; - self.exporter.OTEL.Exporter.export (OTEL.Any_signal_l.Spans [ span ]) + + (* use the current tracer *) + OTEL.Trace_provider.emit span | _ -> () let add_data_to_span _self span (data : (_ * Trace.user_data) list) = @@ -116,9 +130,9 @@ open struct | Info -> OTEL.Log_record.Severity_number_info | Warning -> OTEL.Log_record.Severity_number_warn - let message (self : state) ~(level : Trace_core.Level.t) ~params:_ ~data ~span - msg : unit = - let observed_time_unix_nano = OTEL.Clock.now self.clock in + let message () ~(level : Trace_core.Level.t) ~params:_ ~data ~span msg : unit + = + let observed_time_unix_nano = OTEL.Clock.now_main () in let trace_id, span_id = match span with | Some (Span_otel sp) -> @@ -135,10 +149,10 @@ open struct OTEL.Log_record.make ~severity ?trace_id ?span_id ~attrs:data ~observed_time_unix_nano (`String msg) in - self.exporter.OTEL.Exporter.export (OTEL.Any_signal_l.Logs [ log ]) + OTEL.Log_provider.emit log - let metric (self : state) ~level:_ ~params:_ ~data:attrs name v : unit = - let now = OTEL.Clock.now self.clock in + let metric () ~level:_ ~params:_ ~data:attrs name v : unit = + let now = OTEL.Clock.now_main () in let kind = let open Trace_core.Core_ext in match v with @@ -157,8 +171,7 @@ open struct | `sum v -> [ OTEL.Metrics.sum ~name [ v ] ] | `hist h -> [ OTEL.Metrics.histogram ~name [ h ] ] in - if m <> [] then - self.exporter.OTEL.Exporter.export (OTEL.Any_signal_l.Metrics m) + if m <> [] then OTEL.Emitter.emit (OTEL.Meter_provider.get ()).emit m let extension (_self : state) ~level:_ ev = match ev with @@ -174,35 +187,17 @@ open struct | Ev_record_exn _ -> () | _ -> () - let shutdown self = OTEL.Exporter.shutdown self.exporter + let init () = Trace.set_ambient_context_provider ambient_span_provider + + let shutdown () = () let callbacks : state Trace.Collector.Callbacks.t = Trace.Collector.Callbacks.make ~enter_span ~exit_span ~add_data_to_span - ~message ~metric ~extension ~shutdown () + ~message ~metric ~extension ~init ~shutdown () end -module Ambient_span_provider_ = struct - let get_current_span () = - match OTEL.Ambient_span.get () with - | None -> None - | Some sp -> Some (Span_otel sp) - - let with_current_span_set_to () span f = - match span with - | Span_otel sp -> OTEL.Ambient_span.with_ambient sp (fun () -> f span) - | _ -> f span - - let callbacks : unit Trace.Ambient_span_provider.Callbacks.t = - { get_current_span; with_current_span_set_to } - - let provider = Trace.Ambient_span_provider.ASP_some ((), callbacks) -end - -let ambient_span_provider = Ambient_span_provider_.provider - -let collector_of_exporter (exporter : OTEL.Exporter.t) : Trace_core.collector = - let st = create_state ~exporter () in - Trace_core.Collector.C_some (st, callbacks) +let collector : Trace_core.collector = + Trace_core.Collector.C_some ((), callbacks) let with_ambient_span (sp : Trace.span) f = match sp with @@ -235,37 +230,11 @@ let record_exception sp exn bt : unit = if Trace.enabled () then Trace.extension_event @@ Ev_record_exn { sp; exn; bt } -(** Collector that forwards to the {b currently installed} OTEL exporter. *) -let collector_main_otel_exporter () : Trace.collector = - (* Create a dynamic exporter that forwards to the currently installed main - exporter at call time. *) - let dynamic_exp : OTEL.Exporter.t = - { - OTEL.Exporter.export = - (fun sig_ -> - match OTEL.Sdk.get () with - | None -> () - | Some exp -> exp.OTEL.Exporter.export sig_); - active = (fun () -> Aswitch.dummy); - shutdown = ignore; - self_metrics = (fun () -> OTEL.Sdk.self_metrics ()); - } - in - collector_of_exporter dynamic_exp - -let (collector - [@deprecated "use collector_of_exporter or collector_main_otel_exporter"]) - = - collector_main_otel_exporter - -let setup () = - Trace.set_ambient_context_provider Ambient_span_provider_.provider; - Trace.setup_collector @@ collector_main_otel_exporter () +let setup () = Trace.setup_collector collector let setup_with_otel_exporter exp : unit = - let coll = collector_of_exporter exp in OTEL.Sdk.set exp; - Trace.setup_collector coll + Trace.setup_collector collector let setup_with_otel_backend = setup_with_otel_exporter diff --git a/src/trace/opentelemetry_trace.mli b/src/trace/opentelemetry_trace.mli index 995ab0e7..3037f6d2 100644 --- a/src/trace/opentelemetry_trace.mli +++ b/src/trace/opentelemetry_trace.mli @@ -5,10 +5,10 @@ that use [ocaml-trace], and they will automatically emit OpenTelemetry spans and logs. - Ambient_context is used to track the current ambient span. + [Ambient_context] is used to propagate the current span to child spans. - We use [Trace_core.extension_event] to add more features on top of the - common tracing interface. For example to set the "span kind": + [Trace_core.extension_event] is used to expose OTEL-specific features on top + of the common tracing interface, e.g. to set the span kind: {[ let@ span = Trace_core.with_span ~__FILE__ ~__LINE__ "my-span" in @@ -44,23 +44,26 @@ module Extensions : sig end val setup : unit -> unit -(** Install the OTEL backend as a Trace collector *) +(** Install the OTEL backend as a [Trace] collector. The trace collector will + use {!Trace_provider.get}, {!Log_provider.get}, and {!Meter_provider.get} to + get the current tracer, logger, meter and use that to emit signals. + + This will not do much until a proper {!OTEL.Exporter.t} is installed via + {!OTEL.Sdk.set}. *) val setup_with_otel_exporter : OTEL.Exporter.t -> unit -(** Same as {!setup}, but using the given exporter *) +(** Same as {!setup}, but also calls [OTEL.Sdk.set otel_exporter] *) val setup_with_otel_backend : OTEL.Exporter.t -> unit [@@deprecated "use setup_with_otel_exporter"] -val collector_of_exporter : OTEL.Exporter.t -> Trace_core.collector - -val collector : unit -> Trace_core.collector -[@@deprecated "use collector_of_exporter, avoid global state"] -(** Make a Trace collector that uses the main OTEL backend to send spans and - logs *) +val collector : Trace_core.collector +(** Make a Trace collector that uses the main OTEL providers to emit traces, + metrics, and logs *) val ambient_span_provider : Trace_core.Ambient_span_provider.t -(** Uses {!Ambient_context} to provide contextual spans in {!Trace_core}.*) +(** Uses {!Ambient_context} to provide contextual spans in {!Trace_core}. It is + automatically installed by the {!collector}. *) val link_spans : Otrace.span -> Otrace.span -> unit (** [link_spans sp1 sp2] modifies [sp1] by adding a span link to [sp2].