123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189(* Copyright (c) 2020, Francois Berenger.
* Copyright (c) 2014, INRIA.
* Copyright (c) 2013, Zhang Initiative Research Unit,
* Advance Science Institute, RIKEN
* 2-1 Hirosawa, Wako, Saitama 351-0198, Japan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *)openPrintf(* localtime is used to date events, _not_ GMT, BEWARE SCIENTIST *)typelog_level=|FATAL|ERROR|WARN|INFO|DEBUGletint_of_level=function|FATAL->4|ERROR->3|WARN->2|INFO->1|DEBUG->0letstring_of_level=function|FATAL->"FATAL"|ERROR->"ERROR"|WARN->"WARN "|INFO->"INFO "|DEBUG->"DEBUG"letchar_of_level=function|FATAL->'F'|ERROR->'E'|WARN->'W'|INFO->'I'|DEBUG->'D'letlevel_of_string=function|"FATAL"|"fatal"->FATAL|"ERROR"|"error"->ERROR|"WARN"|"warn"->WARN|"INFO"|"info"->INFO|"DEBUG"|"debug"->DEBUG|str->failwith("no such log level: "^str)typecolor=Black|Red|Green|Yellow|Blue|Magenta|Cyan|White|Default(* ANSI terminal colors for UNIX *)letcolor_to_string=function|Black->"\027[30m"|Red->"\027[31m"|Green->"\027[32m"|Yellow->"\027[33m"|Blue->"\027[34m"|Magenta->"\027[35m"|Cyan->"\027[36m"|White->"\027[37m"|Default->"\027[39m"letcolor_reset="\027[0m"(* default log levels color mapping *)letcolor_of_level=function|FATAL->Magenta|ERROR->Red|WARN->Yellow|INFO->Green|DEBUG->Cyan(* defaults *)letlevel=refERRORletoutput=refstderrletlevel_to_color=refcolor_of_levelletuse_color=reffalseletprefix=ref""letset_log_levell=level:=lletget_log_level()=!levelletset_outputo=output:=oletset_prefixp=prefix:=pletclear_prefix()=prefix:=""letset_color_mappingf=level_to_color:=fletcolor_on()=use_color:=trueletcolor_off()=use_color:=falseletlevel_to_stringlvl=lets=string_of_levellvlinif!use_colorthenletcolor=!level_to_colorlvlin(color_to_stringcolor)^s^(color_reset)elsesletlevel_to_short_stringlvl=letc=char_of_levellvlinif!use_colorthenletcolor=!level_to_colorlvlinsprintf"%s%c%s"(color_to_stringcolor)c(color_reset)elseString.make1cletshort_prefix_builderlvl=letts=Unix.gettimeofday()inlettm=Unix.localtimetsinletus,_s=modftsinsprintf"%02d:%02d:%02d.%02d|%s%s: "tm.Unix.tm_hourtm.Unix.tm_mintm.Unix.tm_sec(int_of_float(100.*.us))(* 1/100 s *)(level_to_short_stringlvl)!prefixlettimestamp_strlvl=letts=Unix.gettimeofday()inlettm=Unix.localtimetsinletus,_s=modftsin(* example: "2012-01-13 18:26:52.091" *)sprintf"%04d-%02d-%02d %02d:%02d:%02d.%03d %s%s: "(1900+tm.Unix.tm_year)(1+tm.Unix.tm_mon)tm.Unix.tm_mdaytm.Unix.tm_hourtm.Unix.tm_mintm.Unix.tm_sec(int_of_float(1_000.*.us))(level_to_stringlvl)!prefixletprefix_builder=reftimestamp_strletset_prefix_builderf=prefix_builder:=fletget_prefix_builder()=!prefix_builderletloglvlfmt=ifint_of_levellvl>=int_of_level!levelthenletnow=!prefix_builderlvlinfprintf!output("%s"^^fmt^^"\n%!")nowelseifprintf!outputfmtletfatalfmt=logFATALfmtleterrorfmt=logERRORfmtletwarnfmt=logWARNfmtletinfofmt=logINFOfmtletdebugfmt=logDEBUGfmt