Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file log_extended.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313openCoreopenAsyncincludeLogmoduleConsole=structmoduleAnsi=Console.Ansiletwith_style~debug~info~errormsg=letstyle,prefix=matchLog.Message.levelmsgwith|None->info,""|Some`Debug->debug,"[DEBUG]"|Some`Info->info," [INFO]"|Some`Error->error,"[ERROR]"inString.concat~sep:" "[prefix;Log.Message.messagemsg]|>Ansi.string_with_attrstyleletoutput?(debug=([`Yellow]:>Ansi.attrlist))?(info=([]:>Ansi.attrlist))?(error=([`Red]:>Ansi.attrlist))writer=Log.Output.create~flush:(fun()->return())(funmsgs->Queue.itermsgs~f:(funmsg->with_style~debug~info~errormsg|>(funstyled_msg->Writer.writewriterstyled_msg;Writer.newlinewriter));Deferred.any_unit[Writer.flushedwriter;Writer.consumer_leftwriter])moduleBlocking=structletoutput?(debug=([`Yellow]:>Ansi.attrlist))?(info=([]:>Ansi.attrlist))?(error=([`Red]:>Ansi.attrlist))outc=Log.Blocking.Output.create(funmsg->(with_style~debug~info~errormsg)|>funline->Out_channel.output_linesoutc[line])endendmoduleSyslog=structletto_syslogmsg=letprefix=matchLog.Message.levelmsgwith|None->""|Somel->Log.Level.to_stringl^" "inprefix^Log.Message.messagemsg;;letto_levelmsg=matchLog.Message.levelmsgwith(* syslog is generally not configured to show `LOG_DEBUG *)|None->Syslog.Level.INFO|Some`Debug->Syslog.Level.INFO|Some`Info->Syslog.Level.INFO|Some`Error->Syslog.Level.ERR;;letdefault_options=[Syslog.Open_option.PID;Syslog.Open_option.CONS]letopenlog?id?(options=default_options)?facility()=Syslog.openlog?id~options?facility();;letoutput?id?options?facility()=letready=letd=Ivar.create()in(* openlog () shouldn't block by default, but In_thread.run's a
cheap cure for paranoia *)upon(In_thread.run(openlog?id?options?facility))(fun()->Ivar.filld());Ivar.readdinLog.Output.create~flush:(fun()->return())(funmsgs->ready>>=fun()->In_thread.run(fun()->Queue.itermsgs~f:(funmsg->letsyslog_level=to_levelmsginletmsg=to_syslogmsginSyslog.syslog~level:syslog_level(msg^"\n"))));;moduleBlocking=structletoutput()=openlog();Log.Blocking.Output.create(funmsg->letsyslog_level=to_levelmsginletmsg=to_syslogmsginSyslog.syslog~level:syslog_level(msg^"\n"));;endendmoduleCommand=structopenCoreopenAsynctypeconsole_style=Plain|Color[@@derivingsexp]typeconsole_output=|No|Stdoutofconsole_style|Stderrofconsole_style[@@derivingsexp]moduleParameters=structtypet={log_level:Level.t;log_to_console:console_output;log_to_syslog:bool;log_to_file:stringoption}[@@derivingfields,sexp]moduleFlag_name=struct(* This module exists to make it easier to inspect flag names. *)letlog_to_file="log-to-file"letlog_to_console="log-to-console"letlog_to_stdout="log-to-stdout"letlog_with_color="log-with-color"letlog_to_syslog="log-to-syslog"letlog_level="log-level"endletlog_to_file_flagt=letdefault=Option.valuet.log_to_file~default:"<NONE>"inletdoc=sprintf"FILENAME Log to a file (default: %s)"defaultinCommand.Param.(flagFlag_name.log_to_file(optionalFilename.arg_type)~doc);;letlog_to_console_flagt=letdefault=matcht.log_to_consolewith|No->false|Stderr_|Stdout_->trueinletdoc=sprintf!"BOOL Log to console (default: %{Bool})"defaultinCommand.Param.(flagFlag_name.log_to_console(optional_with_defaultdefaultbool)~doc);;letlog_to_syslog_flagt=letdoc=sprintf!"BOOL Log to syslog (default: %{Bool})"t.log_to_sysloginCommand.Param.(flagFlag_name.log_to_syslog(optional_with_defaultt.log_to_syslogbool)~doc);;letlog_to_stdout_flagt=letdefault=matcht.log_to_consolewith|No->false|Stdout_->true|Stderr_->falseinletdoc=sprintf!"BOOL Log to stdout when logging to console (default: %{Bool})"defaultinCommand.Param.(flagFlag_name.log_to_stdout(optional_with_defaultdefaultbool)~doc);;letlog_with_color_flagt=letdefault=matcht.log_to_consolewith|No|StdoutPlain|StderrPlain->false|StdoutColor|StderrColor->trueinletdoc=sprintf!"BOOL Log with color when logging to console (default: %{Bool})"defaultinCommand.Param.(flagFlag_name.log_with_color(optional_with_defaultdefaultbool)~doc);;letlog_level_flagt=letdoc=sprintf!"LEVEL Set log level to one of [debug | error | info] (default: %{Log.Level})"t.log_levelinCommand.Param.(flagFlag_name.log_level(optional_with_defaultt.log_levelLevel.arg)~doc);;letcreate_log_to_console~log_to_console~log_with_color~log_to_stdout=matchlog_to_console,log_with_color,log_to_stdoutwith|false,true,_|false,_,true->failwithf"-%s and -%s require -%s"Flag_name.log_with_colorFlag_name.log_to_stdoutFlag_name.log_to_console()|true,false,false->StderrPlain|true,true,false->StderrColor|true,false,true->StdoutPlain|true,true,true->StdoutColor|false,false,false->No;;(* This tests the only(?) path to turning input into a safe type. *)let%expect_test"console_output"=letprint~log_to_console~log_with_color~log_to_stdout=letresult=matchcreate_log_to_console~log_to_console~log_with_color~log_to_stdout|>sexp_of_console_output|>Sexp.to_stringwith|exceptione->Or_error.of_exn~backtrace:(`This"")e|s->Or_error.returnsinAsync.printf!"%{sexp:string Or_error.t}\n"resultinprint~log_to_console:false~log_with_color:false~log_to_stdout:false;let%bind()=[%expect{| (Ok No) |}]inprint~log_to_console:false~log_with_color:true~log_to_stdout:true;let%bind()=[%expect{|
(Error
((Failure "-log-with-color and -log-to-stdout require -log-to-console") "")) |}]inprint~log_to_console:true~log_with_color:true~log_to_stdout:false;let%bind()=[%expect{| (Ok "(Stderr Color)") |}]inprint~log_to_console:true~log_with_color:false~log_to_stdout:false;let%bind()=[%expect{| (Ok "(Stderr Plain)") |}]inprint~log_to_console:true~log_with_color:true~log_to_stdout:true;let%bind()=[%expect{| (Ok "(Stdout Color)") |}]inprint~log_to_console:true~log_with_color:false~log_to_stdout:true;let%bind()=[%expect{| (Ok "(Stdout Plain)") |}]inDeferred.unit;;letparamst=let%map_open.Commandlog_to_file=log_to_file_flagtandlog_to_console=log_to_console_flagtandlog_to_stdout=log_to_stdout_flagtandlog_with_color=log_with_color_flagtandlog_to_syslog=log_to_syslog_flagtandlog_level=log_level_flagtin{log_to_file;log_to_console=create_log_to_console~log_to_console~log_with_color~log_to_stdout;log_to_syslog;log_level};;letconsole_outputt=matcht.log_to_consolewith|No->None|StderrPlain->Some(Log.Output.stderr())|StderrColor->Some(Console.output(Lazy.forceWriter.stderr))|StdoutPlain->Some(Log.Output.stdout())|StdoutColor->Some(Console.output(Lazy.forceWriter.stdout));;letsyslog_outputt=ift.log_to_syslogthenSome(Syslog.output())elseNoneletfile_outputt=matcht.log_to_filewith|None->None|Somefilename->Some(Output.file`Text~filename);;letoutputst=List.filter_map[console_outputt;syslog_outputt;file_outputt]~f:Fn.id;;endletsetup_via_params?(default_output_level=`Info)~log_to_console_by_default~log_to_syslog_by_default?log_to_file_by_default()=letdefault=Parameters.Fields.create~log_level:default_output_level~log_to_console:log_to_console_by_default~log_to_syslog:log_to_syslog_by_default~log_to_file:log_to_file_by_defaultinlet%map.Commandparams=Parameters.paramsdefaultinLog.Global.set_output(Parameters.outputsparams);Log.Global.set_level(Parameters.log_levelparams);;end