From 35f8bbc67d82ee199ac0662db6819a476bd62d87 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Thu, 4 Dec 2025 14:16:08 -0500 Subject: [PATCH] feat exporter: split tick/on_tick again --- src/core/exporter.ml | 79 +++++++------------------------------------- src/core/span.mli | 6 +++- 2 files changed, 17 insertions(+), 68 deletions(-) diff --git a/src/core/exporter.ml b/src/core/exporter.ml index c077cfe7..8bd96b7f 100644 --- a/src/core/exporter.ml +++ b/src/core/exporter.ml @@ -9,17 +9,14 @@ open Common_ open Opentelemetry_emitter -open struct - module Proto = Opentelemetry_proto -end - type t = { emit_spans: Proto.Trace.span Emitter.t; emit_metrics: Proto.Metrics.metric Emitter.t; emit_logs: Proto.Logs.log_record Emitter.t; - on_tick: Cb_set.t; - (** Set of callbacks for "on tick". Should be triggered regularly for - background processing, timeout checks, etc. *) + on_tick: (unit -> unit) -> unit; + tick: unit -> unit; + (** Call all the callbacks registered with [on_tick]. Should be triggered + regularly for background processing, timeout checks, etc. *) cleanup: on_done:(unit -> unit) -> unit -> unit; (** [cleanup ~on_done ()] is called when the exporter is shut down, and is responsible for sending remaining batches, flushing sockets, etc. @@ -30,12 +27,13 @@ type t = { (** Dummy exporter, does nothing *) let dummy () : t = - let on_tick = Cb_set.create () in + let ticker = Cb_set.create () in { emit_spans = Emitter.dummy (); emit_metrics = Emitter.dummy (); emit_logs = Emitter.dummy (); - on_tick; + on_tick = Cb_set.register ticker; + tick = (fun () -> Cb_set.trigger ticker); cleanup = (fun ~on_done () -> on_done ()); } @@ -48,72 +46,19 @@ let[@inline] send_metrics (self : t) (l : Proto.Metrics.metric list) = let[@inline] send_logs (self : t) (l : Proto.Logs.log_record list) = Emitter.emit self.emit_logs l -let on_tick (self : t) f = Cb_set.register self.on_tick f +let[@inline] on_tick (self : t) f = self.on_tick f (** Do background work. Call this regularly if the collector doesn't already have a ticker thread or internal timer. *) let tick (self : t) = - Cb_set.trigger self.on_tick; - (* also tick each emitter! *) + (* make sure emitters get the chance to check timeouts, flush, etc. *) let now = Mtime_clock.now () in Emitter.tick ~now self.emit_spans; Emitter.tick ~now self.emit_metrics; Emitter.tick ~now self.emit_logs; + + (* call the callbacks *) + self.tick (); () let[@inline] cleanup (self : t) ~on_done : unit = self.cleanup ~on_done () - -(** Main exporter, used by the main tracing functions. - - It is better to pass an explicit exporter when possible. *) -module Main_exporter = struct - (* hidden *) - open struct - (* a list of callbacks automatically added to the main exporter *) - let on_tick_cbs_ = Alist.make () - - let exporter : t option Atomic.t = Atomic.make None - end - - (** Set the global exporter *) - let set (exp : t) : unit = - List.iter (on_tick exp) (Alist.get on_tick_cbs_); - Atomic.set exporter (Some exp) - - (** Remove current exporter, if any. - @param on_done see {!t#cleanup}, @since 0.12 *) - let remove ~on_done () : unit = - match Atomic.exchange exporter None with - | None -> () - | Some exp -> - tick exp; - cleanup exp ~on_done - - (** Is there a configured exporter? *) - let present () : bool = Option.is_some (Atomic.get exporter) - - (** Current exporter, if any *) - let[@inline] get () : t option = Atomic.get exporter - - let add_on_tick_callback f = - Alist.add on_tick_cbs_ f; - Option.iter (fun exp -> on_tick exp f) (get ()) -end - -let (set_backend [@deprecated "use `Main_exporter.set`"]) = Main_exporter.set - -let (remove_backend [@deprecated "use `Main_exporter.remove`"]) = - Main_exporter.remove - -let (has_backend [@deprecated "use `Main_exporter.present`"]) = - Main_exporter.present - -let (get_backend [@deprecated "use `Main_exporter.ge"]) = Main_exporter.get - -let with_setup_debug_backend ?(on_done = ignore) (exp : t) ?(enable = true) () f - = - if enable then ( - Main_exporter.set exp; - Fun.protect ~finally:(fun () -> cleanup exp ~on_done) f - ) else - f () diff --git a/src/core/span.mli b/src/core/span.mli index 34a4e858..d4722edc 100644 --- a/src/core/span.mli +++ b/src/core/span.mli @@ -47,6 +47,8 @@ val id : t -> Span_id.t val trace_id : t -> Trace_id.t +val is_not_dummy : t -> bool + val create_new : ?kind:kind -> ?id:Span_id.t -> @@ -96,7 +98,9 @@ val add_links' : t -> (unit -> Span_link.t list) -> unit Note that this takes a function that produces links, and will only call it if there is an instrumentation backend. *) -val add_attrs : t -> (unit -> Key_value.t list) -> unit +val add_attrs : t -> Key_value.t list -> unit + +val add_attrs' : t -> (unit -> Key_value.t list) -> unit val set_status : t -> Span_status.t -> unit (** set the span status.