diff --git a/src/lwt/opentelemetry_lwt.ml b/src/lwt/opentelemetry_lwt.ml index d6545d05..7689dcfd 100644 --- a/src/lwt/opentelemetry_lwt.ml +++ b/src/lwt/opentelemetry_lwt.ml @@ -11,6 +11,10 @@ module GC_metrics = GC_metrics module Metrics_callbacks = Metrics_callbacks module Trace_context = Trace_context +(** See {!Opentelemetry.Scope}; but with several functions overridden to use + [Lwt.Sequence_associated_storage] instead of our homegrown {!Thread_local}. + + @see Lwt.Sequence_associated_storage *) module Scope = struct include Scope @@ -20,6 +24,10 @@ module Scope = struct (**/**) + (** Obtain current scope from Lwt's sequence-associated storage, if one + exists; see {!with_scope}. + + @see Lwt.get *) let get_surrounding ?scope () : t option = let surrounding = Lwt.get _global_scope_key in match scope, surrounding with @@ -27,6 +35,12 @@ module Scope = struct | None, Some _ -> surrounding | None, None -> None + (** [with_scope sc f] calls [f()] in a context where [sc] is the + sequence-local implicit {!Scope.t}; then reverts to the previous local + scope, if any. Lwt will suspend and restore this implicit scope as tasks + are suspended and restored. + + @see Lwt.with_value *) let[@inline] with_scope (sc : t) (f : unit -> 'a) : 'a = Lwt.with_value _global_scope_key (Some sc) f end diff --git a/src/opentelemetry.ml b/src/opentelemetry.ml index 8fa159c5..6646bd6d 100644 --- a/src/opentelemetry.ml +++ b/src/opentelemetry.ml @@ -530,14 +530,24 @@ module Scope = struct (**/**) - (** Obtain current scope from thread-local storage, if available *) + (** Obtain current scope from thread-local storage, if available. + + {b NOTE} In an Lwt context, make sure to use + {!Opentelemetry_lwt.Scope.get_surrounding} instead, as thread-local + storage will probably not interact with suspension/resumption of green + threads as expected. *) let get_surrounding ?scope () : t option = match scope with | Some _ -> scope | None -> Thread_local.get _global_scope (** [with_scope sc f] calls [f()] in a context where [sc] is the - (thread)-local scope, then reverts to the previous local scope, if any. *) + (thread)-local scope, then reverts to the previous local scope, if any. + + {b NOTE} In an Lwt context, make sure to use + {!Opentelemetry_lwt.Scope.with_scope} instead, as thread-local storage + will probably not interact with suspension/resumption of green threads as + expected. *) let[@inline] with_scope (sc : t) (f : unit -> 'a) : 'a = Thread_local.with_ _global_scope sc (fun _ -> f ()) end @@ -728,6 +738,11 @@ module Trace = struct surrounding context, or [scope], or [trace_id], but will always create a fresh new trace ID. + {b NOTE} In an Lwt context, make sure to use + {!Opentelemetry_lwt.Trace.with_} instead, as thread-local storage will + probably not interact with suspension/resumption of green threads as + expected. + {b NOTE} be careful not to call this inside a Gc alarm, as it can cause deadlocks. *) let with_ ?(force_new_trace_id = false) ?trace_state ?service_name