[log] add colors to console output

Summary: Make errors stand out with colours. Also improve error messages around save states.

Reviewed By: mbouaziz

Differential Revision: D7928794

fbshipit-source-id: c81cfe2
master
Jules Villard 7 years ago committed by Facebook Github Bot
parent cbfdacd21c
commit 1fd11ee3cc

@ -877,7 +877,9 @@ let parse_args ~usage initial_action ?initial_command args =
if !anon_arg_action.on_unknown <> `Reject && is_unknown usage_msg then ( if !anon_arg_action.on_unknown <> `Reject && is_unknown usage_msg then (
anon_fun !args_to_parse.(!arg_being_parsed) ; anon_fun !args_to_parse.(!arg_being_parsed) ;
parse_loop () ) parse_loop () )
else Pervasives.(prerr_string usage_msg ; exit 1) else (
ANSITerminal.prerr_string L.(term_styles_of_style Fatal) usage_msg ;
Pervasives.exit 1 )
| Arg.Help _ -> | Arg.Help _ ->
(* we handle --help by ourselves and error on -help, so Arg has no way to raise Help (* we handle --help by ourselves and error on -help, so Arg has no way to raise Help
anymore *) anymore *)

@ -2265,9 +2265,9 @@ let post_parsing_initialization command_opt =
in in
let print_exception () = let print_exception () =
let error prefix msg = let error prefix msg =
ANSITerminal.(prerr_string [Bold; Foreground Red]) prefix ; ANSITerminal.prerr_string L.(term_styles_of_style Fatal) prefix ;
ANSITerminal.(prerr_string [Bold; Foreground Red]) msg ; ANSITerminal.prerr_string L.(term_styles_of_style Fatal) msg ;
Out_channel.newline stderr ANSITerminal.prerr_string L.(term_styles_of_style Normal) "\n"
in in
match exn with match exn with
| Failure msg -> | Failure msg ->
@ -2281,19 +2281,17 @@ let post_parsing_initialization command_opt =
| L.InferExit _ -> | L.InferExit _ ->
() ()
| _ -> | _ ->
error "Uncaught error: " (Exn.to_string exn) error "Uncaught Internal Error: " (Exn.to_string exn)
in in
if not is_infer_exit_zero && (should_print_backtrace_default || !developer_mode) then (
Out_channel.newline stderr ;
ANSITerminal.(prerr_string [Foreground Red]) "Error backtrace:" ;
Out_channel.newline stderr ;
ANSITerminal.(prerr_string [Foreground Red]) backtrace ) ;
print_exception () ; print_exception () ;
if not is_infer_exit_zero && (should_print_backtrace_default || !developer_mode) then (
ANSITerminal.prerr_string L.(term_styles_of_style Error) "Error backtrace:\n" ;
ANSITerminal.prerr_string L.(term_styles_of_style Error) backtrace ) ;
if not is_infer_exit_zero then Out_channel.newline stderr ; if not is_infer_exit_zero then Out_channel.newline stderr ;
if suggest_keep_going then ( if suggest_keep_going then
ANSITerminal.(prerr_string []) ANSITerminal.prerr_string
"Run the command again with `--keep-going` to try and ignore this error." ; L.(term_styles_of_style Normal)
Out_channel.newline stderr ) ; "Run the command again with `--keep-going` to try and ignore this error.\n" ;
let exitcode = L.exit_code_of_exception exn in let exitcode = L.exit_code_of_exception exn in
L.log_uncaught_exception exn ~exitcode ; L.log_uncaught_exception exn ~exitcode ;
Epilogues.late () ; Epilogues.late () ;

@ -50,3 +50,16 @@ let exit_code_of_exception = function
exitcode exitcode
| _ -> | _ ->
(* exit code 2 is used by the OCaml runtime in cases of uncaught exceptions *) 2 (* exit code 2 is used by the OCaml runtime in cases of uncaught exceptions *) 2
type style = Error | Fatal | Normal | Warning
let term_styles_of_style = function
| Error ->
ANSITerminal.[Foreground Red]
| Fatal ->
ANSITerminal.[Bold; Foreground Red]
| Normal ->
[ANSITerminal.default]
| Warning ->
ANSITerminal.[Foreground Yellow]

@ -35,3 +35,7 @@ val die : error -> ('a, Format.formatter, unit, _) format4 -> 'a
(** Raise the corresponding exception. *) (** Raise the corresponding exception. *)
val raise_error : error -> msg:string -> 'a val raise_error : error -> msg:string -> 'a
type style = Error | Fatal | Normal | Warning
val term_styles_of_style : style -> ANSITerminal.style list

@ -87,9 +87,25 @@ let mk_file_formatter file_fmt category0 =
f f
let color_console ?(use_stdout= false) scheme =
let scheme = Option.value scheme ~default:Normal in
let formatter = if use_stdout then F.std_formatter else F.err_formatter in
let can_colorize = Unix.(isatty (if use_stdout then stdout else stderr)) in
if can_colorize then (
let styles = term_styles_of_style scheme in
let out_string s p n =
let print = if use_stdout then ANSITerminal.print_string else ANSITerminal.prerr_string in
print styles (String.slice s p n)
in
F.pp_set_formatter_out_functions formatter
{(F.pp_get_formatter_out_functions formatter ()) with F.out_string} ;
formatter )
else formatter
let register_formatter = let register_formatter =
let all_prefixes = ref [] in let all_prefixes = ref [] in
fun ?(use_stdout= false) prefix -> fun ?use_stdout ?color_scheme prefix ->
all_prefixes := prefix :: !all_prefixes ; all_prefixes := prefix :: !all_prefixes ;
(* lazy so that we get a chance to register all prefixes before computing their max length for (* lazy so that we get a chance to register all prefixes before computing their max length for
alignment purposes *) alignment purposes *)
@ -101,7 +117,7 @@ let register_formatter =
in in
let justified_prefix = fill ^ prefix in let justified_prefix = fill ^ prefix in
let mk_formatters () = let mk_formatters () =
let console = if use_stdout then F.std_formatter else F.err_formatter in let console = color_console ?use_stdout color_scheme in
match !log_file with match !log_file with
| Some (file_fmt, _) -> | Some (file_fmt, _) ->
let file = mk_file_formatter file_fmt justified_prefix in let file = mk_file_formatter file_fmt justified_prefix in
@ -167,11 +183,11 @@ let debug_dev_file_fmts = register_formatter "local debug"
let environment_info_file_fmts = register_formatter "environment" let environment_info_file_fmts = register_formatter "environment"
let external_warning_file_fmts = register_formatter "extern warn" let external_warning_file_fmts = register_formatter ~color_scheme:Warning "extern warn"
let external_error_file_fmts = register_formatter "extern err" let external_error_file_fmts = register_formatter ~color_scheme:Error "extern err"
let internal_error_file_fmts = register_formatter "intern err" let internal_error_file_fmts = register_formatter ~color_scheme:Error "intern err"
let phase_file_fmts = register_formatter "phase" let phase_file_fmts = register_formatter "phase"
@ -179,9 +195,9 @@ let progress_file_fmts = register_formatter "progress"
let result_file_fmts = register_formatter ~use_stdout:true "result" let result_file_fmts = register_formatter ~use_stdout:true "result"
let user_warning_file_fmts = register_formatter "user warn" let user_warning_file_fmts = register_formatter ~color_scheme:Warning "user warn"
let user_error_file_fmts = register_formatter "user err" let user_error_file_fmts = register_formatter ~color_scheme:Fatal "user err"
let phase fmt = log ~to_console:false phase_file_fmts fmt let phase fmt = log ~to_console:false phase_file_fmts fmt

@ -59,10 +59,12 @@ let create_results_dir () =
RunState.load_and_validate () RunState.load_and_validate ()
|> Result.iter_error ~f:(fun error -> |> Result.iter_error ~f:(fun error ->
if Config.force_delete_results_dir then ( if Config.force_delete_results_dir then (
L.user_warning L.user_warning "WARNING: %s@\n" error ;
"%s@\nDeleting results dir because --force-delete-results-dir was passed@." error ; L.progress "Deleting results dir because --force-delete-results-dir was passed@." ;
remove_results_dir () ) remove_results_dir () )
else L.die UserError "%s@\nPlease remove '%s' and try again" error Config.results_dir ) ; else
L.die UserError "ERROR: %s@\nPlease remove '%s' and try again" error
Config.results_dir ) ;
Unix.mkdir_p Config.results_dir ; Unix.mkdir_p Config.results_dir ;
Unix.mkdir_p (Config.results_dir ^/ Config.events_dir_name) ; Unix.mkdir_p (Config.results_dir ^/ Config.events_dir_name) ;
List.iter ~f:Unix.mkdir_p results_dir_dir_markers ; List.iter ~f:Unix.mkdir_p results_dir_dir_markers ;

@ -45,27 +45,26 @@ let load_and_validate () =
(fun err_msg -> (fun err_msg ->
Error Error
(Printf.sprintf (Printf.sprintf
"Incompatible results directory '%s':\n\ "'%s' already exists but it is not an empty directory and it does not look like an \
infer results directory:\n \
%s\n\ %s\n\
Was '%s' created using an older version of infer?" Was it created using an older version of infer?"
Config.results_dir err_msg Config.results_dir) ) Config.results_dir err_msg) )
msg msg
in in
if Sys.file_exists state_file_path <> `Yes then error "save state not found" if Sys.file_exists state_file_path <> `Yes then
error "save state not found: '%s' does not exist" state_file_path
else else
try match Ag_util.Json.from_file Runstate_j.read_t state_file_path with
let loaded_state = Ag_util.Json.from_file Runstate_j.read_t state_file_path in | {Runstate_t.results_dir_format} as loaded_state
if when String.equal !state.Runstate_t.results_dir_format results_dir_format ->
not
(String.equal !state.Runstate_t.results_dir_format
loaded_state.Runstate_t.results_dir_format)
then
error "Incompatible formats: found\n %s\n\nbut expected this format:\n %s\n\n"
loaded_state.results_dir_format !state.Runstate_t.results_dir_format
else (
state := loaded_state ; state := loaded_state ;
Ok () ) Ok ()
with _ -> Error "error reading the save state" | {Runstate_t.results_dir_format} ->
error "Incompatible formats: found\n %s\n\nbut expected this format:\n %s\n\n"
results_dir_format !state.Runstate_t.results_dir_format
| exception e ->
error "could not read the save state '%s': %s" state_file_path (Exn.to_string e)
let reset () = state := state0 let reset () = state := state0

@ -129,7 +129,7 @@ let () =
| Some cluster -> | Some cluster ->
F.fprintf fmt "of cluster %s" (Filename.basename cluster) F.fprintf fmt "of cluster %s" (Filename.basename cluster)
in in
L.environment_info "Starting analysis %a" pp_cluster_opt Config.cluster_cmdline ; L.progress "Starting analysis %a" pp_cluster_opt Config.cluster_cmdline ;
run Driver.Analyze run Driver.Analyze
| Capture | Compile | Run -> | Capture | Compile | Run ->
run (Lazy.force Driver.mode_from_command_line) run (Lazy.force Driver.mode_from_command_line)
@ -140,7 +140,7 @@ let () =
( match (Config.report_current, Config.report_previous) with ( match (Config.report_current, Config.report_previous) with
| None, None -> | None, None ->
L.(die UserError) L.(die UserError)
"Expected at least one argument among 'report-current' and 'report-previous'" "Expected at least one argument among '--report-current' and '--report-previous'"
| _ -> | _ ->
() ) ; () ) ;
ReportDiff.reportdiff ~current_report:Config.report_current ReportDiff.reportdiff ~current_report:Config.report_current

@ -372,7 +372,7 @@ let error_nothing_to_analyze mode =
| None -> | None ->
L.user_warning "%s%s Try cleaning the build first.@." nothing_to_compile_msg L.user_warning "%s%s Try cleaning the build first.@." nothing_to_compile_msg
please_run_capture_msg ) ; please_run_capture_msg ) ;
L.user_error "There was nothing to analyze.@\n@." L.progress "There was nothing to analyze.@."
let analyze_and_report ?suppress_console_report ~changed_files mode = let analyze_and_report ?suppress_console_report ~changed_files mode =

Loading…
Cancel
Save