Skip to content

Commit 4d8f0e5

Browse files
committed
CP-52744: Thread TraceContext as json inside debug_info
Adds functionality to marshal and unmarshal `TraceContext` in the tracing library. Instead of passing only the `traceparent` in `debug_info`, the entire `TraceContext` is now passed as JSON. This change enables the transfer of baggage across xenopsd boundaries, improving tracing propagation and debugging capabilities. This should also enable later use of `baggage` as means of passing the thread classification between components. Signed-off-by: Gabriel Buica <[email protected]>
1 parent e39baa6 commit 4d8f0e5

File tree

6 files changed

+82
-14
lines changed

6 files changed

+82
-14
lines changed

dune-project

+2
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,13 @@
103103
dune
104104
(alcotest :with-test)
105105
(fmt :with-test)
106+
ppx_deriving_yojson
106107
re
107108
uri
108109
(uuid :with-test)
109110
(xapi-log (= :version))
110111
(xapi-stdext-threads (= :version))
112+
yojson
111113
)
112114
(synopsis "Allows to instrument code to generate tracing information")
113115
(description "This library provides modules to allow gathering runtime traces.")

ocaml/libs/tracing/dune

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
(library
22
(name tracing)
33
(modules tracing)
4-
(libraries re uri xapi-log xapi-stdext-threads threads.posix)
4+
(libraries re uri yojson xapi-log xapi-stdext-threads threads.posix)
5+
(preprocess
6+
(pps ppx_deriving_yojson))
57
(public_name xapi-tracing))
68

79
(library

ocaml/libs/tracing/tracing.ml

+19-5
Original file line numberDiff line numberDiff line change
@@ -211,11 +211,12 @@ end
211211

212212
(* The context of a trace that can be propagated across service boundaries. *)
213213
module TraceContext = struct
214-
type traceparent = string
214+
type traceparent = string [@@deriving yojson]
215215

216-
type baggage = (string * string) list
216+
type baggage = (string * string) list [@@deriving yojson]
217217

218218
type t = {traceparent: traceparent option; baggage: baggage option}
219+
[@@deriving yojson]
219220

220221
let empty = {traceparent= None; baggage= None}
221222

@@ -226,6 +227,10 @@ module TraceContext = struct
226227
let traceparent_of ctx = ctx.traceparent
227228

228229
let baggage_of ctx = ctx.baggage
230+
231+
let to_json_string t = Yojson.Safe.to_string (to_yojson t)
232+
233+
let of_json_string s = of_yojson (Yojson.Safe.from_string s)
229234
end
230235

231236
module SpanContext = struct
@@ -297,6 +302,8 @@ module Span = struct
297302

298303
let get_context t = t.context
299304

305+
let get_trace_context t = t.context |> SpanContext.context_of_span_context
306+
300307
let start ?(attributes = Attributes.empty)
301308
?(trace_context : TraceContext.t option) ~name ~parent ~span_kind () =
302309
let trace_id, extra_context =
@@ -312,9 +319,9 @@ module Span = struct
312319
in
313320
let context =
314321
(* If trace_context is provided to the call, override any inherited trace context. *)
315-
Option.fold ~none:context
316-
~some:(Fun.flip SpanContext.with_trace_context context)
317-
trace_context
322+
trace_context
323+
|> Option.fold ~none:context
324+
~some:(Fun.flip SpanContext.with_trace_context context)
318325
in
319326
(* Using gettimeofday over Mtime as it is better for sharing timestamps between the systems *)
320327
let begin_time = Unix.gettimeofday () in
@@ -411,6 +418,13 @@ module Span = struct
411418
{span with status= {status_code; _description}}
412419
| _ ->
413420
span
421+
422+
let to_propagation_context span =
423+
let traceparent = span |> get_context |> SpanContext.to_traceparent in
424+
span
425+
|> get_context
426+
|> SpanContext.context_of_span_context
427+
|> TraceContext.with_traceparent (Some traceparent)
414428
end
415429

416430
module TraceMap = Map.Make (Trace_id)

ocaml/libs/tracing/tracing.mli

+8
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ module TraceContext : sig
9494
val traceparent_of : t -> traceparent option
9595

9696
val baggage_of : t -> baggage option
97+
98+
val to_json_string : t -> string
99+
100+
val of_json_string : string -> (t, string) result
97101
end
98102

99103
module SpanContext : sig
@@ -119,6 +123,8 @@ module Span : sig
119123

120124
val get_context : t -> SpanContext.t
121125

126+
val get_trace_context : t -> TraceContext.t
127+
122128
val add_link : t -> SpanContext.t -> (string * string) list -> t
123129

124130
val add_event : t -> string -> (string * string) list -> t
@@ -140,6 +146,8 @@ module Span : sig
140146
val get_end_time : t -> float option
141147

142148
val get_attributes : t -> (string * string) list
149+
150+
val to_propagation_context : t -> TraceContext.t
143151
end
144152

145153
module TraceMap : module type of Map.Make (Trace_id)

ocaml/xapi-idl/lib/debug_info.ml

+48-8
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,34 @@ let make ~log ~tracing = {log; tracing}
2222
let of_string s =
2323
let open Tracing in
2424
match String.split_on_char separator s with
25-
| [log; traceparent] ->
26-
let spancontext = SpanContext.of_traceparent traceparent in
25+
| [log; trace_context] ->
26+
(* Process the tracing data:
27+
1. We expect a JSON representing the trace_context.
28+
2. If the JSON is valid but not representing a trace_context,
29+
we ignore the tracing data.
30+
3. If we get an exception from parsing the JSON string,
31+
it means a traceparent string was received.*)
32+
let trace_context =
33+
try
34+
let trace_context =
35+
Tracing.TraceContext.of_json_string trace_context
36+
in
37+
match trace_context with
38+
| Ok trace_context ->
39+
Some trace_context
40+
| Error _ ->
41+
None
42+
with _ ->
43+
Some
44+
(TraceContext.empty
45+
|> TraceContext.with_traceparent (Some trace_context)
46+
)
47+
in
48+
let spancontext =
49+
Option.(join (map Tracing.SpanContext.of_trace_context trace_context))
50+
in
2751
let tracing =
28-
Option.map (fun tp -> Tracer.span_of_span_context tp log) spancontext
52+
Option.map (Fun.flip Tracer.span_of_span_context log) spancontext
2953
in
3054
{log; tracing}
3155
| _ ->
@@ -37,11 +61,13 @@ let filter_separator = Astring.String.filter (( <> ) separator)
3761
let to_string t =
3862
Option.fold ~none:t.log
3963
~some:(fun span ->
40-
let traceparent =
41-
Tracing.Span.get_context span |> Tracing.SpanContext.to_traceparent
64+
let trace_context =
65+
span
66+
|> Tracing.Span.to_propagation_context
67+
|> Tracing.TraceContext.to_json_string
4268
in
4369
Printf.sprintf "%s%c%s" (filter_separator t.log) separator
44-
(filter_separator traceparent)
70+
(filter_separator trace_context)
4571
)
4672
t.tracing
4773

@@ -68,7 +94,21 @@ let with_dbg ?(with_thread = false) ~module_name ~name ~dbg f =
6894

6995
let traceparent_of_dbg dbg =
7096
match String.split_on_char separator dbg with
71-
| [_; traceparent] ->
72-
Some traceparent
97+
| [_; trace_context] -> (
98+
(* Process the tracing data:
99+
1. We expect a JSON representing the trace_context.
100+
2. If the JSON is valid but not representing a trace_context,
101+
we ignore the tracing data.
102+
3. If we get an exception from parsing the JSON string,
103+
it means a traceparent string was received.*)
104+
try
105+
let trace_context = Tracing.TraceContext.of_json_string trace_context in
106+
match trace_context with
107+
| Ok trace_context ->
108+
Tracing.TraceContext.traceparent_of trace_context
109+
| Error _ ->
110+
None
111+
with _ -> Some trace_context
112+
)
73113
| _ ->
74114
None

xapi-tracing.opam

+2
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@ depends: [
1313
"dune" {>= "3.15"}
1414
"alcotest" {with-test}
1515
"fmt" {with-test}
16+
"ppx_deriving_yojson"
1617
"re"
1718
"uri"
1819
"uuid" {with-test}
1920
"xapi-log" {= version}
2021
"xapi-stdext-threads" {= version}
22+
"yojson"
2123
"odoc" {with-doc}
2224
]
2325
build: [

0 commit comments

Comments
 (0)