mirror of
https://github.com/ocaml-tracing/ocaml-trace.git
synced 2026-03-07 18:37:56 -05:00
refactor core library
much cleaner now, and simpler. - `span` is an open sum type, so it can carry as much info as we want from enter to exit. This means most collectors shouldn't even need a global table for spans! - merge manual spans and spans. It's just spans now. Keep old Trace_core.xxx_manual_xxx functions but deprecate them - add `extension_parameter` to carry additional info to collector (eg OTEL span kind, TEF sync/async, maybe span links, etc) - make the collector into a record of callbacks + a state, for efficiency (but also to make it easier to extend in the future with callbacks that have a default implementation )
This commit is contained in:
parent
1c9a869148
commit
5018a9ead7
5 changed files with 312 additions and 323 deletions
|
|
@ -6,103 +6,93 @@
|
|||
|
||||
open Types
|
||||
|
||||
let dummy_span : span = Int64.min_int
|
||||
let dummy_trace_id : trace_id = "<dummy>"
|
||||
type span += Span_dummy
|
||||
|
||||
let dummy_explicit_span : explicit_span =
|
||||
{ span = dummy_span; trace_id = dummy_trace_id; meta = Meta_map.empty }
|
||||
(** A fake span that never emits data. All collectors should handle this span by
|
||||
doing nothing. *)
|
||||
let dummy_span : span = Span_dummy
|
||||
|
||||
let dummy_explicit_span_ctx : explicit_span_ctx =
|
||||
{ span = dummy_span; trace_id = dummy_trace_id }
|
||||
module Callbacks = struct
|
||||
type 'st t = {
|
||||
enter_span:
|
||||
'st ->
|
||||
__FUNCTION__:string option ->
|
||||
__FILE__:string ->
|
||||
__LINE__:int ->
|
||||
params:extension_parameter list ->
|
||||
data:(string * user_data) list ->
|
||||
parent:parent ->
|
||||
string ->
|
||||
span;
|
||||
(** Enter a span *)
|
||||
exit_span: 'st -> span -> unit;
|
||||
(** Exit a span. Must be called exactly once per span. Additional
|
||||
constraints on nesting, threads, etc. vary per collector. *)
|
||||
current_span: 'st -> span option;
|
||||
(** Access the current span, if supported. Returns [None] if there is no
|
||||
current span or if the current span isn't tracked by the collector.
|
||||
*)
|
||||
add_data_to_span: 'st -> span -> (string * user_data) list -> unit;
|
||||
message:
|
||||
'st ->
|
||||
params:extension_parameter list ->
|
||||
data:(string * user_data) list ->
|
||||
span:span option ->
|
||||
string ->
|
||||
unit;
|
||||
(** Emit a message or log *)
|
||||
counter_int:
|
||||
'st ->
|
||||
params:extension_parameter list ->
|
||||
data:(string * user_data) list ->
|
||||
string ->
|
||||
int ->
|
||||
unit;
|
||||
(** Integer counter. *)
|
||||
counter_float:
|
||||
'st ->
|
||||
params:extension_parameter list ->
|
||||
data:(string * user_data) list ->
|
||||
string ->
|
||||
float ->
|
||||
unit;
|
||||
extension: 'st -> extension_event -> unit;
|
||||
(** Collector-specific extension *)
|
||||
shutdown: 'st -> unit;
|
||||
(** Shutdown collector, possibly waiting for it to finish sending data.
|
||||
*)
|
||||
}
|
||||
(** Callbacks taking a state ['st] *)
|
||||
|
||||
(** Signature for a collector.
|
||||
(** Helper to create backends in a future-proof way *)
|
||||
let make ~enter_span ~exit_span ?(current_span = fun _ -> None)
|
||||
~add_data_to_span ~message ~counter_int ~counter_float
|
||||
?(extension = fun _ _ -> ()) ?(shutdown = ignore) () : _ t =
|
||||
{
|
||||
enter_span;
|
||||
exit_span;
|
||||
current_span;
|
||||
add_data_to_span;
|
||||
message;
|
||||
counter_int;
|
||||
counter_float;
|
||||
extension;
|
||||
shutdown;
|
||||
}
|
||||
end
|
||||
|
||||
(** Definition of a collector.
|
||||
|
||||
This is only relevant to implementors of tracing backends; to instrument
|
||||
your code you only need to look at the {!Trace} module. *)
|
||||
module type S = sig
|
||||
val with_span :
|
||||
__FUNCTION__:string option ->
|
||||
__FILE__:string ->
|
||||
__LINE__:int ->
|
||||
data:(string * user_data) list ->
|
||||
string ->
|
||||
(span -> 'a) ->
|
||||
'a
|
||||
(** Run the function in a new span.
|
||||
@since 0.3 *)
|
||||
your code you only need to look at the {!Trace} module.
|
||||
|
||||
val enter_span :
|
||||
__FUNCTION__:string option ->
|
||||
__FILE__:string ->
|
||||
__LINE__:int ->
|
||||
data:(string * user_data) list ->
|
||||
string ->
|
||||
span
|
||||
(** Enter a new implicit span. For many uses cases, {!with_span} will be
|
||||
easier to use.
|
||||
@since 0.6 *)
|
||||
The definition changed since NEXT_RELEASE to a record of callbacks + a state
|
||||
*)
|
||||
type t =
|
||||
| C_none (** No collector. *)
|
||||
| C_some : 'st * 'st Callbacks.t -> t
|
||||
(** Collector with a state and some callbacks. *)
|
||||
|
||||
val exit_span : span -> unit
|
||||
(** Exit span. This should be called on the same thread as the corresponding
|
||||
{!enter_span}, and nest properly with other calls to enter/exit_span and
|
||||
{!with_span}.
|
||||
@since 0.6 *)
|
||||
|
||||
val enter_manual_span :
|
||||
parent:explicit_span_ctx option ->
|
||||
flavor:[ `Sync | `Async ] option ->
|
||||
__FUNCTION__:string option ->
|
||||
__FILE__:string ->
|
||||
__LINE__:int ->
|
||||
data:(string * user_data) list ->
|
||||
string ->
|
||||
explicit_span
|
||||
(** Enter an explicit span. Surrounding scope, if any, is provided by
|
||||
[parent], and this function can store as much metadata as it wants in the
|
||||
hmap in the {!explicit_span}'s [meta] field.
|
||||
|
||||
{b NOTE} the [parent] argument is now an {!explicit_span_ctx} and not an
|
||||
{!explicit_span} since 0.10.
|
||||
|
||||
This means that the collector doesn't need to implement contextual storage
|
||||
mapping {!span} to scopes, metadata, etc. on its side; everything can be
|
||||
transmitted in the {!explicit_span}.
|
||||
@since 0.3 *)
|
||||
|
||||
val exit_manual_span : explicit_span -> unit
|
||||
(** Exit an explicit span.
|
||||
@since 0.3 *)
|
||||
|
||||
val add_data_to_span : span -> (string * user_data) list -> unit
|
||||
(** @since Adds data to the current span.
|
||||
|
||||
0.4 *)
|
||||
|
||||
val add_data_to_manual_span :
|
||||
explicit_span -> (string * user_data) list -> unit
|
||||
(** Adds data to the given span.
|
||||
@since 0.4 *)
|
||||
|
||||
val message : ?span:span -> data:(string * user_data) list -> string -> unit
|
||||
(** Emit a message with associated metadata. *)
|
||||
|
||||
val name_thread : string -> unit
|
||||
(** Give a name to the current thread. *)
|
||||
|
||||
val name_process : string -> unit
|
||||
(** Give a name to the current process. *)
|
||||
|
||||
val counter_int : data:(string * user_data) list -> string -> int -> unit
|
||||
(** Integer counter. *)
|
||||
|
||||
val counter_float : data:(string * user_data) list -> string -> float -> unit
|
||||
(** Float counter. *)
|
||||
|
||||
val extension_event : extension_event -> unit
|
||||
(** Handle an extension event. A collector {b MUST} simple ignore events it
|
||||
doesn't know, and return [()] silently.
|
||||
@since 0.8 *)
|
||||
|
||||
val shutdown : unit -> unit
|
||||
(** Shutdown collector, possibly waiting for it to finish sending data. *)
|
||||
end
|
||||
let[@inline] is_some = function
|
||||
| C_none -> false
|
||||
| C_some _ -> true
|
||||
|
|
|
|||
15
src/core/core_ext.ml
Normal file
15
src/core/core_ext.ml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
(** A few core extensions.
|
||||
|
||||
@since NEXT_RELEASE *)
|
||||
|
||||
open Types
|
||||
|
||||
(** Additional extensions *)
|
||||
type extension_event +=
|
||||
| Extension_set_thread_name of string
|
||||
| Extension_set_process_name of string
|
||||
|
||||
(** Specialized parameters *)
|
||||
type extension_parameter +=
|
||||
| Extension_span_flavor of [ `Sync | `Async ]
|
||||
(** Tell the backend if this is a sync or async span *)
|
||||
|
|
@ -3,13 +3,14 @@ module A = Atomic_
|
|||
module Collector = Collector
|
||||
module Meta_map = Meta_map
|
||||
module Level = Level
|
||||
module Core_ext = Core_ext
|
||||
|
||||
type collector = (module Collector.S)
|
||||
type collector = Collector.t
|
||||
|
||||
(* ## globals ## *)
|
||||
|
||||
(** Global collector. *)
|
||||
let collector : collector option A.t = A.make None
|
||||
let collector : collector A.t = A.make Collector.C_none
|
||||
|
||||
(* default level for spans without a level *)
|
||||
let default_level_ = A.make Level.Trace
|
||||
|
|
@ -17,16 +18,8 @@ let current_level_ = A.make Level.Trace
|
|||
|
||||
(* ## implementation ## *)
|
||||
|
||||
let[@inline] ctx_of_span (sp : explicit_span) : explicit_span_ctx =
|
||||
{ span = sp.span; trace_id = sp.trace_id }
|
||||
|
||||
let data_empty_build_ () = []
|
||||
|
||||
let[@inline] enabled () =
|
||||
match A.get collector with
|
||||
| None -> false
|
||||
| Some _ -> true
|
||||
|
||||
let[@inline] enabled () = Collector.is_some (A.get collector)
|
||||
let[@inline] get_default_level () = A.get default_level_
|
||||
let[@inline] set_default_level l = A.set default_level_ l
|
||||
let[@inline] set_current_level l = A.set current_level_ l
|
||||
|
|
@ -35,152 +28,154 @@ let[@inline] get_current_level () = A.get current_level_
|
|||
let[@inline] check_level ?(level = A.get default_level_) () : bool =
|
||||
Level.leq level (A.get current_level_)
|
||||
|
||||
let with_span_collector_ (module C : Collector.S) ?__FUNCTION__ ~__FILE__
|
||||
~__LINE__ ?(data = data_empty_build_) name f =
|
||||
let data = data () in
|
||||
C.with_span ~__FUNCTION__ ~__FILE__ ~__LINE__ ~data name f
|
||||
let parent_of_span_opt_opt = function
|
||||
| None -> P_unknown
|
||||
| Some None -> P_none
|
||||
| Some (Some p) -> P_some p
|
||||
|
||||
let[@inline] with_span ?level ?__FUNCTION__ ~__FILE__ ~__LINE__ ?data name f =
|
||||
let enter_span_st st (cbs : _ Collector.Callbacks.t) ?__FUNCTION__ ~__FILE__
|
||||
~__LINE__ ?parent ?(params = []) ?(data = data_empty_build_) name : span =
|
||||
let parent = parent_of_span_opt_opt parent in
|
||||
let data = data () in
|
||||
cbs.enter_span st ~__FUNCTION__ ~__FILE__ ~__LINE__ ~parent ~params ~data name
|
||||
|
||||
let with_span_collector_ st (cbs : _ Collector.Callbacks.t) ?__FUNCTION__
|
||||
~__FILE__ ~__LINE__ ?parent ?params ?data name f =
|
||||
let sp : span =
|
||||
enter_span_st st cbs ?__FUNCTION__ ~__FILE__ ~__LINE__ ?parent ?params ?data
|
||||
name
|
||||
in
|
||||
match f sp with
|
||||
| res ->
|
||||
cbs.exit_span st sp;
|
||||
res
|
||||
| exception exn ->
|
||||
let bt = Printexc.get_raw_backtrace () in
|
||||
cbs.exit_span st sp;
|
||||
Printexc.raise_with_backtrace exn bt
|
||||
|
||||
let[@inline] with_span ?level ?__FUNCTION__ ~__FILE__ ~__LINE__ ?parent ?params
|
||||
?data name f =
|
||||
match A.get collector with
|
||||
| Some collector when check_level ?level () ->
|
||||
with_span_collector_ collector ?__FUNCTION__ ~__FILE__ ~__LINE__ ?data name
|
||||
f
|
||||
| C_some (st, cbs) when check_level ?level () ->
|
||||
with_span_collector_ st cbs ?__FUNCTION__ ~__FILE__ ~__LINE__ ?parent
|
||||
?params ?data name f
|
||||
| _ ->
|
||||
(* fast path: no collector, no span *)
|
||||
f Collector.dummy_span
|
||||
|
||||
let[@inline] enter_span ?level ?__FUNCTION__ ~__FILE__ ~__LINE__
|
||||
?(data = data_empty_build_) name : span =
|
||||
let[@inline] enter_span ?level ?__FUNCTION__ ~__FILE__ ~__LINE__ ?parent ?params
|
||||
?data name : span =
|
||||
match A.get collector with
|
||||
| Some (module C) when check_level ?level () ->
|
||||
let data = data () in
|
||||
C.enter_span ~__FUNCTION__ ~__FILE__ ~__LINE__ ~data name
|
||||
| C_some (st, cbs) when check_level ?level () ->
|
||||
(enter_span_st [@inlined never]) st cbs ?__FUNCTION__ ~__FILE__ ~__LINE__
|
||||
?parent ?params ?data name
|
||||
| _ -> Collector.dummy_span
|
||||
|
||||
let[@inline] exit_span sp : unit =
|
||||
match A.get collector with
|
||||
| None -> ()
|
||||
| Some (module C) -> C.exit_span sp
|
||||
|
||||
let enter_manual_span_collector_ (module C : Collector.S) ~parent ~flavor
|
||||
?__FUNCTION__ ~__FILE__ ~__LINE__ ?(data = data_empty_build_) name :
|
||||
explicit_span =
|
||||
let data = data () in
|
||||
C.enter_manual_span ~parent ~flavor ~__FUNCTION__ ~__FILE__ ~__LINE__ ~data
|
||||
name
|
||||
|
||||
let[@inline] enter_manual_span ~parent ?flavor ?level ?__FUNCTION__ ~__FILE__
|
||||
~__LINE__ ?data name : explicit_span =
|
||||
match A.get collector with
|
||||
| Some coll when check_level ?level () ->
|
||||
enter_manual_span_collector_ coll ~parent ~flavor ?__FUNCTION__ ~__FILE__
|
||||
~__LINE__ ?data name
|
||||
| _ -> Collector.dummy_explicit_span
|
||||
|
||||
let[@inline] enter_manual_toplevel_span ?flavor ?level ?__FUNCTION__ ~__FILE__
|
||||
~__LINE__ ?data name : explicit_span =
|
||||
enter_manual_span ~parent:None ?flavor ?level ?__FUNCTION__ ~__FILE__
|
||||
~__LINE__ ?data name
|
||||
|
||||
let[@inline] enter_manual_sub_span ~parent ?flavor ?level ?__FUNCTION__
|
||||
~__FILE__ ~__LINE__ ?data name : explicit_span =
|
||||
enter_manual_span
|
||||
~parent:(Some (ctx_of_span parent))
|
||||
?flavor ?level ?__FUNCTION__ ~__FILE__ ~__LINE__ ?data name
|
||||
|
||||
let[@inline] exit_manual_span espan : unit =
|
||||
if espan != Collector.dummy_explicit_span then (
|
||||
match A.get collector with
|
||||
| None -> ()
|
||||
| Some (module C) -> C.exit_manual_span espan
|
||||
)
|
||||
| C_none -> ()
|
||||
| C_some (st, cbs) -> cbs.exit_span st sp
|
||||
|
||||
let[@inline] add_data_to_span sp data : unit =
|
||||
if sp != Collector.dummy_span && data <> [] then (
|
||||
match A.get collector with
|
||||
| None -> ()
|
||||
| Some (module C) -> C.add_data_to_span sp data
|
||||
| C_none -> ()
|
||||
| C_some (st, cbs) -> cbs.add_data_to_span st sp data
|
||||
)
|
||||
|
||||
let[@inline] add_data_to_manual_span esp data : unit =
|
||||
if esp != Collector.dummy_explicit_span && data <> [] then (
|
||||
match A.get collector with
|
||||
| None -> ()
|
||||
| Some (module C) -> C.add_data_to_manual_span esp data
|
||||
)
|
||||
|
||||
let message_collector_ (module C : Collector.S) ?span
|
||||
let message_collector_ st (cbs : _ Collector.Callbacks.t) ?span ?(params = [])
|
||||
?(data = data_empty_build_) msg : unit =
|
||||
let data = data () in
|
||||
C.message ?span ~data msg
|
||||
cbs.message st ~span ~params ~data msg
|
||||
|
||||
let[@inline] message ?level ?span ?data msg : unit =
|
||||
let[@inline] message ?level ?span ?params ?data msg : unit =
|
||||
match A.get collector with
|
||||
| Some coll when check_level ?level () ->
|
||||
message_collector_ coll ?span ?data msg
|
||||
| C_some (st, cbs) when check_level ?level () ->
|
||||
(message_collector_ [@inlined never]) st cbs ?span ?params ?data msg
|
||||
| _ -> ()
|
||||
|
||||
let messagef ?level ?span ?data k =
|
||||
let messagef ?level ?span ?params ?data k =
|
||||
match A.get collector with
|
||||
| Some (module C) when check_level ?level () ->
|
||||
| C_some (st, cbs) when check_level ?level () ->
|
||||
k (fun fmt ->
|
||||
Format.kasprintf
|
||||
(fun str ->
|
||||
let data =
|
||||
match data with
|
||||
| None -> []
|
||||
| Some f -> f ()
|
||||
in
|
||||
C.message ?span ~data str)
|
||||
(fun str -> message_collector_ st cbs ?span ?params ?data str)
|
||||
fmt)
|
||||
| _ -> ()
|
||||
|
||||
let counter_int ?level ?(data = data_empty_build_) name n : unit =
|
||||
let counter_int ?level ?(params = []) ?(data = data_empty_build_) name n : unit
|
||||
=
|
||||
match A.get collector with
|
||||
| Some (module C) when check_level ?level () ->
|
||||
| C_some (st, cbs) when check_level ?level () ->
|
||||
let data = data () in
|
||||
C.counter_int ~data name n
|
||||
cbs.counter_int st ~params ~data name n
|
||||
| _ -> ()
|
||||
|
||||
let counter_float ?level ?(data = data_empty_build_) name f : unit =
|
||||
let counter_float ?level ?(params = []) ?(data = data_empty_build_) name f :
|
||||
unit =
|
||||
match A.get collector with
|
||||
| Some (module C) when check_level ?level () ->
|
||||
| C_some (st, cbs) when check_level ?level () ->
|
||||
let data = data () in
|
||||
C.counter_float ~data name f
|
||||
cbs.counter_float st ~params ~data name f
|
||||
| _ -> ()
|
||||
|
||||
let set_thread_name name : unit =
|
||||
match A.get collector with
|
||||
| None -> ()
|
||||
| Some (module C) -> C.name_thread name
|
||||
|
||||
let set_process_name name : unit =
|
||||
match A.get collector with
|
||||
| None -> ()
|
||||
| Some (module C) -> C.name_process name
|
||||
|
||||
let setup_collector c : unit =
|
||||
while
|
||||
let cur = A.get collector in
|
||||
match cur with
|
||||
| Some _ -> invalid_arg "trace: collector already present"
|
||||
| None -> not (A.compare_and_set collector cur (Some c))
|
||||
| C_some _ -> invalid_arg "trace: collector already present"
|
||||
| C_none -> not (A.compare_and_set collector cur c)
|
||||
do
|
||||
()
|
||||
done
|
||||
|
||||
let shutdown () =
|
||||
match A.exchange collector None with
|
||||
| None -> ()
|
||||
| Some (module C) -> C.shutdown ()
|
||||
match A.exchange collector C_none with
|
||||
| C_none -> ()
|
||||
| C_some (st, cbs) -> cbs.shutdown st
|
||||
|
||||
type extension_event = Types.extension_event = ..
|
||||
|
||||
let[@inline] extension_event ev =
|
||||
let[@inline] extension_event ev : unit =
|
||||
match A.get collector with
|
||||
| None -> ()
|
||||
| Some (module C) -> C.extension_event ev
|
||||
| C_none -> ()
|
||||
| C_some (st, cbs) -> cbs.extension st ev
|
||||
|
||||
let set_thread_name name : unit =
|
||||
extension_event @@ Core_ext.Extension_set_thread_name name
|
||||
|
||||
let set_process_name name : unit =
|
||||
extension_event @@ Core_ext.Extension_set_process_name name
|
||||
|
||||
module Internal_ = struct
|
||||
module Atomic_ = Atomic_
|
||||
end
|
||||
|
||||
(* ### deprecated *)
|
||||
|
||||
[@@@ocaml.alert "-deprecated"]
|
||||
|
||||
let enter_manual_span ~parent ?flavor ?level ?__FUNCTION__ ~__FILE__ ~__LINE__
|
||||
?data name : explicit_span =
|
||||
let params =
|
||||
match flavor with
|
||||
| None -> []
|
||||
| Some f -> [ Core_ext.Extension_span_flavor f ]
|
||||
in
|
||||
enter_span ~parent ~params ?level ?__FUNCTION__ ~__FILE__ ~__LINE__ ?data name
|
||||
|
||||
let enter_manual_toplevel_span ?flavor ?level ?__FUNCTION__ ~__FILE__ ~__LINE__
|
||||
?data name : explicit_span =
|
||||
enter_manual_span ~parent:None ?flavor ?level ?__FUNCTION__ ~__FILE__
|
||||
~__LINE__ ?data name
|
||||
|
||||
let enter_manual_sub_span ~parent ?flavor ?level ?__FUNCTION__ ~__FILE__
|
||||
~__LINE__ ?data name : explicit_span =
|
||||
enter_manual_span ~parent:(Some parent) ?flavor ?level ?__FUNCTION__ ~__FILE__
|
||||
~__LINE__ ?data name
|
||||
|
||||
let exit_manual_span = exit_span
|
||||
let add_data_to_manual_span = add_data_to_span
|
||||
|
||||
[@@@ocaml.alert "+deprecated"]
|
||||
|
|
|
|||
|
|
@ -31,15 +31,13 @@ val set_default_level : Level.t -> unit
|
|||
is [Level.Trace].
|
||||
@since 0.7 *)
|
||||
|
||||
val ctx_of_span : explicit_span -> explicit_span_ctx
|
||||
(** Turn a span into a span context.
|
||||
@since 0.10 *)
|
||||
|
||||
val with_span :
|
||||
?level:Level.t ->
|
||||
?__FUNCTION__:string ->
|
||||
__FILE__:string ->
|
||||
__LINE__:int ->
|
||||
?parent:span option ->
|
||||
?params:extension_parameter list ->
|
||||
?data:(unit -> (string * user_data) list) ->
|
||||
string ->
|
||||
(span -> 'a) ->
|
||||
|
|
@ -53,106 +51,53 @@ val with_span :
|
|||
@param level
|
||||
optional level for this span. since 0.7. Default is set via
|
||||
{!set_default_level}.
|
||||
@param parent the span's parent, if any. since NEXT_RELEASE.
|
||||
@param params
|
||||
extension parameters, used to communicate additional information to the
|
||||
collector. It might be collector-specific. since NEXT_RELEASE.
|
||||
|
||||
{b NOTE} an important restriction is that this is only supposed to work for
|
||||
synchronous, direct style code. Monadic concurrency, Effect-based fibers,
|
||||
etc. might not play well with this style of spans on some or all backends.
|
||||
If you use cooperative concurrency, see {!enter_manual_span}. *)
|
||||
Depending on the collector, this might clash with some forms of cooperative
|
||||
concurrency in which [with_span (fun span -> …)] might contain a yield
|
||||
point. Effect-based fibers, etc. might not play well with this style of
|
||||
spans on some or all backends. If you use cooperative concurrency, a safer
|
||||
alternative can be {!enter_span}. *)
|
||||
|
||||
val enter_span :
|
||||
?level:Level.t ->
|
||||
?__FUNCTION__:string ->
|
||||
__FILE__:string ->
|
||||
__LINE__:int ->
|
||||
?parent:span option ->
|
||||
?params:extension_parameter list ->
|
||||
?data:(unit -> (string * user_data) list) ->
|
||||
string ->
|
||||
span
|
||||
(** Enter a span manually.
|
||||
(** Enter a span manually. This means the caller is responsible for exiting the
|
||||
span exactly once on every path that exits the current scope. The context
|
||||
must be passed to the exit function as is.
|
||||
|
||||
@param level
|
||||
optional level for this span. since 0.7. Default is set via
|
||||
{!set_default_level}. *)
|
||||
{!set_default_level}.
|
||||
@param parent the span's parent, if any. since NEXT_RELEASE.
|
||||
@param params see {!with_span}. *)
|
||||
|
||||
val exit_span : span -> unit
|
||||
(** Exit a span manually. This must run on the same thread as the corresponding
|
||||
{!enter_span}, and spans must nest correctly. *)
|
||||
(** Exit a span manually. Spans must be nested correctly (ie form a stack or
|
||||
tree).
|
||||
|
||||
For some collectors, [enter_span] and [exit_span] must run on the same
|
||||
thread (e.g. Tracy). For some others, it doesn't matter. *)
|
||||
|
||||
val add_data_to_span : span -> (string * user_data) list -> unit
|
||||
(** Add structured data to the given active span (see {!with_span}). Behavior is
|
||||
not specified if the span has been exited.
|
||||
@since 0.4 *)
|
||||
|
||||
val enter_manual_span :
|
||||
parent:explicit_span_ctx option ->
|
||||
?flavor:span_flavor ->
|
||||
?level:Level.t ->
|
||||
?__FUNCTION__:string ->
|
||||
__FILE__:string ->
|
||||
__LINE__:int ->
|
||||
?data:(unit -> (string * user_data) list) ->
|
||||
string ->
|
||||
explicit_span
|
||||
(** Like {!with_span} but the caller is responsible for obtaining the [parent]
|
||||
span from their {e own} caller, and carry the resulting {!explicit_span} to
|
||||
the matching {!exit_manual_span}.
|
||||
|
||||
{b NOTE} this replaces [enter_manual_sub_span] and
|
||||
[enter_manual_toplevel_span] by just making [parent] an explicit option. It
|
||||
is breaking anyway because we now pass an {!explicit_span_ctx} instead of a
|
||||
full {!explicit_span} (the reason being that we might receive this
|
||||
explicit_span_ctx from another process or machine).
|
||||
|
||||
@param flavor
|
||||
a description of the span that can be used by the {!Collector.S} to decide
|
||||
how to represent the span. Typically, [`Sync] spans start and stop on one
|
||||
thread, and are nested purely by their timestamp; and [`Async] spans can
|
||||
overlap, migrate between threads, etc. (as happens in Lwt, Eio, Async,
|
||||
etc.) which impacts how the collector might represent them.
|
||||
@param level
|
||||
optional level for this span. since 0.7. Default is set via
|
||||
{!set_default_level}.
|
||||
@since 0.10 *)
|
||||
|
||||
val enter_manual_sub_span :
|
||||
parent:explicit_span ->
|
||||
?flavor:[ `Sync | `Async ] ->
|
||||
?level:Level.t ->
|
||||
?__FUNCTION__:string ->
|
||||
__FILE__:string ->
|
||||
__LINE__:int ->
|
||||
?data:(unit -> (string * user_data) list) ->
|
||||
string ->
|
||||
explicit_span
|
||||
[@@deprecated "use enter_manual_span"]
|
||||
(** @deprecated since 0.10, use {!enter_manual_span} *)
|
||||
|
||||
val enter_manual_toplevel_span :
|
||||
?flavor:[ `Sync | `Async ] ->
|
||||
?level:Level.t ->
|
||||
?__FUNCTION__:string ->
|
||||
__FILE__:string ->
|
||||
__LINE__:int ->
|
||||
?data:(unit -> (string * user_data) list) ->
|
||||
string ->
|
||||
explicit_span
|
||||
[@@deprecated "use enter_manual_span"]
|
||||
(** @deprecated since 0.10, use {!enter_manual_span} *)
|
||||
|
||||
val exit_manual_span : explicit_span -> unit
|
||||
(** Exit an explicit span. This can be on another thread, in a fiber or
|
||||
lightweight thread, etc. and will be supported by backends nonetheless. The
|
||||
span can be obtained via {!enter_manual_sub_span} or
|
||||
{!enter_manual_toplevel_span}.
|
||||
@since 0.3 *)
|
||||
|
||||
val add_data_to_manual_span : explicit_span -> (string * user_data) list -> unit
|
||||
(** [add_data_explicit esp data] adds [data] to the span [esp]. The behavior is
|
||||
not specified is the span has been exited already.
|
||||
@since 0.4 *)
|
||||
|
||||
val message :
|
||||
?level:Level.t ->
|
||||
?span:span ->
|
||||
?params:extension_parameter list ->
|
||||
?data:(unit -> (string * user_data) list) ->
|
||||
string ->
|
||||
unit
|
||||
|
|
@ -162,31 +107,39 @@ val message :
|
|||
optional level for this span. since 0.7. Default is set via
|
||||
{!set_default_level}.
|
||||
@param span
|
||||
the surrounding span, if any. This might be ignored by the collector. *)
|
||||
the surrounding span, if any. This might be ignored by the collector.
|
||||
@param params
|
||||
extension parameters, used to communicate additional information to the
|
||||
collector. It might be collector-specific. since NEXT_RELEASE. *)
|
||||
|
||||
val messagef :
|
||||
?level:Level.t ->
|
||||
?span:span ->
|
||||
?params:extension_parameter list ->
|
||||
?data:(unit -> (string * user_data) list) ->
|
||||
((('a, Format.formatter, unit, unit) format4 -> 'a) -> unit) ->
|
||||
unit
|
||||
(** [messagef (fun k->k"hello %s %d!" "world" 42)] is like
|
||||
[message "hello world 42!"] but only computes the string formatting if a
|
||||
collector is installed.
|
||||
@param level
|
||||
optional level for this span. since 0.7. Default is set via
|
||||
{!set_default_level}. *)
|
||||
|
||||
See {!message} for a description of the other arguments. *)
|
||||
|
||||
val set_thread_name : string -> unit
|
||||
(** Give a name to the current thread. This might be used by the collector to
|
||||
display traces in a more informative way. *)
|
||||
display traces in a more informative way.
|
||||
|
||||
Uses {!Core_ext.Extension_set_thread_name} since NEXT_RELEASE *)
|
||||
|
||||
val set_process_name : string -> unit
|
||||
(** Give a name to the current process. This might be used by the collector to
|
||||
display traces in a more informative way. *)
|
||||
display traces in a more informative way.
|
||||
|
||||
Uses {!Core_ext.Extension_set_process_name} since NEXT_RELEASE *)
|
||||
|
||||
val counter_int :
|
||||
?level:Level.t ->
|
||||
?params:extension_parameter list ->
|
||||
?data:(unit -> (string * user_data) list) ->
|
||||
string ->
|
||||
int ->
|
||||
|
|
@ -200,6 +153,7 @@ val counter_int :
|
|||
|
||||
val counter_float :
|
||||
?level:Level.t ->
|
||||
?params:extension_parameter list ->
|
||||
?data:(unit -> (string * user_data) list) ->
|
||||
string ->
|
||||
float ->
|
||||
|
|
@ -212,10 +166,8 @@ val counter_float :
|
|||
|
||||
(** {2 Collector} *)
|
||||
|
||||
type collector = (module Collector.S)
|
||||
(** An event collector.
|
||||
|
||||
See {!Collector} for more details. *)
|
||||
type collector = Collector.t
|
||||
(** An event collector. See {!Collector} for more details. *)
|
||||
|
||||
val setup_collector : collector -> unit
|
||||
(** [setup_collector c] installs [c] as the current collector.
|
||||
|
|
@ -246,3 +198,58 @@ val extension_event : extension_event -> unit
|
|||
defines it. Some collectors will simply ignore it. This does nothing if no
|
||||
collector is setup.
|
||||
@since 0.8 *)
|
||||
|
||||
(** {2 Core extensions} *)
|
||||
|
||||
module Core_ext = Core_ext
|
||||
|
||||
(** {2 Deprecated} *)
|
||||
|
||||
[@@@ocaml.alert "-deprecated"]
|
||||
|
||||
val enter_manual_span :
|
||||
parent:explicit_span_ctx option ->
|
||||
?flavor:[ `Sync | `Async ] ->
|
||||
?level:Level.t ->
|
||||
?__FUNCTION__:string ->
|
||||
__FILE__:string ->
|
||||
__LINE__:int ->
|
||||
?data:(unit -> (string * user_data) list) ->
|
||||
string ->
|
||||
explicit_span
|
||||
[@@deprecated "use enter_span"]
|
||||
|
||||
val enter_manual_sub_span :
|
||||
parent:explicit_span ->
|
||||
?flavor:[ `Sync | `Async ] ->
|
||||
?level:Level.t ->
|
||||
?__FUNCTION__:string ->
|
||||
__FILE__:string ->
|
||||
__LINE__:int ->
|
||||
?data:(unit -> (string * user_data) list) ->
|
||||
string ->
|
||||
explicit_span
|
||||
[@@deprecated "use enter_span"]
|
||||
(** @deprecated since 0.10, use {!enter_span} *)
|
||||
|
||||
val enter_manual_toplevel_span :
|
||||
?flavor:[ `Sync | `Async ] ->
|
||||
?level:Level.t ->
|
||||
?__FUNCTION__:string ->
|
||||
__FILE__:string ->
|
||||
__LINE__:int ->
|
||||
?data:(unit -> (string * user_data) list) ->
|
||||
string ->
|
||||
explicit_span
|
||||
[@@deprecated "use enter_span"]
|
||||
(** @deprecated since 0.10 use {!enter_span} *)
|
||||
|
||||
val exit_manual_span : explicit_span -> unit
|
||||
[@@deprecated "use exit_span"]
|
||||
(** @deprecated since 0.10 use {!exit_span} *)
|
||||
|
||||
val add_data_to_manual_span : explicit_span -> (string * user_data) list -> unit
|
||||
[@@deprecated "use add_data_to_span"]
|
||||
(** @deprecated since 0.10 use {!add_data_to_span} *)
|
||||
|
||||
[@@@ocaml.alert "+deprecated"]
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
type span = int64
|
||||
(** A span identifier.
|
||||
(** Main type definitions *)
|
||||
|
||||
The meaning of the identifier depends on the collector. *)
|
||||
type span = ..
|
||||
(** A span. Its representation is defined by the current collector. *)
|
||||
|
||||
type trace_id = string
|
||||
(** A bytestring representing a (possibly distributed) trace made of async
|
||||
spans. With opentelemetry this is 16 bytes.
|
||||
@since 0.10 *)
|
||||
(** Information about a span's parent span, if any.
|
||||
@since NEXT_RELEASE *)
|
||||
type parent =
|
||||
| P_unknown (** Parent is not specified at this point *)
|
||||
| P_none (** We know the current span has no parent *)
|
||||
| P_some of span (** We know the parent of the current span *)
|
||||
|
||||
type user_data =
|
||||
[ `Int of int
|
||||
|
|
@ -18,35 +20,15 @@ type user_data =
|
|||
(** User defined data, generally passed as key/value pairs to whatever collector
|
||||
is installed (if any). *)
|
||||
|
||||
type span_flavor =
|
||||
[ `Sync
|
||||
| `Async
|
||||
]
|
||||
(** Some information about the span.
|
||||
@since NEXT_RELEASE *)
|
||||
|
||||
type explicit_span_ctx = {
|
||||
span: span; (** The current span *)
|
||||
trace_id: trace_id; (** The trace this belongs to *)
|
||||
}
|
||||
(** A context, passed around for async traces.
|
||||
@since 0.10 *)
|
||||
|
||||
type explicit_span = {
|
||||
span: span;
|
||||
(** Identifier for this span. Several explicit spans might share the same
|
||||
identifier since we can differentiate between them via [meta]. *)
|
||||
trace_id: trace_id; (** The trace this belongs to *)
|
||||
mutable meta: Meta_map.t;
|
||||
(** Metadata for this span (and its context). This can be used by
|
||||
collectors to carry collector-specific information from the beginning
|
||||
of the span, to the end of the span. *)
|
||||
}
|
||||
(** Explicit span, with collector-specific metadata. This is richer than
|
||||
{!explicit_span_ctx} but not intended to be passed around (or sent across
|
||||
the wire), unlike {!explicit_span_ctx}. *)
|
||||
type explicit_span = span [@@deprecated "use span"]
|
||||
type explicit_span_ctx = span [@@deprecated "use span"]
|
||||
|
||||
type extension_event = ..
|
||||
(** An extension event, used to add features that are backend specific or simply
|
||||
not envisioned by [trace].
|
||||
@since 0.8 *)
|
||||
|
||||
type extension_parameter = ..
|
||||
(** An extension parameter, used to carry information for spans/messages/metrics
|
||||
that can be backend-specific or just not envisioned by [trace].
|
||||
@since NEXT_RELEASE *)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue