mirror of
https://github.com/ocaml-tracing/ocaml-opentelemetry.git
synced 2026-03-08 03:47:59 -04:00
refator core OTEL: remove Scope, directly use Span as builder
now that fields are mutable, it's cheaper and easier
This commit is contained in:
parent
cb4be48746
commit
bd335ecadd
8 changed files with 175 additions and 247 deletions
|
|
@ -6,3 +6,6 @@ let conv (k, v) =
|
|||
let open Proto.Common in
|
||||
let value = Value.conv v in
|
||||
make_key_value ~key:k ?value ()
|
||||
|
||||
let of_otel (kv : Proto.Common.key_value) : t =
|
||||
kv.key, Value.of_otel_opt kv.value
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
(** Opentelemetry types and instrumentation *)
|
||||
|
||||
open Common_
|
||||
|
||||
module Rand_bytes = Rand_bytes
|
||||
(** Generation of random identifiers. *)
|
||||
|
||||
|
|
@ -29,9 +27,6 @@ module Timestamp_ns = Timestamp_ns
|
|||
module Exporter = Exporter
|
||||
module Collector = Exporter [@@deprecated "Use 'Exporter' instead"]
|
||||
|
||||
module Tick_callbacks = Tick_callbacks
|
||||
(** Helper to implement part of the exporter *)
|
||||
|
||||
(** {2 Identifiers} *)
|
||||
|
||||
module Trace_id = Trace_id
|
||||
|
|
@ -63,10 +58,6 @@ module Span_link = Span_link
|
|||
module Span_status = Span_status
|
||||
module Span_kind = Span_kind
|
||||
|
||||
(** {2 Scopes} *)
|
||||
|
||||
module Scope = Scope
|
||||
|
||||
(** {2 Traces} *)
|
||||
|
||||
module Span = Span
|
||||
|
|
|
|||
|
|
@ -1,131 +0,0 @@
|
|||
open Common_
|
||||
|
||||
type item_list =
|
||||
| Nil
|
||||
| Ev of Event.t * item_list
|
||||
| Attr of Key_value.t * item_list
|
||||
| Span_link of Span_link.t * item_list
|
||||
| Span_status of Span_status.t * item_list
|
||||
| Span_kind of Span_kind.t * item_list
|
||||
|
||||
type t = {
|
||||
trace_id: Trace_id.t;
|
||||
span_id: Span_id.t;
|
||||
mutable items: item_list;
|
||||
}
|
||||
|
||||
let attrs scope =
|
||||
let rec loop acc = function
|
||||
| Nil -> acc
|
||||
| Attr (attr, l) -> loop (attr :: acc) l
|
||||
| Ev (_, l) | Span_kind (_, l) | Span_link (_, l) | Span_status (_, l) ->
|
||||
loop acc l
|
||||
in
|
||||
loop [] scope.items
|
||||
|
||||
let events scope =
|
||||
let rec loop acc = function
|
||||
| Nil -> acc
|
||||
| Ev (event, l) -> loop (event :: acc) l
|
||||
| Attr (_, l) | Span_kind (_, l) | Span_link (_, l) | Span_status (_, l) ->
|
||||
loop acc l
|
||||
in
|
||||
loop [] scope.items
|
||||
|
||||
let links scope =
|
||||
let rec loop acc = function
|
||||
| Nil -> acc
|
||||
| Span_link (span_link, l) -> loop (span_link :: acc) l
|
||||
| Ev (_, l) | Span_kind (_, l) | Attr (_, l) | Span_status (_, l) ->
|
||||
loop acc l
|
||||
in
|
||||
loop [] scope.items
|
||||
|
||||
let status scope =
|
||||
let rec loop = function
|
||||
| Nil -> None
|
||||
| Span_status (status, _) -> Some status
|
||||
| Ev (_, l) | Attr (_, l) | Span_kind (_, l) | Span_link (_, l) -> loop l
|
||||
in
|
||||
loop scope.items
|
||||
|
||||
let kind scope =
|
||||
let rec loop = function
|
||||
| Nil -> None
|
||||
| Span_kind (k, _) -> Some k
|
||||
| Ev (_, l) | Span_status (_, l) | Attr (_, l) | Span_link (_, l) -> loop l
|
||||
in
|
||||
loop scope.items
|
||||
|
||||
let make ~trace_id ~span_id ?(events = []) ?(attrs = []) ?(links = []) ?status
|
||||
() : t =
|
||||
let items =
|
||||
let items =
|
||||
match status with
|
||||
| None -> Nil
|
||||
| Some status -> Span_status (status, Nil)
|
||||
in
|
||||
let items = List.fold_left (fun acc ev -> Ev (ev, acc)) items events in
|
||||
let items = List.fold_left (fun acc attr -> Attr (attr, acc)) items attrs in
|
||||
List.fold_left (fun acc link -> Span_link (link, acc)) items links
|
||||
in
|
||||
{ trace_id; span_id; items }
|
||||
|
||||
let[@inline] to_span_link ?trace_state ?attrs ?dropped_attributes_count
|
||||
(self : t) : Span_link.t =
|
||||
Span_link.make ?trace_state ?attrs ?dropped_attributes_count
|
||||
~trace_id:self.trace_id ~span_id:self.span_id ()
|
||||
|
||||
let[@inline] to_span_ctx (self : t) : Span_ctx.t =
|
||||
Span_ctx.make ~trace_id:self.trace_id ~parent_id:self.span_id ()
|
||||
|
||||
open struct
|
||||
let[@inline] is_not_dummy (self : t) : bool = Span_id.is_valid self.span_id
|
||||
end
|
||||
|
||||
let[@inline] add_event (self : t) (ev : unit -> Event.t) : unit =
|
||||
if is_not_dummy self then self.items <- Ev (ev (), self.items)
|
||||
|
||||
let[@inline] record_exception (self : t) (exn : exn)
|
||||
(bt : Printexc.raw_backtrace) : unit =
|
||||
if is_not_dummy self then (
|
||||
let ev =
|
||||
Event.make "exception"
|
||||
~attrs:
|
||||
[
|
||||
"exception.message", `String (Printexc.to_string exn);
|
||||
"exception.type", `String (Printexc.exn_slot_name exn);
|
||||
( "exception.stacktrace",
|
||||
`String (Printexc.raw_backtrace_to_string bt) );
|
||||
]
|
||||
in
|
||||
self.items <- Ev (ev, self.items)
|
||||
)
|
||||
|
||||
let[@inline] add_attrs (self : t) (attrs : unit -> Key_value.t list) : unit =
|
||||
if is_not_dummy self then
|
||||
self.items <-
|
||||
List.fold_left (fun acc attr -> Attr (attr, acc)) self.items (attrs ())
|
||||
|
||||
let[@inline] add_links (self : t) (links : unit -> Span_link.t list) : unit =
|
||||
if is_not_dummy self then
|
||||
self.items <-
|
||||
List.fold_left
|
||||
(fun acc link -> Span_link (link, acc))
|
||||
self.items (links ())
|
||||
|
||||
let set_status (self : t) (status : Span_status.t) : unit =
|
||||
if is_not_dummy self then self.items <- Span_status (status, self.items)
|
||||
|
||||
let set_kind (self : t) (k : Span_kind.t) : unit =
|
||||
if is_not_dummy self then self.items <- Span_kind (k, self.items)
|
||||
|
||||
let ambient_scope_key : t Ambient_context.key = Ambient_context.create_key ()
|
||||
|
||||
let get_ambient_scope ?scope () : t option =
|
||||
match scope with
|
||||
| Some _ -> scope
|
||||
| None -> Ambient_context.get ambient_scope_key
|
||||
|
||||
let[@inline] with_ambient_scope (sc : t) (f : unit -> 'a) : 'a =
|
||||
Ambient_context.with_binding ambient_scope_key sc (fun _ -> f ())
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
(** Scopes.
|
||||
|
||||
A scope is a trace ID and the span ID of the currently active span. *)
|
||||
|
||||
open Common_
|
||||
|
||||
type item_list
|
||||
|
||||
type t = {
|
||||
trace_id: Trace_id.t;
|
||||
span_id: Span_id.t;
|
||||
mutable items: item_list;
|
||||
}
|
||||
|
||||
val attrs : t -> Key_value.t list
|
||||
|
||||
val events : t -> Event.t list
|
||||
|
||||
val links : t -> Span_link.t list
|
||||
|
||||
val status : t -> Span_status.t option
|
||||
|
||||
val kind : t -> Span_kind.t option
|
||||
|
||||
val make :
|
||||
trace_id:Trace_id.t ->
|
||||
span_id:Span_id.t ->
|
||||
?events:Event.t list ->
|
||||
?attrs:Key_value.t list ->
|
||||
?links:Span_link.t list ->
|
||||
?status:Span_status.t ->
|
||||
unit ->
|
||||
t
|
||||
|
||||
val to_span_link :
|
||||
?trace_state:string ->
|
||||
?attrs:Key_value.t list ->
|
||||
?dropped_attributes_count:int ->
|
||||
t ->
|
||||
Span_link.t
|
||||
(** Turn the scope into a span link *)
|
||||
|
||||
val to_span_ctx : t -> Span_ctx.t
|
||||
(** Turn the scope into a span context *)
|
||||
|
||||
val add_event : t -> (unit -> Event.t) -> unit
|
||||
(** Add an event to the scope. It will be aggregated into the span.
|
||||
|
||||
Note that this takes a function that produces an event, and will only call
|
||||
it if there is an instrumentation backend. *)
|
||||
|
||||
val record_exception : t -> exn -> Printexc.raw_backtrace -> unit
|
||||
|
||||
val add_attrs : t -> (unit -> Key_value.t list) -> unit
|
||||
(** Add attributes to the scope. It will be aggregated into the span.
|
||||
|
||||
Note that this takes a function that produces attributes, and will only call
|
||||
it if there is an instrumentation backend. *)
|
||||
|
||||
val add_links : t -> (unit -> Span_link.t list) -> unit
|
||||
(** Add links to the scope. It will be aggregated into the span.
|
||||
|
||||
Note that this takes a function that produces links, and will only call it
|
||||
if there is an instrumentation backend. *)
|
||||
|
||||
val set_status : t -> Span_status.t -> unit
|
||||
(** set the span status.
|
||||
|
||||
Note that this function will be called only if there is an instrumentation
|
||||
backend. *)
|
||||
|
||||
val set_kind : t -> Span_kind.t -> unit
|
||||
(** Set the span's kind.
|
||||
@since 0.11 *)
|
||||
|
||||
val ambient_scope_key : t Ambient_context.key
|
||||
(** The opaque key necessary to access/set the ambient scope with
|
||||
{!Ambient_context}. *)
|
||||
|
||||
val get_ambient_scope : ?scope:t -> unit -> t option
|
||||
(** Obtain current scope from {!Ambient_context}, if available. *)
|
||||
|
||||
val with_ambient_scope : t -> (unit -> 'a) -> 'a
|
||||
(** [with_ambient_scope sc thunk] calls [thunk()] in a context where [sc] is the
|
||||
(thread|continuation)-local scope, then reverts to the previous local scope,
|
||||
if any.
|
||||
|
||||
@see <https://github.com/ELLIOTTCABLE/ocaml-ambient-context>
|
||||
ambient-context docs *)
|
||||
|
|
@ -22,11 +22,15 @@ type key_value =
|
|||
| `None
|
||||
]
|
||||
|
||||
let id self = Span_id.of_bytes self.span_id
|
||||
let[@inline] id self = Span_id.of_bytes self.span_id
|
||||
|
||||
let create ?(kind = !Globals.default_span_kind) ?(id = Span_id.create ())
|
||||
?trace_state ?(attrs = []) ?(events = []) ?status ~trace_id ?parent
|
||||
?(links = []) ~start_time ~end_time name : t * id =
|
||||
let[@inline] trace_id self = Trace_id.of_bytes self.trace_id
|
||||
|
||||
let[@inline] is_not_dummy self = Span_id.is_valid (id self)
|
||||
|
||||
let make ?(kind = !Globals.default_span_kind) ?trace_state ?(attrs = [])
|
||||
?(events = []) ?status ~trace_id ~id ?parent ?(links = []) ~start_time
|
||||
~end_time name : t =
|
||||
let trace_id = Trace_id.to_bytes trace_id in
|
||||
let parent_span_id = Option.map Span_id.to_bytes parent in
|
||||
let attributes = List.map Key_value.conv attrs in
|
||||
|
|
@ -35,4 +39,85 @@ let create ?(kind = !Globals.default_span_kind) ?(id = Span_id.create ())
|
|||
~attributes ~events ?trace_state ?status ~kind ~name ~links
|
||||
~start_time_unix_nano:start_time ~end_time_unix_nano:end_time ()
|
||||
in
|
||||
span, id
|
||||
span
|
||||
|
||||
let create_new ?kind ?(id = Span_id.create ()) ?trace_state ?attrs ?events
|
||||
?status ~trace_id ?parent ?links ~start_time ~end_time name : t =
|
||||
make ?kind ~id ~trace_id ?trace_state ?attrs ?events ?status ?parent ?links
|
||||
~start_time ~end_time name
|
||||
|
||||
let attrs self = self.attributes |> List.rev_map Key_value.of_otel
|
||||
|
||||
let events self = self.events
|
||||
|
||||
let links self : Span_link.t list = self.links
|
||||
|
||||
let status self = self.status
|
||||
|
||||
let kind self =
|
||||
let k = self.kind in
|
||||
if k = Span_kind_unspecified then
|
||||
None
|
||||
else
|
||||
Some k
|
||||
|
||||
let to_span_link (self : t) : Span_link.t =
|
||||
make_span_link ~attributes:self.attributes
|
||||
?dropped_attributes_count:
|
||||
(if span_has_dropped_attributes_count self then
|
||||
Some self.dropped_attributes_count
|
||||
else
|
||||
None)
|
||||
?trace_state:
|
||||
(if span_has_trace_state self then
|
||||
Some self.trace_state
|
||||
else
|
||||
None)
|
||||
~trace_id:self.trace_id ~span_id:self.span_id ()
|
||||
|
||||
let[@inline] to_span_ctx (self : t) : Span_ctx.t =
|
||||
Span_ctx.make ~trace_id:(trace_id self) ~parent_id:(id self) ()
|
||||
|
||||
let[@inline] add_event self ev : unit =
|
||||
if is_not_dummy self then span_set_events self (ev :: self.events)
|
||||
|
||||
let add_event' self ev : unit = if is_not_dummy self then add_event self (ev ())
|
||||
|
||||
let record_exception (self : t) (exn : exn) (bt : Printexc.raw_backtrace) : unit
|
||||
=
|
||||
if is_not_dummy self then (
|
||||
let ev =
|
||||
Event.make "exception"
|
||||
~attrs:
|
||||
[
|
||||
"exception.message", `String (Printexc.to_string exn);
|
||||
"exception.type", `String (Printexc.exn_slot_name exn);
|
||||
( "exception.stacktrace",
|
||||
`String (Printexc.raw_backtrace_to_string bt) );
|
||||
]
|
||||
in
|
||||
add_event self ev
|
||||
)
|
||||
|
||||
let[@inline] add_attrs (self : t) (attrs : unit -> Key_value.t list) : unit =
|
||||
if is_not_dummy self then (
|
||||
let attrs = List.rev_map Key_value.conv (attrs ()) in
|
||||
let attrs = List.rev_append attrs self.attributes in
|
||||
span_set_attributes self attrs
|
||||
)
|
||||
|
||||
let add_links (self : t) (links : Span_link.t list) : unit =
|
||||
if links <> [] then (
|
||||
let links = List.rev_append links self.links in
|
||||
span_set_links self links
|
||||
)
|
||||
|
||||
let add_links' (self : t) (links : unit -> Span_link.t list) : unit =
|
||||
if is_not_dummy self then (
|
||||
let links = List.rev_append (links ()) self.links in
|
||||
span_set_links self links
|
||||
)
|
||||
|
||||
let set_status = span_set_status
|
||||
|
||||
let set_kind = span_set_kind
|
||||
|
|
|
|||
|
|
@ -24,9 +24,30 @@ val id : t -> Span_id.t
|
|||
|
||||
type key_value = Key_value.t
|
||||
|
||||
val create :
|
||||
val make :
|
||||
?kind:kind ->
|
||||
?id:id ->
|
||||
?trace_state:string ->
|
||||
?attrs:key_value list ->
|
||||
?events:Event.t list ->
|
||||
?status:status ->
|
||||
trace_id:Trace_id.t ->
|
||||
id:Span_id.t ->
|
||||
?parent:id ->
|
||||
?links:Span_link.t list ->
|
||||
start_time:Timestamp_ns.t ->
|
||||
end_time:Timestamp_ns.t ->
|
||||
string ->
|
||||
t
|
||||
(** [make ~trace_id ~id name] creates a new span
|
||||
@param trace_id the trace this belongs to
|
||||
@param parent parent span, if any
|
||||
@param links
|
||||
list of links to other spans, each with their trace state (see
|
||||
{{:https://www.w3.org/TR/trace-context/#tracestate-header} w3.org}) *)
|
||||
|
||||
val create_new :
|
||||
?kind:kind ->
|
||||
?id:Span_id.t ->
|
||||
?trace_state:string ->
|
||||
?attrs:key_value list ->
|
||||
?events:Event.t list ->
|
||||
|
|
@ -37,10 +58,50 @@ val create :
|
|||
start_time:Timestamp_ns.t ->
|
||||
end_time:Timestamp_ns.t ->
|
||||
string ->
|
||||
t * id
|
||||
(** [create ~trace_id name] creates a new span with its unique ID.
|
||||
@param trace_id the trace this belongs to
|
||||
@param parent parent span, if any
|
||||
@param links
|
||||
list of links to other spans, each with their trace state (see
|
||||
{{:https://www.w3.org/TR/trace-context/#tracestate-header} w3.org}) *)
|
||||
t
|
||||
|
||||
val attrs : t -> Key_value.t list
|
||||
|
||||
val events : t -> Event.t list
|
||||
|
||||
val links : t -> Span_link.t list
|
||||
|
||||
val status : t -> Span_status.t option
|
||||
|
||||
val kind : t -> Span_kind.t option
|
||||
|
||||
val to_span_link : t -> Span_link.t
|
||||
(** Turn the scope into a span link *)
|
||||
|
||||
val to_span_ctx : t -> Span_ctx.t
|
||||
(** Turn the scope into a span context *)
|
||||
|
||||
val add_event : t -> Event.t -> unit
|
||||
|
||||
val add_event' : t -> (unit -> Event.t) -> unit
|
||||
(** Add an event to the scope. It will be aggregated into the span.
|
||||
|
||||
Note that this takes a function that produces an event, and will only call
|
||||
it if there is an instrumentation backend. *)
|
||||
|
||||
val record_exception : t -> exn -> Printexc.raw_backtrace -> unit
|
||||
|
||||
val add_links : t -> Span_link.t list -> unit
|
||||
|
||||
val add_links' : t -> (unit -> Span_link.t list) -> unit
|
||||
(** Add links to the scope. It will be aggregated into the span.
|
||||
|
||||
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 set_status : t -> Span_status.t -> unit
|
||||
(** set the span status.
|
||||
|
||||
Note that this function will be called only if there is an instrumentation
|
||||
backend. *)
|
||||
|
||||
val set_kind : t -> Span_kind.t -> unit
|
||||
(** Set the span's kind.
|
||||
@since 0.11 *)
|
||||
|
|
|
|||
|
|
@ -49,11 +49,11 @@ let simple_main_exporter : t =
|
|||
|
||||
{b NOTE} be careful not to call this inside a Gc alarm, as it can cause
|
||||
deadlocks. *)
|
||||
let emit ?service_name:_ ?attrs:_ (spans : span list) : unit =
|
||||
let (emit [@deprecated "use an explicit tracer"]) =
|
||||
fun ?service_name:_ ?attrs:_ (spans : span list) : unit ->
|
||||
match Exporter.Main_exporter.get () with
|
||||
| None -> ()
|
||||
| Some exp -> exp#send_trace spans
|
||||
[@@deprecated "use an explicit tracer"]
|
||||
|
||||
(* TODO: remove scope, use span directly *)
|
||||
type scope = Scope.t = {
|
||||
|
|
@ -113,11 +113,11 @@ let with_' ?(tracer = simple_main_exporter) ?(force_new_trace_id = false)
|
|||
(make_status ~code:Status_code_error ~message:(Printexc.to_string e)
|
||||
()))
|
||||
in
|
||||
let span, _ =
|
||||
let span =
|
||||
(* TODO: should the attrs passed to with_ go on the Span
|
||||
(in Span.create) or on the ResourceSpan (in emit)?
|
||||
(question also applies to Opentelemetry_lwt.Trace.with) *)
|
||||
Span.create ?kind ~trace_id ?parent ~links:(Scope.links scope) ~id:span_id
|
||||
Span.make ?kind ~trace_id ?parent ~links:(Scope.links scope) ~id:span_id
|
||||
?trace_state ~attrs:(Scope.attrs scope) ~events:(Scope.events scope)
|
||||
~start_time
|
||||
~end_time:(Timestamp_ns.now_unix_ns ())
|
||||
|
|
|
|||
|
|
@ -17,3 +17,11 @@ let conv =
|
|||
| `Bool b -> Some (Bool_value b)
|
||||
| `Float f -> Some (Double_value f)
|
||||
| `None -> None
|
||||
|
||||
let of_otel_opt (v : Proto.Common.any_value option) : t =
|
||||
match v with
|
||||
| Some (Int_value i) -> `Int (Int64.to_int i)
|
||||
| Some (String_value s) -> `String s
|
||||
| Some (Bool_value b) -> `Bool b
|
||||
| Some (Double_value f) -> `Float f
|
||||
| Some (Array_value _ | Kvlist_value _ | Bytes_value _) | None -> `None
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue