Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CP-50444: Instrument http svr with dt #5888

Merged
Merged
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 dune
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
(ocamlopt_flags (:standard -g -p -w -39))
(flags (:standard -w -39))
)
(dev (flags (:standard -g -w -39 -warn-error -69)))
(dev (flags (:standard -g -w -39)))
(release
(flags (:standard -w -39-6@5))
(env-vars (ALCOTEST_COMPACT 1))
Expand Down
1 change: 1 addition & 0 deletions dune-project
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@
(xapi-rrd (= :version))
(xapi-stdext-threads (= :version))
(xapi-stdext-unix (= :version))
xapi-tracing
)
)

Expand Down
1 change: 1 addition & 0 deletions ocaml/libs/http-lib/dune
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
ipaddr
polly
threads.posix
tracing
GabrielBuica marked this conversation as resolved.
Show resolved Hide resolved
uri
xapi-log
xapi-stdext-pervasives
Expand Down
23 changes: 23 additions & 0 deletions ocaml/libs/http-lib/http.ml
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,29 @@ module Request = struct
let headers, body = to_headers_and_body x in
let frame_header = if x.frame then make_frame_header headers else "" in
frame_header ^ headers ^ body

let traceparent_of req =
let open Tracing in
let ( let* ) = Option.bind in
let* traceparent = req.traceparent in
let* span_context = SpanContext.of_traceparent traceparent in
let span = Tracer.span_of_span_context span_context req.uri in
Some span

let with_tracing ?attributes ~name req f =
let open Tracing in
let parent = traceparent_of req in
with_child_trace ?attributes parent ~name (fun (span : Span.t option) ->
match span with
| Some span ->
let traceparent =
Some (span |> Span.get_context |> SpanContext.to_traceparent)
in
let req = {req with traceparent} in
f req
| None ->
f req
)
end

module Response = struct
Expand Down
5 changes: 5 additions & 0 deletions ocaml/libs/http-lib/http.mli
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,11 @@ module Request : sig

val to_wire_string : t -> string
(** [to_wire_string t] returns a string which could be sent to a server *)

val traceparent_of : t -> Tracing.Span.t option

val with_tracing :
?attributes:(string * string) list -> name:string -> t -> (t -> 'a) -> 'a
end

(** Parsed form of the HTTP response *)
Expand Down
26 changes: 26 additions & 0 deletions ocaml/libs/http-lib/http_svr.ml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ module E = Debug.Make (struct let name = "http_internal_errors" end)

let ( let* ) = Option.bind

let ( let@ ) f x = f x

type uri_path = string

module Stats = struct
Expand Down Expand Up @@ -101,6 +103,7 @@ let response_of_request req hdrs =

let response_fct req ?(hdrs = []) s (response_length : int64)
(write_response_to_fd_fn : Unix.file_descr -> unit) =
let@ req = Http.Request.with_tracing ~name:__FUNCTION__ req in
let res =
{
(response_of_request req hdrs) with
Expand Down Expand Up @@ -441,9 +444,28 @@ let request_of_bio_exn ~proxy_seen ~read_timeout ~total_timeout ~max_length bio
already sent back a suitable error code and response to the client. *)
let request_of_bio ?proxy_seen ~read_timeout ~total_timeout ~max_length ic =
try
let tracer = Tracing.Tracer.get_tracer ~name:"http_tracer" in
let loop_span =
match Tracing.Tracer.start ~tracer ~name:__FUNCTION__ ~parent:None () with
| Ok span ->
span
| Error _ ->
None
in
let r, proxy =
request_of_bio_exn ~proxy_seen ~read_timeout ~total_timeout ~max_length ic
in
let parent_span = Http.Request.traceparent_of r in
let loop_span =
Option.fold ~none:None
~some:(fun span ->
Tracing.Tracer.update_span_with_parent span parent_span
)
loop_span
in
let _ : (Tracing.Span.t option, exn) result =
Tracing.Tracer.finish loop_span
in
(Some r, proxy)
with e ->
D.warn "%s (%s)" (Printexc.to_string e) __LOC__ ;
Expand Down Expand Up @@ -486,6 +508,8 @@ let request_of_bio ?proxy_seen ~read_timeout ~total_timeout ~max_length ic =
(None, None)

let handle_one (x : 'a Server.t) ss context req =
let@ req = Http.Request.with_tracing ~name:__FUNCTION__ req in
let span = Http.Request.traceparent_of req in
let ic = Buf_io.of_fd ss in
let finished = ref false in
try
Expand All @@ -499,6 +523,7 @@ let handle_one (x : 'a Server.t) ss context req =
Option.value ~default:empty
(Radix_tree.longest_prefix req.Request.uri method_map)
in
let@ _ = Tracing.with_child_trace span ~name:"handler" in
( match te.TE.handler with
| BufIO handlerfn ->
handlerfn req ic context
Expand Down Expand Up @@ -561,6 +586,7 @@ let handle_connection ~header_read_timeout ~header_total_timeout
request_of_bio ?proxy_seen ~read_timeout ~total_timeout
~max_length:max_header_length ic
in

(* 2. now we attempt to process the request *)
let finished =
Option.fold ~none:true
Expand Down
65 changes: 49 additions & 16 deletions ocaml/libs/tracing/tracing.ml
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ let ok_none = Ok None
module Status = struct
type status_code = Unset | Ok | Error [@@deriving rpcty]

type t = {status_code: status_code; description: string option}
type t = {status_code: status_code; _description: string option}
end

module Attributes = struct
Expand All @@ -151,6 +151,8 @@ end
module SpanContext = struct
type t = {trace_id: string; span_id: string} [@@deriving rpcty]

let context trace_id span_id = {trace_id; span_id}

let to_traceparent t = Printf.sprintf "00-%s-%s-01" t.trace_id t.span_id

let of_traceparent traceparent =
Expand All @@ -167,7 +169,7 @@ module SpanContext = struct
end

module SpanLink = struct
type t = {context: SpanContext.t; attributes: (string * string) list}
psafont marked this conversation as resolved.
Show resolved Hide resolved
type t = {_context: SpanContext.t; _attributes: (string * string) list}
end

module Span = struct
Expand Down Expand Up @@ -208,7 +210,7 @@ module Span = struct
(* Using gettimeofday over Mtime as it is better for sharing timestamps between the systems *)
let begin_time = Unix.gettimeofday () in
let end_time = None in
let status : Status.t = {status_code= Status.Unset; description= None} in
let status : Status.t = {status_code= Status.Unset; _description= None} in
let links = [] in
let events = [] in
{
Expand Down Expand Up @@ -250,7 +252,7 @@ module Span = struct
let set_span_kind span span_kind = {span with span_kind}

let add_link span context attributes =
let link : SpanLink.t = {context; attributes} in
let link : SpanLink.t = {_context= context; _attributes= attributes} in
{span with links= link :: span.links}

let add_event span name attributes =
Expand All @@ -263,7 +265,7 @@ module Span = struct
| exn, stacktrace -> (
let msg = Printexc.to_string exn in
let exn_type = Printexc.exn_slot_name exn in
let description =
let _description =
Some
(Printf.sprintf "Error: %s Type: %s Backtrace: %s" msg exn_type
stacktrace
Expand All @@ -286,17 +288,17 @@ module Span = struct
span.attributes
(Attributes.of_list exn_attributes)
in
{span with status= {status_code; description}; attributes}
{span with status= {status_code; _description}; attributes}
| _ ->
span
)

let set_ok span =
let description = None in
let _description = None in
let status_code = Status.Ok in
match span.status.status_code with
| Unset ->
{span with status= {status_code; description}}
{span with status= {status_code; _description}}
| _ ->
span
end
Expand All @@ -311,7 +313,7 @@ module Spans = struct
Hashtbl.length spans
)

let max_spans = Atomic.make 1000
let max_spans = Atomic.make 2500

let set_max_spans x = Atomic.set max_spans x

Expand Down Expand Up @@ -519,8 +521,8 @@ module TracerProvider = struct
get_tracer_providers_unlocked

let set ?enabled ?attributes ?endpoints ~uuid () =
let update_provider (provider : t) ?(enabled = provider.enabled) attributes
endpoints =
let update_provider (provider : t) enabled attributes endpoints =
let enabled = Option.value ~default:provider.enabled enabled in
let attributes : string Attributes.t =
Option.fold ~none:provider.attributes ~some:Attributes.of_list
attributes
Expand All @@ -537,7 +539,7 @@ module TracerProvider = struct
let provider =
match Hashtbl.find_opt tracer_providers uuid with
| Some (provider : t) ->
update_provider provider ?enabled attributes endpoints
update_provider provider enabled attributes endpoints
| None ->
fail "The TracerProvider : %s does not exist" uuid
in
Expand All @@ -564,9 +566,9 @@ module TracerProvider = struct
end

module Tracer = struct
type t = {name: string; provider: TracerProvider.t}
type t = {_name: string; provider: TracerProvider.t}

let create ~name ~provider = {name; provider}
let create ~name ~provider = {_name= name; provider}

let no_op =
let provider : TracerProvider.t =
Expand All @@ -577,7 +579,7 @@ module Tracer = struct
; enabled= false
}
in
{name= ""; provider}
{_name= ""; provider}

let get_tracer ~name =
if Atomic.get observe then (
Expand All @@ -598,7 +600,7 @@ module Tracer = struct
let span_of_span_context context name : Span.t =
{
context
; status= {status_code= Status.Unset; description= None}
; status= {status_code= Status.Unset; _description= None}
; name
; parent= None
; span_kind= SpanKind.Client (* This will be the span of the client call*)
Expand All @@ -624,6 +626,30 @@ module Tracer = struct
let span = Span.start ~attributes ~name ~parent ~span_kind () in
Spans.add_to_spans ~span ; Ok (Some span)

let update_span_with_parent span (parent : Span.t option) =
GabrielBuica marked this conversation as resolved.
Show resolved Hide resolved
if Atomic.get observe then
match parent with
| None ->
Some span
| Some parent ->
span
|> Spans.remove_from_spans
|> Option.map (fun existing_span ->
let old_context = Span.get_context existing_span in
let new_context : SpanContext.t =
SpanContext.context
(SpanContext.trace_id_of_span_context parent.context)
old_context.span_id
in
let updated_span = {existing_span with parent= Some parent} in
let updated_span = {updated_span with context= new_context} in

let () = Spans.add_to_spans ~span:updated_span in
updated_span
)
else
Some span

let finish ?error span =
Ok
(Option.map
Expand Down Expand Up @@ -673,6 +699,13 @@ let with_tracing ?(attributes = []) ?(parent = None) ~name f =
) else
f None

let with_child_trace ?attributes parent ~name f =
match parent with
| None ->
f None
| Some _ as parent ->
with_tracing ?attributes ~parent ~name f

module EnvHelpers = struct
let traceparent_key = "TRACEPARENT"

Expand Down
21 changes: 21 additions & 0 deletions ocaml/libs/tracing/tracing.mli
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ end
module SpanContext : sig
type t

val context : string -> string -> t

val to_traceparent : t -> string

val of_traceparent : string -> t option
Expand Down Expand Up @@ -125,6 +127,16 @@ module Tracer : sig
-> unit
-> (Span.t option, exn) result

val update_span_with_parent : Span.t -> Span.t option -> Span.t option
(**[update_span_with_parent s p] returns [Some span] where [span] is an
updated verison of the span [s].
If [p] is [Some parent], [span] is a child of [parent], otherwise it is the
original [s].

If the span [s] is finished or is no longer considered an on-going span,
returns [None].
*)

val finish :
?error:exn * string -> Span.t option -> (Span.t option, exn) result

Expand Down Expand Up @@ -199,6 +211,15 @@ val with_tracing :
-> (Span.t option -> 'a)
-> 'a

val with_child_trace :
?attributes:(string * string) list
-> Span.t option
-> name:string
-> (Span.t option -> 'a)
-> 'a
(** [with_child_trace ?attributes ?parent ~name f] is like {!val:with_tracing}, but
only creates a span if the [parent] span exists. *)

val get_observe : unit -> bool

val validate_attribute : string * string -> bool
Expand Down
Loading
Loading