Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion devkit.opam
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,6 @@ depopts: [
]
conflicts: [
"jemalloc" {< "0.2"}
"opentelemetry" {< "0.13"}
"opentelemetry" {< "0.91"}
]
available: arch != "arm32" & arch != "x86_32"
12 changes: 11 additions & 1 deletion possibly_otel.mli
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
module Otrace := Trace_core

module Trace_context : sig
val header_names : string list
(** Names of the W3C trace context headers ([traceparent], [tracestate]) *)

val get_ambient_headers : ?explicit_span:Trace_core.span -> unit -> (string * string) list
(** Headers propagating the context of [explicit_span], or else of the ambient span:
[traceparent] with the span's sampled flag, and [tracestate] if non-empty.
Empty if there is no OTEL span. *)
end

module Traceparent : sig
val name : string
val get_ambient : ?explicit_span:Trace_core.span -> unit -> string option
end
end [@@deprecated "use Trace_context, which also propagates tracestate"]

val enter_manual_span :
__FUNCTION__:string ->
Expand Down
34 changes: 24 additions & 10 deletions possibly_otel.real.ml
Original file line number Diff line number Diff line change
@@ -1,18 +1,32 @@
open Opentelemetry

let ambient_span ?explicit_span () =
match explicit_span, Trace_core.current_span () with
| Some (Opentelemetry_trace.Extensions.Span_otel span), _
| _, Some (Opentelemetry_trace.Extensions.Span_otel span) -> Some span
| _ -> None

module Trace_context = struct
let header_names = Opentelemetry.Trace_context.[ Traceparent.name; Tracestate.name ]

let get_ambient_headers ?explicit_span () =
match ambient_span ?explicit_span () with
| Some span -> Opentelemetry.Trace_context.headers_of_span_ctx (Span.to_span_ctx span)
| None -> []
end

module Traceparent = struct
let name = Trace_context.Traceparent.name
let name = Opentelemetry.Trace_context.Traceparent.name

let get_ambient ?explicit_span () =
match explicit_span, Trace_core.current_span () with
| Some (Opentelemetry_trace.Extensions.Span_otel span), _
| _, Some (Opentelemetry_trace.Extensions.Span_otel span) ->
let ctx = Trace_context.Traceparent.to_value
~trace_id:(Span.trace_id span) ~parent_id:(Span.id span) () in
Some ctx
| _ -> None
match ambient_span ?explicit_span () with
| Some span ->
Some (Opentelemetry.Trace_context.Traceparent.to_value
~trace_flags:(Span.trace_flags span) ~trace_id:(Span.trace_id span) ~parent_id:(Span.id span) ())
| None -> None
end

(* no explicit [~parent]: the current span if any, otherwise let the collector look for
an ambient context (e.g. from an incoming traceparent) instead of forcing a new trace *)
let enter_manual_span ~__FUNCTION__ ~__FILE__ ~__LINE__ ?data name =
let parent = Trace_core.current_span () in
Trace_core.enter_span ~parent ~__FUNCTION__ ~__FILE__ ~__LINE__ ?data name
Trace_core.enter_span ~__FUNCTION__ ~__FILE__ ~__LINE__ ?data name
6 changes: 6 additions & 0 deletions possibly_otel.stub.ml
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
module Trace_context = struct
let header_names = [ "traceparent"; "tracestate" ]

let get_ambient_headers ?explicit_span:_ () = []
end

module Traceparent = struct
let name = "traceparent"

Expand Down
19 changes: 10 additions & 9 deletions web.ml
Original file line number Diff line number Diff line change
Expand Up @@ -329,12 +329,12 @@ module Http (IO : IO_TYPE) (Curl_IO : CURL with type 'a t = 'a IO.t) : HTTP with
| `Plain, _ -> verbose_curl_result_plain nr_http action t hr
| `Logfmt, _ -> verbose_curl_result_logfmt nr_http action t hr

(* Given a list of strings, check pre-existing entry starting with `~name`; and adds the concatenation of `~name` and `~value` if not. *)
let add_if_absent ~name ~value strs =
match strs with
| Some strs when List.exists (fun s -> Stre.starts_with s (name^":")) strs -> strs
| Some strs -> (String.concat ": " [name; value]) :: strs
| None -> [String.concat ": " [name; value]]
(* Remove from the list of "Name: value" headers those whose name (case-insensitive) is in `names`, then add `pairs`. *)
let replace_headers ~names pairs strs =
let is_replaced s = let (n, _) = Stre.dividec s ':' in List.exists (Stre.iequal (String.strip n)) names in
let strs = Option.default [] strs in
let strs = if List.exists is_replaced strs then List.filter (fun s -> not (is_replaced s)) strs else strs in
List.map (fun (n, v) -> sprintf "%s: %s" n v) pairs @ strs

(* NOTE don't forget to set http_1_0=true when sending requests to a Httpev-based server *)
(* Don't use curl_setheaders when using ?headers option *)
Expand Down Expand Up @@ -414,9 +414,10 @@ module Http (IO : IO_TYPE) (Curl_IO : CURL with type 'a t = 'a IO.t) : HTTP with
Possibly_otel.enter_manual_span
~__FUNCTION__:"Devkit.Web.Http.http_request_k" ~__FILE__ ~__LINE__ ~data:describe span_name in

let headers = match Possibly_otel.Traceparent.get_ambient ~explicit_span () with
| None -> headers
| Some value -> Some (add_if_absent ~name:(Possibly_otel.Traceparent.name) ~value headers)
(* trace context headers always override the caller's *)
let headers = match Possibly_otel.Trace_context.get_ambient_headers ~explicit_span () with
| [] -> headers
| pairs -> Some (replace_headers ~names:Possibly_otel.Trace_context.header_names pairs headers)
in

let set_body_and_headers h ct body =
Expand Down
Loading