From b3747cfc8e0e273e49a65f5f721e69bea5c6c12d Mon Sep 17 00:00:00 2001 From: Corentin Leruth Date: Fri, 4 Oct 2024 18:10:34 +0200 Subject: [PATCH 1/2] add links to scope --- .../opentelemetry_client_ocurl.ml | 1 + src/core/opentelemetry.ml | 158 ++++++++++-------- .../cohttp/opentelemetry_cohttp_lwt.ml | 9 +- src/trace/opentelemetry_trace.ml | 8 +- 4 files changed, 100 insertions(+), 76 deletions(-) diff --git a/src/client-ocurl/opentelemetry_client_ocurl.ml b/src/client-ocurl/opentelemetry_client_ocurl.ml index d67be711..a0a9c39d 100644 --- a/src/client-ocurl/opentelemetry_client_ocurl.ml +++ b/src/client-ocurl/opentelemetry_client_ocurl.ml @@ -38,6 +38,7 @@ module Self_trace = struct span_id = dummy_span_id; attrs = []; events = []; + links = []; } in f scope diff --git a/src/core/opentelemetry.ml b/src/core/opentelemetry.ml index e4e3128a..4b030787 100644 --- a/src/core/opentelemetry.ml +++ b/src/core/opentelemetry.ml @@ -751,75 +751,6 @@ end = struct default_span_event ~time_unix_nano ~name ~attributes:attrs () end -(** {2 Scopes} *) - -(** Scopes. - - A scope is a trace ID and the span ID of the currently active span. -*) -module Scope = struct - type t = { - trace_id: Trace_id.t; - span_id: Span_id.t; - mutable events: Event.t list; - mutable attrs: key_value list; - } - - (** Turn the scope into a span context *) - let[@inline] to_span_ctx (self : t) : Span_ctx.t = - Span_ctx.make ~trace_id:self.trace_id ~parent_id:self.span_id () - - (** 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. *) - let[@inline] add_event (scope : t) (ev : unit -> Event.t) : unit = - if Collector.has_backend () then scope.events <- ev () :: scope.events - - let[@inline] record_exception (scope : t) (exn : exn) - (bt : Printexc.raw_backtrace) : unit = - if Collector.has_backend () then ( - let ev = - Event.make "exception" - ~attrs: - [ - "message", `String (Printexc.to_string exn); - "type", `String (Printexc.exn_slot_name exn); - "stacktrace", `String (Printexc.raw_backtrace_to_string bt); - ] - in - scope.events <- ev :: scope.events - ) - - (** Add an attr 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. *) - let[@inline] add_attrs (scope : t) (attrs : unit -> key_value list) : unit = - if Collector.has_backend () then - scope.attrs <- List.rev_append (attrs ()) scope.attrs - - (** The opaque key necessary to access/set the ambient scope with - {!Ambient_context}. *) - let ambient_scope_key : t Ambient_context.key = Ambient_context.create_key () - - (** Obtain current scope from {!Ambient_context}, if available. *) - let get_ambient_scope ?scope () : t option = - match scope with - | Some _ -> scope - | None -> Ambient_context.get ambient_scope_key - - (** [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 ambient-context docs *) - let[@inline] with_ambient_scope (sc : t) (f : unit -> 'a) : 'a = - Ambient_context.with_binding ambient_scope_key sc (fun _ -> f ()) -end - -(** {2 Traces} *) - (** Span Link A pointer from the current span to another span in the same trace or in a @@ -858,11 +789,89 @@ end = struct ~span_id:(Span_id.to_bytes span_id) ?trace_state ~attributes ?dropped_attributes_count () - let[@inline] of_span_ctx ?attrs ctx : t = + let[@inline] of_span_ctx ?attrs (ctx : Span_ctx.t) : t = make ~trace_id:(Span_ctx.trace_id ctx) ~span_id:(Span_ctx.parent_id ctx) ?attrs () end +(** {2 Scopes} *) + +(** Scopes. + + A scope is a trace ID and the span ID of the currently active span. +*) +module Scope = struct + type t = { + trace_id: Trace_id.t; + span_id: Span_id.t; + mutable events: Event.t list; + mutable attrs: key_value list; + mutable links: Span_link.t list; + } + + (** Turn the scope into a span context *) + let[@inline] to_span_ctx (self : t) : Span_ctx.t = + Span_ctx.make ~trace_id:self.trace_id ~parent_id:self.span_id () + + (** 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. *) + let[@inline] add_event (scope : t) (ev : unit -> Event.t) : unit = + if Collector.has_backend () then scope.events <- ev () :: scope.events + + let[@inline] record_exception (scope : t) (exn : exn) + (bt : Printexc.raw_backtrace) : unit = + if Collector.has_backend () then ( + let ev = + Event.make "exception" + ~attrs: + [ + "message", `String (Printexc.to_string exn); + "type", `String (Printexc.exn_slot_name exn); + "stacktrace", `String (Printexc.raw_backtrace_to_string bt); + ] + in + scope.events <- ev :: scope.events + ) + + (** 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. *) + let[@inline] add_attrs (scope : t) (attrs : unit -> key_value list) : unit = + if Collector.has_backend () then + scope.attrs <- List.rev_append (attrs ()) scope.attrs + + (** 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. *) + let[@inline] add_links (scope : t) (links : unit -> Span_link.t list) : unit = + if Collector.has_backend () then + scope.links <- List.rev_append (links ()) scope.links + + (** The opaque key necessary to access/set the ambient scope with + {!Ambient_context}. *) + let ambient_scope_key : t Ambient_context.key = Ambient_context.create_key () + + (** Obtain current scope from {!Ambient_context}, if available. *) + let get_ambient_scope ?scope () : t option = + match scope with + | Some _ -> scope + | None -> Ambient_context.get ambient_scope_key + + (** [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 ambient-context docs *) + let[@inline] with_ambient_scope (sc : t) (f : unit -> 'a) : 'a = + Ambient_context.with_binding ambient_scope_key sc (fun _ -> f ()) +end + +(** {2 Traces} *) + (** Spans. A Span is the workhorse of traces, it indicates an operation that @@ -1007,6 +1016,7 @@ module Trace = struct span_id: Span_id.t; mutable events: Event.t list; mutable attrs: Span.key_value list; + mutable links: Span_link.t list; } [@@deprecated "use Scope.t"] @@ -1016,7 +1026,7 @@ module Trace = struct let with_' ?(force_new_trace_id = false) ?trace_state ?service_name ?(attrs : (string * [< value ]) list = []) ?kind ?trace_id ?parent ?scope - ?links name cb = + ?(links = []) name cb = let scope = if force_new_trace_id then None @@ -1039,7 +1049,7 @@ module Trace = struct in let start_time = Timestamp_ns.now_unix_ns () in let span_id = Span_id.create () in - let scope = { trace_id; span_id; events = []; attrs } in + let scope = { trace_id; span_id; events = []; attrs; links } in (* called once we're done, to emit a span *) let finally res = let status = @@ -1055,8 +1065,8 @@ module Trace = struct (* 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 ~id:span_id ?trace_state - ~attrs:scope.attrs ~events:scope.events ~start_time + Span.create ?kind ~trace_id ?parent ~links:scope.links ~id:span_id + ?trace_state ~attrs:scope.attrs ~events:scope.events ~start_time ~end_time:(Timestamp_ns.now_unix_ns ()) ~status name in diff --git a/src/integrations/cohttp/opentelemetry_cohttp_lwt.ml b/src/integrations/cohttp/opentelemetry_cohttp_lwt.ml index 9adb3902..a3ffc715 100644 --- a/src/integrations/cohttp/opentelemetry_cohttp_lwt.ml +++ b/src/integrations/cohttp/opentelemetry_cohttp_lwt.ml @@ -112,7 +112,14 @@ end = struct (match Traceparent.of_value v with | Ok (trace_id, parent_id) -> Some - Otel.Trace.{ trace_id; span_id = parent_id; events = []; attrs = [] } + Otel.Trace. + { + trace_id; + span_id = parent_id; + events = []; + attrs = []; + links = []; + } | Error _ -> None) let remove_trace_context req = diff --git a/src/trace/opentelemetry_trace.ml b/src/trace/opentelemetry_trace.ml index 8dfb1d13..a27788e9 100644 --- a/src/trace/opentelemetry_trace.ml +++ b/src/trace/opentelemetry_trace.ml @@ -122,7 +122,13 @@ module Internal = struct in let new_scope = - { Scope.span_id = otel_id; trace_id; events = []; attrs = data } + { + Scope.span_id = otel_id; + trace_id; + events = []; + attrs = data; + links = []; + } in let start_time = Timestamp_ns.now_unix_ns () in From 41f1f434705b3bfe678a62e2747b492c87dee1a4 Mon Sep 17 00:00:00 2001 From: Corentin Leruth Date: Mon, 7 Oct 2024 15:28:19 +0200 Subject: [PATCH 2/2] add Scope.make --- src/client-ocurl/opentelemetry_client_ocurl.ml | 8 +------- src/core/opentelemetry.ml | 6 +++++- src/integrations/cohttp/opentelemetry_cohttp_lwt.ml | 10 +--------- src/trace/opentelemetry_trace.ml | 10 +--------- 4 files changed, 8 insertions(+), 26 deletions(-) diff --git a/src/client-ocurl/opentelemetry_client_ocurl.ml b/src/client-ocurl/opentelemetry_client_ocurl.ml index a0a9c39d..d724f1c3 100644 --- a/src/client-ocurl/opentelemetry_client_ocurl.ml +++ b/src/client-ocurl/opentelemetry_client_ocurl.ml @@ -33,13 +33,7 @@ module Self_trace = struct else ( (* do nothing *) let scope = - { - Scope.trace_id = dummy_trace_id_; - span_id = dummy_span_id; - attrs = []; - events = []; - links = []; - } + Scope.make ~trace_id:dummy_trace_id_ ~span_id:dummy_span_id () in f scope ) diff --git a/src/core/opentelemetry.ml b/src/core/opentelemetry.ml index 4b030787..4cd7124e 100644 --- a/src/core/opentelemetry.ml +++ b/src/core/opentelemetry.ml @@ -809,6 +809,10 @@ module Scope = struct mutable links: Span_link.t list; } + let make ~trace_id ~span_id ?(events = []) ?(attrs = []) ?(links = []) () : t + = + { trace_id; span_id; events; attrs; links } + (** Turn the scope into a span context *) let[@inline] to_span_ctx (self : t) : Span_ctx.t = Span_ctx.make ~trace_id:self.trace_id ~parent_id:self.span_id () @@ -1049,7 +1053,7 @@ module Trace = struct in let start_time = Timestamp_ns.now_unix_ns () in let span_id = Span_id.create () in - let scope = { trace_id; span_id; events = []; attrs; links } in + let scope = Scope.make ~trace_id ~span_id ~attrs ~links () in (* called once we're done, to emit a span *) let finally res = let status = diff --git a/src/integrations/cohttp/opentelemetry_cohttp_lwt.ml b/src/integrations/cohttp/opentelemetry_cohttp_lwt.ml index a3ffc715..a0dee06f 100644 --- a/src/integrations/cohttp/opentelemetry_cohttp_lwt.ml +++ b/src/integrations/cohttp/opentelemetry_cohttp_lwt.ml @@ -111,15 +111,7 @@ end = struct | Some v -> (match Traceparent.of_value v with | Ok (trace_id, parent_id) -> - Some - Otel.Trace. - { - trace_id; - span_id = parent_id; - events = []; - attrs = []; - links = []; - } + Some (Otel.Scope.make ~trace_id ~span_id:parent_id ()) | Error _ -> None) let remove_trace_context req = diff --git a/src/trace/opentelemetry_trace.ml b/src/trace/opentelemetry_trace.ml index a27788e9..9c53c33e 100644 --- a/src/trace/opentelemetry_trace.ml +++ b/src/trace/opentelemetry_trace.ml @@ -121,15 +121,7 @@ module Internal = struct | None, None -> None in - let new_scope = - { - Scope.span_id = otel_id; - trace_id; - events = []; - attrs = data; - links = []; - } - in + let new_scope = Otel.Scope.make ~trace_id ~span_id:otel_id ~attrs:data () in let start_time = Timestamp_ns.now_unix_ns () in let sb =