1
- open Log_level
2
- module Sync_queue = Moonpool. Blocking_queue
1
+ open ! Log_level
3
2
4
3
type level = Log_level .t [@@ deriving show , eq ]
5
4
@@ -51,9 +50,12 @@ open struct
51
50
end
52
51
53
52
module Output = struct
54
- type t = { emit : Log_event .t -> unit } [@@ unboxed]
53
+ type t = {
54
+ emit : Log_event .t -> unit ;
55
+ flush : unit -> unit ;
56
+ }
55
57
56
- let to_event ~emit_ev () : t = { emit = emit_ev }
58
+ let to_event ~emit_ev ~ flush () : t = { emit = emit_ev; flush }
57
59
let () = Fmt. set_color_default true
58
60
59
61
let to_str_ (ev : Log_event.t ) : string =
@@ -92,41 +94,49 @@ module Output = struct
92
94
93
95
Buf_fmt. get_contents buf_fmt
94
96
95
- let to_str ~(emit_str : string -> unit ) () : t =
97
+ let to_str ~(emit_str : string -> unit ) ~ flush () : t =
96
98
{
97
99
emit =
98
100
(fun ev ->
99
101
let s = to_str_ ev in
100
102
emit_str s);
103
+ flush;
101
104
}
102
105
103
- let to_chan (oc : out_channel ) : t =
106
+ let to_chan ?(autoflush = true ) (oc : out_channel ) : t =
107
+ let oc = Lock_. create oc in
104
108
to_str
109
+ ~flush: (fun () -> Lock_. with_ oc Stdlib. flush)
105
110
~emit_str: (fun s ->
106
111
try
112
+ let @ oc = Lock_. with_ oc in
107
113
output_string oc s;
108
114
output_char oc '\n' ;
109
- flush oc
115
+ if autoflush then Stdlib. flush oc
110
116
with _ -> Printf. eprintf " logger: failed to log to chan\n %!" )
111
117
()
112
118
113
119
let stdout () = to_chan stdout
114
120
let stderr () = to_chan stderr
115
121
116
122
let filter_level pred (self : t ) : t =
117
- { emit = (fun ev -> if pred ev.lvl then self.emit ev) }
123
+ { emit = (fun ev -> if pred ev.lvl then self.emit ev); flush = self.flush }
118
124
119
125
let buf_pool : Buffer.t Apool.t =
120
126
Apool. create ~clear: Buffer. reset
121
127
~mk_item: (fun () -> Buffer. create 256 )
122
128
~max_size: 8 ()
123
129
124
130
(* * Logger that writes events, one per line, on the given channel. *)
125
- let to_chan_jsonl (oc : out_channel ) : t =
126
- to_event () ~emit_ev: (fun ev ->
131
+ let to_chan_jsonl ?(autoflush = true ) (oc : out_channel ) : t =
132
+ let oc = Lock_. create oc in
133
+ to_event ()
134
+ ~flush: (fun () -> Lock_. with_ oc flush)
135
+ ~emit_ev: (fun ev ->
127
136
let json = Log_event. to_yojson ev in
128
137
129
138
try
139
+ let @ oc = Lock_. with_ oc in
130
140
((* use a local buffer *)
131
141
let @ buf = Apool. with_resource buf_pool in
132
142
Buffer. clear buf;
@@ -135,16 +145,12 @@ module Output = struct
135
145
Buffer. output_buffer oc buf);
136
146
137
147
output_char oc '\n' ;
138
- flush oc
148
+ if autoflush then flush oc
139
149
with exn ->
140
150
Printf. eprintf " log to json chan: failed with %s\n %!"
141
151
(Printexc. to_string exn ))
142
152
end
143
153
144
- type task =
145
- | T_fence of { wakeup : unit Moonpool.Fut .promise }
146
- | T_emit of Log_event .t
147
-
148
154
type capture_meta_hook = unit -> (string * Log_meta .t ) list
149
155
150
156
open struct
@@ -183,19 +189,23 @@ end
183
189
let add_rich_tag = add_rich_tag
184
190
185
191
type t = {
186
- q : task Sync_queue .t ;
187
- events : Log_event .t Observer .t ;
192
+ active : bool Atomic .t ;
193
+ events : Log_event .t Observer .t ; (* * Additional subscriptions on events *)
188
194
outputs : Output .t list Atomic .t ;
189
- reporter : Logs .reporter ;
190
- mutable bg_thread : Thread .t option ;
195
+ emit_ev : Log_event .t -> unit ;
196
+ emit_fence : unit -> unit ;
197
+ reporter : Logs .reporter ; (* * As reporter *)
191
198
}
192
199
193
200
let [@ inline] as_reporter self = self.reporter
194
201
let [@ inline] events self = self.events
202
+ let [@ inline] shutdown self = Atomic. set self.active false
195
203
196
- let shutdown self =
197
- Sync_queue. close self.q;
198
- Option. iter Thread. join self.bg_thread
204
+ let trace_level_of_level : level -> Trace.Level.t = function
205
+ | Info | App -> Trace.Level. Info
206
+ | Error -> Trace.Level. Error
207
+ | Warning -> Trace.Level. Warning
208
+ | Debug -> Trace.Level. Debug3
199
209
200
210
let add_output self out : unit =
201
211
while
@@ -267,7 +277,8 @@ let to_event_if_ (p : level -> bool) ~emit_ev : Logs.reporter =
267
277
at least the TEF collector needs to know on which thread we are running. *)
268
278
if Trace_core. enabled () then (
269
279
let msg = Ansi_clean. remove_escape_codes msg in
270
- Trace_core. message msg ~data: (fun () ->
280
+ Trace_core. message ~level: (trace_level_of_level level) msg
281
+ ~data: (fun () ->
271
282
let meta =
272
283
List. map (fun (k , v ) -> k, Log_meta. to_trace_data v) meta
273
284
in
@@ -290,6 +301,7 @@ let to_event_if_ (p : level -> bool) ~emit_ev : Logs.reporter =
290
301
in
291
302
{ Logs. report }
292
303
304
+ (*
293
305
let bg_thread_loop_ (self : t) : unit =
294
306
Trace_core.set_thread_name "logger.bg";
295
307
ignore
@@ -304,7 +316,7 @@ let bg_thread_loop_ (self : t) : unit =
304
316
Sys.sigusr2;
305
317
Sys.sigvtalrm;
306
318
]
307
- : _ list );
319
+ : _ list);
308
320
309
321
let local_q = Queue.create () in
310
322
try
@@ -323,55 +335,71 @@ let bg_thread_loop_ (self : t) : unit =
323
335
Queue.clear local_q
324
336
done
325
337
with Sync_queue.Closed -> ()
338
+ *)
326
339
327
- let fence_ : (unit -> unit Moonpool.Fut.t) ref =
328
- ref (fun () -> Moonpool.Fut. return () )
329
-
330
- let [@ inline] emit_ev (self : t ) ev : unit =
331
- try Sync_queue. push self.q (T_emit ev) with Sync_queue. Closed -> ()
340
+ let fence_ : (unit -> unit) ref = ref ignore
341
+ let set_as_fence_ (self : t ) : unit = fence_ := self.emit_fence
332
342
333
343
let to_outputs (outs : Output.t list ) : t =
344
+ let active = Atomic. make true in
334
345
let outputs = Atomic. make outs in
335
346
let events = Observer. create () in
336
- let q = Sync_queue. create () in
347
+ let emit_ev ev =
348
+ (try Observer. emit events ev
349
+ with exn ->
350
+ Printf. eprintf " logger observer failed with %s\n %!"
351
+ (Printexc. to_string exn ));
352
+ match Atomic. get outputs with
353
+ | [] -> ()
354
+ | outs ->
355
+ List. iter
356
+ (fun (out : Output.t ) ->
357
+ try out.emit ev
358
+ with exn ->
359
+ Printf. eprintf " logger output failed with %s\n %!"
360
+ (Printexc. to_string exn ))
361
+ outs
362
+ in
337
363
let reporter =
338
364
to_event_if_
339
365
(fun _ ->
340
366
(* emit event only if we have some outputs or event subscribers *)
341
- Observer. has_subscribers events
342
- || not ( CCList. is_empty ( Atomic. get outputs)))
343
- ~emit_ev: ( fun ev ->
344
- try Sync_queue. push q ( T_emit ev) with Sync_queue. Closed -> () )
367
+ Atomic. get active
368
+ && ( Observer. has_subscribers events
369
+ || not ( CCList. is_empty ( Atomic. get outputs))))
370
+ ~emit_ev
345
371
in
346
372
347
- let fence () =
348
- let fut, prom = Moonpool.Fut. make () in
349
- (try Sync_queue. push q (T_fence { wakeup = prom })
350
- with Sync_queue. Closed -> Moonpool.Fut. fulfill prom @@ Ok () );
351
- fut
373
+ let emit_fence () =
374
+ let outs = Atomic. get outputs in
375
+ List. iter (fun (out : Output.t ) -> out.flush () ) outs
352
376
in
353
377
354
- fence_ := fence;
355
- let self = { q; outputs; reporter; events; bg_thread = None } in
356
- self.bg_thread < - Some (Thread. create bg_thread_loop_ self);
378
+ let self = { active; emit_ev; emit_fence; outputs; reporter; events } in
357
379
self
358
380
381
+ let [@ inline] emit_ev (self : t ) ev : unit = self.emit_ev ev
359
382
let null () : t = to_outputs []
360
383
384
+ let setup_ (self : t ) : unit =
385
+ Logs. set_reporter self.reporter;
386
+ set_as_fence_ self;
387
+ ()
388
+
361
389
let with_no_logger () f =
362
390
let old = Logs. reporter () in
363
391
Logs. set_reporter Logs. nop_reporter;
364
392
Fun. protect ~finally: (fun () -> Logs. set_reporter old) f
365
393
366
394
let setup_logger_to_stdout () =
367
395
let outs = [ Output. stdout () ] in
368
- let reporter = to_outputs outs in
369
- Logs. set_reporter (as_reporter reporter)
396
+ let logger = to_outputs outs in
397
+ setup_ logger
370
398
371
399
let setup_logger_to_stderr () =
372
400
let outs = [ Output. stderr () ] in
373
- let reporter = to_outputs outs in
374
- Logs. set_reporter (as_reporter reporter)
401
+ let logger = to_outputs outs in
402
+ setup_ logger
375
403
376
404
(* * Setup a logger that emits into the file specified in ["LOG_FILE"] env,
377
405
or no logger otherwise. *)
@@ -380,7 +408,8 @@ let setup_logger_to_LOG_FILE ?filename () k =
380
408
| Some file , _ | None , Some file ->
381
409
let @ oc = CCIO. with_out file in
382
410
let outs = [ Output. to_chan oc ] in
383
- Logs. set_reporter (to_outputs outs |> as_reporter);
411
+ let logger = to_outputs outs in
412
+ setup_ logger;
384
413
k ()
385
414
| _ -> k ()
386
415
@@ -390,9 +419,7 @@ module type LOG = sig
390
419
val src : Logs .src
391
420
end
392
421
393
- let fence () =
394
- let fut = ! fence_ () in
395
- Moonpool.Fut. wait_block_exn fut
422
+ let [@ inline] fence () = ! fence_ ()
396
423
397
424
let mk_log_str s : (module LOG) =
398
425
let src = Logs.Src. create s in
0 commit comments