123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190(* Copyright (c) 2019, 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"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)elsesletsection_width=ref0moduletypeS=sigvallog:log_level->('a,out_channel,unit)format->'avalfatal:('a,out_channel,unit)format->'avalerror:('a,out_channel,unit)format->'avalwarn:('a,out_channel,unit)format->'avalinfo:('a,out_channel,unit)format->'avaldebug:('a,out_channel,unit)format->'aendmoduletypeSECTION=sigvalsection:stringendmoduleMake(S:SECTION)=structlet()=ifS.section<>""thensection_width:=max(String.lengthS.section)!section_widthlettimestamp_strlvl=letsection=if!section_width=0then""elsesprintf"%-*s "!section_widthS.sectioninletts=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%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))section(level_to_stringlvl)!prefix(* example for a shorter timestamp string *)let_short_timestamp_strlvl=sprintf"%.3f %s: "(Unix.gettimeofday())(string_of_levellvl)letloglvlfmt=ifint_of_levellvl>=int_of_level!levelthenletnow=timestamp_strlvlinfprintf!output("%s"^^fmt^^"\n%!")nowelseifprintf!outputfmtletfatalfmt=logFATALfmtleterrorfmt=logERRORfmtletwarnfmt=logWARNfmtletinfofmt=logINFOfmtletdebugfmt=logDEBUGfmtendincludeMake(structletsection=""end)