You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
203 lines
6.2 KiB
203 lines
6.2 KiB
7 years ago
|
(*
|
||
6 years ago
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||
7 years ago
|
*
|
||
|
* This source code is licensed under the MIT license found in the
|
||
|
* LICENSE file in the root directory of this source tree.
|
||
|
*)
|
||
7 years ago
|
|
||
5 years ago
|
module Char = Base.Char
|
||
|
module List = Base.List
|
||
|
module Map = Base.Map
|
||
|
module Option = Base.Option
|
||
|
module String = Base.String
|
||
|
|
||
7 years ago
|
(** Debug trace logging *)
|
||
|
|
||
5 years ago
|
type 'a printf = ('a, Format.formatter, unit) format -> 'a
|
||
6 years ago
|
type pf = {pf: 'a. 'a printf}
|
||
7 years ago
|
|
||
6 years ago
|
let fs = Format.err_formatter
|
||
|
let flush = Format.pp_print_newline fs
|
||
7 years ago
|
|
||
6 years ago
|
type trace_mod_funs =
|
||
|
{trace_mod: bool option; trace_funs: bool Map.M(String).t}
|
||
7 years ago
|
|
||
6 years ago
|
type trace_mods_funs = trace_mod_funs Map.M(String).t
|
||
7 years ago
|
|
||
5 years ago
|
type config =
|
||
|
{trace_all: bool; trace_mods_funs: trace_mods_funs; colors: bool}
|
||
|
|
||
|
let none =
|
||
|
{ trace_all= false
|
||
|
; trace_mods_funs= Map.empty (module String)
|
||
|
; colors= false }
|
||
|
|
||
6 years ago
|
let all = {none with trace_all= true}
|
||
6 years ago
|
let config : config ref = ref none
|
||
7 years ago
|
|
||
6 years ago
|
let parse s =
|
||
6 years ago
|
try
|
||
6 years ago
|
if String.equal s "*" then Ok all
|
||
|
else
|
||
|
let default = Map.empty (module String) in
|
||
|
let index_from s i =
|
||
|
Option.merge ~f:min
|
||
|
(String.index_from s i '+')
|
||
|
(String.index_from s i '-')
|
||
|
in
|
||
|
let rec split s rev_parts i =
|
||
|
match index_from s (i + 1) with
|
||
|
| Some j when j = i -> split s rev_parts j
|
||
|
| Some j ->
|
||
|
split s (String.sub s ~pos:i ~len:(j - i) :: rev_parts) j
|
||
|
| _ -> List.rev (String.subo s ~pos:i :: rev_parts)
|
||
|
in
|
||
|
let parts = split s [] 0 in
|
||
|
let trace_mods_funs =
|
||
|
List.fold parts ~init:default ~f:(fun m part ->
|
||
|
let parse_part part =
|
||
|
let sign, rest =
|
||
|
match part.[0] with
|
||
|
| '-' -> (false, String.subo part ~pos:1)
|
||
|
| '+' -> (true, String.subo part ~pos:1)
|
||
|
| _ -> (true, part)
|
||
6 years ago
|
in
|
||
6 years ago
|
assert (not (String.is_empty rest)) ;
|
||
|
assert (Char.is_uppercase rest.[0]) ;
|
||
|
match String.lsplit2 rest ~on:'.' with
|
||
|
| Some (mod_name, fun_name) ->
|
||
|
assert (Char.is_lowercase fun_name.[0]) ;
|
||
|
(mod_name, Some fun_name, sign)
|
||
|
| None -> (rest, None, sign)
|
||
|
in
|
||
|
match parse_part part with
|
||
|
| mod_name, Some fun_name, enabled ->
|
||
|
let {trace_mod; trace_funs} =
|
||
|
match Map.find m mod_name with
|
||
|
| Some c -> c
|
||
|
| None -> {trace_mod= None; trace_funs= default}
|
||
|
in
|
||
|
Map.set m ~key:mod_name
|
||
|
~data:
|
||
|
{ trace_mod
|
||
|
; trace_funs=
|
||
|
Map.set trace_funs ~key:fun_name ~data:enabled }
|
||
|
| mod_name, None, enabled ->
|
||
|
Map.set m ~key:mod_name
|
||
|
~data:{trace_mod= Some enabled; trace_funs= default} )
|
||
|
in
|
||
|
Ok {none with trace_mods_funs}
|
||
6 years ago
|
with Assert_failure _ as exn -> Error exn
|
||
6 years ago
|
|
||
5 years ago
|
let pp_styled style fmt fs =
|
||
|
Format.pp_open_box fs 2 ;
|
||
5 years ago
|
if not !config.colors then
|
||
|
Format.kfprintf (fun fs -> Format.pp_close_box fs ()) fs fmt
|
||
5 years ago
|
else (
|
||
|
( match style with
|
||
5 years ago
|
| `Bold -> Format.fprintf fs "@<0>\027[1m"
|
||
|
| `Cyan -> Format.fprintf fs "@<0>\027[36m"
|
||
|
| `Magenta -> Format.fprintf fs "@<0>\027[95m" ) ;
|
||
5 years ago
|
Format.kfprintf
|
||
|
(fun fs ->
|
||
5 years ago
|
Format.fprintf fs "@<0>\027[0m" ;
|
||
5 years ago
|
Format.pp_close_box fs () )
|
||
|
fs fmt )
|
||
|
|
||
5 years ago
|
let init ?(colors = false) ?(margin = 240) ?config:(c = none) () =
|
||
7 years ago
|
Format.set_margin margin ;
|
||
|
Format.set_max_indent (margin - 1) ;
|
||
6 years ago
|
Format.pp_set_margin fs margin ;
|
||
|
Format.pp_set_max_indent fs (margin - 1) ;
|
||
|
Format.pp_open_vbox fs 0 ;
|
||
7 years ago
|
Caml.at_exit flush ;
|
||
5 years ago
|
config := {c with colors}
|
||
6 years ago
|
|
||
|
let unwrap s =
|
||
|
let rec index s i =
|
||
|
if i <= 1 then None
|
||
|
else if not (Char.equal '_' s.[i]) then index s (i - 1)
|
||
|
else if not (Char.equal '_' s.[i - 1]) then index s (i - 2)
|
||
|
else Some (i + 1)
|
||
|
in
|
||
|
match index s (String.length s - 2) with
|
||
|
| Some pos -> String.subo s ~pos
|
||
|
| None -> s
|
||
|
|
||
|
let enabled mod_name fun_name =
|
||
5 years ago
|
let {trace_all; trace_mods_funs; _} = !config in
|
||
6 years ago
|
match Map.find trace_mods_funs (unwrap mod_name) with
|
||
|
| Some {trace_mod; trace_funs} -> (
|
||
|
match Map.find trace_funs fun_name with
|
||
|
| Some fun_enabled -> fun_enabled
|
||
|
| None -> (
|
||
|
match trace_mod with
|
||
|
| Some mod_enabled -> mod_enabled
|
||
|
| None -> trace_all ) )
|
||
|
| None -> trace_all
|
||
7 years ago
|
|
||
6 years ago
|
let kprintf mod_name fun_name k fmt =
|
||
|
if enabled mod_name fun_name then Format.kfprintf k fs fmt
|
||
|
else Format.ifprintf fs fmt
|
||
|
|
||
|
let fprintf mod_name fun_name fs fmt =
|
||
|
if enabled mod_name fun_name then Format.fprintf fs fmt
|
||
|
else Format.ifprintf fs fmt
|
||
|
|
||
|
let printf mod_name fun_name fmt = fprintf mod_name fun_name fs fmt
|
||
|
|
||
7 years ago
|
let info mod_name fun_name fmt =
|
||
6 years ago
|
if enabled mod_name fun_name then (
|
||
|
Format.fprintf fs "@\n@[<2>| " ;
|
||
|
Format.kfprintf (fun fs -> Format.fprintf fs "@]") fs fmt )
|
||
|
else Format.ifprintf fs fmt
|
||
|
|
||
5 years ago
|
let infok mod_name fun_name k =
|
||
|
k {pf= (fun fmt -> info mod_name fun_name fmt)}
|
||
|
|
||
6 years ago
|
let incf mod_name fun_name fmt =
|
||
|
if enabled mod_name fun_name then (
|
||
|
Format.fprintf fs "@\n@[<2>@[<hv 2>( %s:@ " fun_name ;
|
||
|
Format.kfprintf (fun fs -> Format.fprintf fs "@]") fs fmt )
|
||
|
else Format.ifprintf fs fmt
|
||
|
|
||
|
let decf mod_name fun_name fmt =
|
||
|
if enabled mod_name fun_name then (
|
||
|
Format.fprintf fs "@]@\n@[<2>) %s:@ " fun_name ;
|
||
|
Format.kfprintf (fun fs -> Format.fprintf fs "@]") fs fmt )
|
||
|
else Format.ifprintf fs fmt
|
||
|
|
||
|
let call mod_name fun_name k =
|
||
|
k {pf= (fun fmt -> incf mod_name fun_name fmt)}
|
||
7 years ago
|
|
||
|
let retn mod_name fun_name k result =
|
||
6 years ago
|
k {pf= (fun fmt -> decf mod_name fun_name fmt)} result ;
|
||
7 years ago
|
result
|
||
6 years ago
|
|
||
5 years ago
|
type ('a, 'b) fmt = ('a, Base.Formatter.t, unit, 'b) format4
|
||
|
|
||
|
let raisef ?margin exn fmt =
|
||
|
let bt = Caml.Printexc.get_raw_backtrace () in
|
||
|
let fs = Format.str_formatter in
|
||
|
( match margin with
|
||
|
| Some m ->
|
||
|
Format.pp_set_margin fs m ;
|
||
|
Format.pp_set_max_indent fs (m - 1)
|
||
|
| None -> () ) ;
|
||
|
Format.pp_open_box fs 2 ;
|
||
|
Format.kfprintf
|
||
|
(fun fs () ->
|
||
|
Format.pp_close_box fs () ;
|
||
|
let msg = Format.flush_str_formatter () in
|
||
|
let exn = exn msg in
|
||
|
Caml.Printexc.raise_with_backtrace exn bt )
|
||
|
fs fmt
|
||
|
|
||
6 years ago
|
let fail fmt =
|
||
5 years ago
|
let margin = Format.pp_get_margin fs () in
|
||
|
raisef ~margin
|
||
5 years ago
|
(fun msg ->
|
||
|
Format.fprintf fs "@\n@[<2>| %s@]@." msg ;
|
||
|
Failure msg )
|
||
|
fmt
|