diff --git a/src/core/opentelemetry.ml b/src/core/opentelemetry.ml index 0b303f7..6908d98 100644 --- a/src/core/opentelemetry.ml +++ b/src/core/opentelemetry.ml @@ -782,7 +782,12 @@ module Span_link : sig unit -> t - val of_span_ctx : ?attrs:key_value list -> Span_ctx.t -> t + val of_span_ctx : + ?trace_state:string -> + ?attrs:key_value list -> + ?dropped_attributes_count:int -> + Span_ctx.t -> + t end = struct open Proto.Trace @@ -799,9 +804,10 @@ end = struct ~span_id:(Span_id.to_bytes span_id) ?trace_state ~attributes ?dropped_attributes_count () - let[@inline] of_span_ctx ?attrs (ctx : Span_ctx.t) : t = + let[@inline] of_span_ctx ?trace_state ?attrs ?dropped_attributes_count + (ctx : Span_ctx.t) : t = make ~trace_id:(Span_ctx.trace_id ctx) ~span_id:(Span_ctx.parent_id ctx) - ?attrs () + ?trace_state ?attrs ?dropped_attributes_count () end module Span_status : sig @@ -834,6 +840,29 @@ end = struct let make ~message ~code = { message; code } end +(** @since NEXT_RELEASE *) +module Span_kind : sig + open Proto.Trace + + type t = span_span_kind = + | Span_kind_unspecified + | Span_kind_internal + | Span_kind_server + | Span_kind_client + | Span_kind_producer + | Span_kind_consumer +end = struct + open Proto.Trace + + type t = span_span_kind = + | Span_kind_unspecified + | Span_kind_internal + | Span_kind_server + | Span_kind_client + | Span_kind_producer + | Span_kind_consumer +end + (** {2 Scopes} *) (** Scopes. @@ -857,6 +886,8 @@ module Scope : sig 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 -> @@ -867,6 +898,14 @@ module Scope : sig unit -> t + val to_span_link : + ?trace_state:string -> + ?attrs:key_value 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 *) @@ -896,6 +935,10 @@ module Scope : sig 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 NEXT_RELEASE *) + val ambient_scope_key : t Ambient_context.key (** The opaque key necessary to access/set the ambient scope with {!Ambient_context}. *) @@ -916,6 +959,7 @@ end = struct | Attr of key_value * 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; @@ -927,7 +971,8 @@ end = struct let rec loop acc = function | Nil -> acc | Attr (attr, l) -> loop (attr :: acc) l - | Ev (_, l) | Span_link (_, l) | Span_status (_, l) -> loop acc l + | Ev (_, l) | Span_kind (_, l) | Span_link (_, l) | Span_status (_, l) -> + loop acc l in loop [] scope.items @@ -935,7 +980,9 @@ end = struct let rec loop acc = function | Nil -> acc | Ev (event, l) -> loop (event :: acc) l - | Attr (_, l) | Span_link (_, l) | Span_status (_, l) -> loop acc l + | Attr (_, l) | Span_kind (_, l) | Span_link (_, l) | Span_status (_, l) + -> + loop acc l in loop [] scope.items @@ -943,17 +990,27 @@ end = struct let rec loop acc = function | Nil -> acc | Span_link (span_link, l) -> loop (span_link :: acc) l - | Ev (_, l) | Attr (_, l) | Span_status (_, l) -> loop 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 acc = function - | Nil -> acc + let rec loop = function + | Nil -> None | Span_status (status, _) -> Some status - | Ev (_, l) | Attr (_, l) | Span_link (_, l) -> loop acc l + | 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 None scope.items + loop scope.items let make ~trace_id ~span_id ?(events = []) ?(attrs = []) ?(links = []) ?status () : t = @@ -971,6 +1028,11 @@ end = struct 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 () @@ -1008,6 +1070,9 @@ end = struct if Collector.has_backend () then scope.items <- Span_status (status, scope.items) + let set_kind (scope : t) (k : Span_kind.t) : unit = + if Collector.has_backend () then scope.items <- Span_kind (k, scope.items) + let ambient_scope_key : t Ambient_context.key = Ambient_context.create_key () let get_ambient_scope ?scope () : t option = @@ -1034,7 +1099,7 @@ module Span : sig type id = Span_id.t - type nonrec kind = span_span_kind = + type kind = Span_kind.t = | Span_kind_unspecified | Span_kind_internal | Span_kind_server @@ -1079,7 +1144,7 @@ end = struct type id = Span_id.t - type nonrec kind = span_span_kind = + type kind = Span_kind.t = | Span_kind_unspecified | Span_kind_internal | Span_kind_server diff --git a/src/trace/opentelemetry_trace.ml b/src/trace/opentelemetry_trace.ml index ebf9328..09b29d7 100644 --- a/src/trace/opentelemetry_trace.ml +++ b/src/trace/opentelemetry_trace.ml @@ -53,6 +53,11 @@ open Well_known let on_internal_error = ref (fun msg -> Printf.eprintf "error in Opentelemetry_trace: %s\n%!" msg) +type Otrace.extension_event += + | Ev_link_span of Otrace.explicit_span * Otrace.explicit_span + | Ev_set_span_kind of Otrace.explicit_span * Otel.Span_kind.t + | Ev_record_exn of Otrace.explicit_span * exn * Printexc.raw_backtrace + module Internal = struct type span_begin = { start_time: int64; @@ -193,6 +198,9 @@ module Internal = struct Active_span_tbl.remove active_spans.tbl otrace_id; Some (exit_span_ otel_span_begin) + let[@inline] get_scope (span : Otrace.explicit_span) : Otel.Scope.t option = + Otrace.Meta_map.find k_explicit_scope span.meta + module M = struct let with_span ~__FUNCTION__ ~__FILE__ ~__LINE__ ~data name cb = let otrace_id, sb = @@ -259,10 +267,10 @@ module Internal = struct | Some sb -> Otel.Scope.add_attrs sb.scope (fun () -> data) let add_data_to_manual_span (span : Otrace.explicit_span) data : unit = - match Otrace.Meta_map.find_exn k_explicit_scope span.meta with - | exception _ -> + match get_scope span with + | None -> !on_internal_error (spf "manual span does not a contain an OTEL scope") - | scope -> Otel.Scope.add_attrs scope (fun () -> data) + | Some scope -> Otel.Scope.add_attrs scope (fun () -> data) let message ?span ~data:_ msg : unit = (* gather information from context *) @@ -293,9 +301,35 @@ module Internal = struct let _kind, attrs = otel_attrs_of_otrace_data data in let m = Otel.Metrics.(gauge ~name [ float ~attrs cur_val ]) in Otel.Metrics.emit [ m ] + + let extension_event = function + | Ev_link_span (sp1, sp2) -> + (match get_scope sp1, get_scope sp2 with + | Some sc1, Some sc2 -> + Otel.Scope.add_links sc1 (fun () -> [ Otel.Scope.to_span_link sc2 ]) + | _ -> !on_internal_error "could not find scope for OTEL span") + | Ev_set_span_kind (sp, k) -> + (match get_scope sp with + | None -> !on_internal_error "could not find scope for OTEL span" + | Some sc -> Otel.Scope.set_kind sc k) + | Ev_record_exn (sp, exn, bt) -> + (match get_scope sp with + | None -> !on_internal_error "could not find scope for OTEL span" + | Some sc -> Otel.Scope.record_exception sc exn bt) + | _ -> () end end +let link_spans (sp1 : Otrace.explicit_span) (sp2 : Otrace.explicit_span) : unit + = + if Otrace.enabled () then Otrace.extension_event @@ Ev_link_span (sp1, sp2) + +let set_span_kind sp k : unit = + if Otrace.enabled () then Otrace.extension_event @@ Ev_set_span_kind (sp, k) + +let record_exception sp exn bt : unit = + if Otrace.enabled () then Otrace.extension_event @@ Ev_record_exn (sp, exn, bt) + let collector () : Otrace.collector = (module Internal.M) let setup () = Otrace.setup_collector @@ collector () diff --git a/src/trace/opentelemetry_trace.mli b/src/trace/opentelemetry_trace.mli index 0834960..da8f848 100644 --- a/src/trace/opentelemetry_trace.mli +++ b/src/trace/opentelemetry_trace.mli @@ -48,6 +48,19 @@ val setup_with_otel_backend : Opentelemetry.Collector.backend -> unit val collector : unit -> Trace_core.collector (** Make a Trace collector that uses the OTEL backend to send spans and logs *) +val link_spans : Otrace.explicit_span -> Otrace.explicit_span -> unit +(** [link_spans sp1 sp2] modifies [sp1] by adding a span link to [sp2]. + @since NEXT_RELEASE *) + +val set_span_kind : Otrace.explicit_span -> Otel.Span.kind -> unit +(** [set_span_kind sp k] sets the span's kind. + @since NEXT_RELEASE *) + +val record_exception : + Otrace.explicit_span -> exn -> Printexc.raw_backtrace -> unit +(** Record exception in the current span. + @since NEXT_RELEASE *) + (** Static references for well-known identifiers; see {!label-wellknown}. *) module Well_known : sig val spankind_key : string @@ -68,6 +81,7 @@ module Well_known : sig (string * Otrace.user_data) list -> Otel.Span.kind * Otel.Span.key_value list end +[@@deprecated "use the regular functions for this"] (**/**)