Source file trace_subscriber.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
open Trace_core
module Callbacks = Callbacks
module Subscriber = Subscriber
module Span_tbl = Span_tbl
include Types
type t = Subscriber.t
module Private_ = struct
let mock = ref false
let get_now_ns_ = ref Time_.get_time_ns
let get_tid_ = ref Thread_.get_tid
(** Now, in nanoseconds *)
let[@inline] now_ns () : int64 =
if !mock then
!get_now_ns_ ()
else
Time_.get_time_ns ()
let[@inline] tid_ () : int =
if !mock then
!get_tid_ ()
else
Thread_.get_tid ()
end
open struct
module A = Trace_core.Internal_.Atomic_
type manual_span_info = {
name: string;
flavor: flavor option;
mutable data: (string * user_data) list;
}
(** Key used to carry some information between begin and end of manual spans,
by way of the meta map *)
let key_manual_info : manual_span_info Meta_map.key = Meta_map.Key.create ()
end
let[@inline] conv_flavor = function
| `Async -> Async
| `Sync -> Sync
let[@inline] conv_flavor_opt = function
| None -> None
| Some f -> Some (conv_flavor f)
let[@inline] conv_user_data = function
| `Int i -> U_int i
| `Bool b -> U_bool b
| `Float f -> U_float f
| `String s -> U_string s
| `None -> U_none
let rec conv_data = function
| [] -> []
| [ (k, v) ] -> [ k, conv_user_data v ]
| (k, v) :: tl -> (k, conv_user_data v) :: conv_data tl
(** A collector that calls the callbacks of subscriber *)
let collector (Sub { st; callbacks = (module CB) } : Subscriber.t) : collector =
let open Private_ in
let module M = struct
let trace_id_gen_ = A.make 0
let[@inline] mk_trace_id () : trace_id =
let n = A.fetch_and_add trace_id_gen_ 1 in
let b = Bytes.create 8 in
Bytes.set_int64_le b 0 (Int64.of_int n);
Bytes.unsafe_to_string b
(** generator for span ids *)
let new_span_ : unit -> int =
let span_id_gen_ = A.make 0 in
fun [@inline] () -> A.fetch_and_add span_id_gen_ 1
let enter_span ~__FUNCTION__ ~__FILE__ ~__LINE__ ~data name : span =
let span = Int64.of_int (new_span_ ()) in
let tid = tid_ () in
let time_ns = now_ns () in
let data = conv_data data in
CB.on_enter_span st ~__FUNCTION__ ~__FILE__ ~__LINE__ ~time_ns ~tid ~data
~name span;
span
let exit_span span : unit =
let time_ns = now_ns () in
let tid = tid_ () in
CB.on_exit_span st ~time_ns ~tid span
let with_span ~__FUNCTION__ ~__FILE__ ~__LINE__ ~data name f =
let span = enter_span ~__FUNCTION__ ~__FILE__ ~__LINE__ ~data name in
try
let x = f span in
exit_span span;
x
with exn ->
let bt = Printexc.get_raw_backtrace () in
exit_span span;
Printexc.raise_with_backtrace exn bt
let add_data_to_span span data =
if data <> [] then (
let data = conv_data data in
CB.on_add_data st ~data span
)
let enter_manual_span ~(parent : explicit_span_ctx option) ~flavor
~__FUNCTION__ ~__FILE__ ~__LINE__ ~data name : explicit_span =
let span = Int64.of_int (new_span_ ()) in
let tid = tid_ () in
let time_ns = now_ns () in
let data = conv_data data in
let flavor = conv_flavor_opt flavor in
let trace_id, parent =
match parent with
| Some m -> m.trace_id, Some m.span
| None -> mk_trace_id (), None
in
CB.on_enter_manual_span st ~__FUNCTION__ ~__FILE__ ~__LINE__ ~parent ~data
~time_ns ~tid ~name ~flavor ~trace_id span;
let meta =
Meta_map.empty
|> Meta_map.add key_manual_info { name; flavor; data = [] }
in
{ span; trace_id; meta }
let exit_manual_span (es : explicit_span) : unit =
let time_ns = now_ns () in
let tid = tid_ () in
let trace_id = es.trace_id in
let minfo =
match Meta_map.find key_manual_info es.meta with
| None -> assert false
| Some m -> m
in
CB.on_exit_manual_span st ~tid ~time_ns ~data:minfo.data ~name:minfo.name
~flavor:minfo.flavor ~trace_id es.span
let add_data_to_manual_span (es : explicit_span) data =
if data <> [] then (
let data = conv_data data in
match Meta_map.find key_manual_info es.meta with
| None -> assert false
| Some m -> m.data <- List.rev_append data m.data
)
let message ?span ~data msg : unit =
let time_ns = now_ns () in
let tid = tid_ () in
let data = conv_data data in
CB.on_message st ~time_ns ~tid ~span ~data msg
let counter_float ~data name f : unit =
let time_ns = now_ns () in
let tid = tid_ () in
let data = conv_data data in
CB.on_counter st ~tid ~time_ns ~data ~name f
let[@inline] counter_int ~data name i =
counter_float ~data name (float_of_int i)
let name_process name : unit =
let tid = tid_ () in
let time_ns = now_ns () in
CB.on_name_process st ~time_ns ~tid ~name
let name_thread name : unit =
let tid = tid_ () in
let time_ns = now_ns () in
CB.on_name_thread st ~time_ns ~tid ~name
let shutdown () =
let time_ns = now_ns () in
CB.on_shutdown st ~time_ns
let extension_event ev =
let tid = tid_ () in
let time_ns = now_ns () in
CB.on_extension_event st ~time_ns ~tid ev
let () =
let time_ns = now_ns () in
CB.on_init st ~time_ns
end in
(module M)