Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file logger.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536(**************************************************************************)(* This file is part of BINSEC. *)(* *)(* Copyright (C) 2016-2026 *)(* CEA (Commissariat à l'énergie atomique et aux énergies *)(* alternatives) *)(* *)(* you can redistribute it and/or modify it under the terms of the GNU *)(* Lesser General Public License as published by the Free Software *)(* Foundation, version 2.1. *)(* *)(* It is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)(* GNU Lesser General Public License for more details. *)(* *)(* See the GNU Lesser General Public License version 2.1 *)(* for more details (enclosed in the file licenses/LGPLv2.1). *)(* *)(**************************************************************************)openFormatletwith_tags_onppffmt=letmark_tags=pp_get_mark_tagsppf()andprint_tags=pp_get_print_tagsppf()inpp_set_mark_tagsppftrue;pp_set_print_tagsppftrue;kfprintf(funppf->pp_set_mark_tagsppfmark_tags;pp_set_print_tagsppfprint_tags)ppffmtmoduleColor=structtypet=|Black|DarkGray|Blue|LightBlue|Green|LightGreen|Cyan|LightCyan|Red|LightRed|Purple|LightPurple|Brown|Yellow|LightGray|Whitelet_terminal_encoding=function|Black->"0;30"|DarkGray->"1;30"|Blue->"0;34"|LightBlue->"1;34"|Green->"0;32"|LightGreen->"1;32"|Cyan->"0;36"|LightCyan->"1;36"|Red->"0;31"|LightRed->"1;31"|Purple->"0;35"|LightPurple->"1;35"|Brown->"0;33"|Yellow->"1;33"|LightGray->"0;37"|White->"1;37"letto_string=function|Black->"black"|DarkGray->"darkgray"|Blue->"blue"|LightBlue->"lightblue"|Green->"green"|LightGreen->"lightgreen"|Cyan->"cyan"|LightCyan->"lightcyan"|Red->"red"|LightRed->"lightred"|Purple->"purple"|LightPurple->"lightpurple"|Brown->"brown"|Yellow->"yellow"|LightGray->"lightgray"|White->"white"letstring_to_terminal_color_codescolor_name=matchString.lowercase_asciicolor_namewith|"black"->Some"0;30"|"darkgray"->Some"1;30"|"blue"->Some"0;34"|"lightblue"->Some"1;34"|"green"->Some"0;32"|"lightgreen"->Some"1;32"|"cyan"->Some"0;36"|"lightcyan"->Some"1;36"|"red"->Some"0;31"|"lightred"->Some"1;31"|"purple"->Some"0;35"|"lightpurple"->Some"1;35"|"brown"->Some"0;33"|"yellow"->Some"1;33"|"lightgray"->Some"0;37"|"white"->Some"1;37"|_->(* warning "Unsupported color name %s@." s;*)None(* ¯\_(ツ)_/¯ *)let_black=Blacklet_darkgray=DarkGraylet_blue=Bluelet_lightblue=LightBluelet_green=Greenlet_lightgreen=LightGreenlet_cyan=Cyanlet_lightcyan=LightCyanlet_red=Redlet_lightred=LightRedlet_purple=Purplelet_lightpurple=LightPurplelet_brown=Brownlet_yellow=Yellowlet_lightgray=LightGraylet_white=WhiteendmoduleChannelKind=structtypet=|ChInfo(* Normal output to feedback positive results *)|ChResult(* Normal output kind *)|ChDebug(* Debug message *)|ChWarning(* Warning message *)|ChError(* For events not meant to occur but that we can handle *)|ChFatal(* Fatal failures *)letto_string=function|ChInfo->"info"|ChResult->"result"|ChDebug->"debug"|ChWarning->"warning"|ChError->"error"|ChFatal->"fatal"letvalues=["debug";"info";"result";"warning";"error";"fatal"]letloglevel=function|ChDebug->0|ChInfo->10|ChWarning->20|ChError->100|ChFatal->max_int(* Fatal & Result channels cannot be turned off *)|ChResult->max_intletof_strings=matchString.lowercase_asciiswith|"info"->ChInfo|"result"->ChResult|"warning"->ChWarning|"error"->ChError|"fatal"->ChFatal|"debug"->ChDebug|s->failwith(sprintf"%s not a channel string identifier"s)letis_string_identifiers=matchof_stringswith_->true|exceptionFailure_->falseletcolorkind=letopenColorinmatchkindwith|ChInfo->LightGray|ChResult->LightGray|ChDebug->Cyan|ChWarning->Yellow|ChError->LightRed|ChFatal->RedendmoduletypeS=sigtypechannelvalfatal_channel:channelvalerror_channel:channelvalresult_channel:channelvalwarning_channel:channelvalinfo_channel:channelvaldebug_channel:channelvalfatal:?e:exn->('a,Format.formatter,unit,'b)format4->'avalerror:('a,Format.formatter,unit)format->'avalresult:('a,Format.formatter,unit)format->'avalwarning:?level:int->('a,Format.formatter,unit)format->'avalset_warning_level:int->unitvalget_warning_level:unit->intvalinfo:?level:int->('a,Format.formatter,unit)format->'avalset_info_level:int->unitvalget_info_level:unit->intvaldebug:?level:int->('a,Format.formatter,unit)format->'avalfdebug:?level:int->(unit->(unit,Format.formatter,unit)format)->unitvalset_debug_level:int->unitvalget_debug_level:unit->intvalis_debug_enabled:unit->boolvalset_tagged_entry:bool->unitvalset_log_level:string->unitvalquiet:unit->unitvalchannel_set_color:bool->channel->unitvalchannel_get_color:channel->boolvalset_color:bool->unitvalget_color:unit->boolvalset_logging:(string->unit)option->channel->unitendmoduletypeChannelGroup=sigvalname:stringendtypechannel={kind:ChannelKind.t;mutableppfs:Format.formatterlist;(* These are similar to listeners *)}moduleMake(G:ChannelGroup)=structletset_log_level,log_level_of_chkind,get_log_level,quiet=letloglevel=ref(ChannelKind.loglevelChannelKind.ChInfo)in((fun(s:string)->loglevel:=ChannelKind.of_strings|>ChannelKind.loglevel),(funck->letck_loglevel=ChannelKind.loglevelckin(* Only auto-update loglevel if it is lower than it already is *)ifck_loglevel<!loglevelthenloglevel:=ck_loglevel),(fun()->!loglevel),fun()->loglevel:=max_int)typenonrecchannel=channelletdefault_outkind={kind;ppfs=[Format.std_formatter]}leterr_outkind={kind;ppfs=[Format.err_formatter]}letdebug_channel=default_outChannelKind.ChDebugandinfo_channel=default_outChannelKind.ChInfoandresult_channel=default_outChannelKind.ChResultandwarning_channel=err_outChannelKind.ChWarninganderror_channel=err_outChannelKind.ChErrorandfatal_channel=err_outChannelKind.ChFatalletchannels=[debug_channel;info_channel;warning_channel;result_channel;error_channel;fatal_channel;]letset_formattersppfschannel=channel.ppfs<-ppfsletreset_channel:channel->unit=funchannel->matchchannel.kindwith|ChInfo|ChResult|ChDebug->set_formatters[Format.std_formatter]channel|ChWarning|ChError|ChFatal->set_formatters[Format.err_formatter]channelletset_tagged_entry,get_tagged_entry=lettag=reftruein((funta->tag:=ta),fun()->!tag)letchannel_group_delimiter=':'letchannel_namechan_kind=letchan_kind_name=ChannelKind.to_stringchan_kindinifG.name=""thenchan_kind_nameelsesprintf"%s%c%s"G.namechannel_group_delimiterchan_kind_name(* @assumes a tag string for channels has a form <[group_name/]channel_name>
It should have been produced by a call to [channel_name] to ensure the
pre-condition.
*)letchannel_kind_of_tagstringtag_string=matchString.indextag_stringchannel_group_delimiterwith|n->assert(n<>0);String.subtag_string(n+1)(String.lengthtag_string-n-1)|exceptionNot_found->tag_stringletis_channel_tagstringtag_string=channel_kind_of_tagstringtag_string|>ChannelKind.is_string_identifier(* Tag functions that react to color codes and channel tagging *)lettag_functionsppf=letmark_open_stag=function|String_tagtag_string->(matchColor.string_to_terminal_color_codestag_stringwith|None->""|Sometcolor_code->sprintf"\027[%sm"tcolor_code)|_->""andprint_open_stag=function|String_tagtag_string->ifget_tagged_entry()&&is_channel_tagstringtag_stringthenfprintfppf"[%s] "tag_string|_->()(* otherwise it's assumed to be a color tag string, handled by
[mark_open_tag] *)andprint_close_stag_tag_string=()andmark_close_stag_="\027[0m"in{mark_open_stag;mark_close_stag;print_open_stag;print_close_stag}letlogfinallychanneltxt=letppfs=channel.ppfsinletppfmttxt=ifChannelKind.loglevelchannel.kind>=get_log_level()thenFormat.kfprintf(funfmt->Format.kfprintf(funfmt->Format.kfprintffinallyfmt"@]@}@}@.")fmttxt)fmt"@{<%s>@{<%s>@[<hov 0>"(ChannelKind.colorchannel.kind|>Color.to_string)(channel_namechannel.kind)elseFormat.ikfprintffinallyfmttxtinletrecaux=function|[]->assertfalse(* One should not be able to "dry" a channel,
i.e. have no pretty-printing formatter associated to it *)|[ppf]->ppppftxt|ppf::ppfs->ignore@@ppppftxt;auxppfsinauxppfs(* module type Leveled_chan = sig
* val set : int -> unit
* val get : unit -> int
* val pass : int -> bool
* end
*
*
* let mk_level_mod chan =
* let module M = struct
* let level = ref 0
* let set n =
* assert (n >= 0);
* level := n;
* log_level_of_chkind chan.kind
*
* let get () = !level
*
* let pass n = n <= !level
* end
* in (module M:Leveled_chan) *)letmk_level_functionschan=letlevel=ref0in((fun()->!level),(funn->assert(n>=0);level:=n;log_level_of_chkindchan.kind),funlvl->lvl<=!level)(* let d = mk_level_mod debug_channel
* module Debug_level = (val d : Leveled_chan)
*
* let i = mk_level_mod info_channel
* module Info_level = (val i : Leveled_chan)
*
* let w = mk_level_mod warning_channel
* module Warning_level = (val w : Leveled_chan) *)letget_debug_level,set_debug_level,debug_pass=mk_level_functionsdebug_channelletis_debug_enabled=letthreshold=ChannelKind.loglevelChannelKind.ChDebuginfun()->get_log_level()<=thresholdletget_info_level,set_info_level,info_pass=mk_level_functionsinfo_channelletget_warning_level,set_warning_level,warning_pass=mk_level_functionswarning_channelletleveled_channelfinallychannellevel_pass?(level=0)txt=iflevel_passlevelthenlogfinallychanneltxtelseFormat.ifprintfFormat.std_formattertxtletfinally_unit_=()letdebug?(level=0)txt=leveled_channelfinally_unitdebug_channeldebug_pass~leveltxtletfdebug?(level=0)f=ifdebug_passlevelthenlogfinally_unitdebug_channel(f())elseFormat.ifprintfFormat.std_formatter""letinfo?(level=0)txt=leveled_channelfinally_unitinfo_channelinfo_pass~leveltxtletwarning?(level=0)txt=leveled_channelfinally_unitwarning_channelwarning_pass~leveltxtletfatal?(e=Failure"abort")txt=log(fun_->raisee)fatal_channeltxtleterrortxt=logfinally_uniterror_channeltxtletresulttxt=logfinally_unitresult_channeltxtlet_=List.iter(funchannel->letppfs=channel.ppfsinList.iter(funppf->pp_set_formatter_stag_functionsppf(tag_functionsppf);pp_set_print_tagsppftrue)ppfs)channelsletchannel_set_color,channel_get_color=letcolor_tbl=Hashtbl.create(List.lengthChannelKind.values)in((funbchannel->Hashtbl.replacecolor_tblchannelb;letppfs=channel.ppfsinList.iter(funppf->pp_set_mark_tagsppfb)ppfs),funchannel->matchHashtbl.findcolor_tblchannelwith|color_bool->color_bool|exceptionNot_found->false)letset_color,get_color=letv=reffalsein((funb->v:=b;List.iter(channel_set_colorb)channels),fun()->!v)letset_loggingsendchannel=matchsendwith|None->reset_channelchannel|Somef->letbuffer=Buffer.create2048inletout_stringstrstartlen=Buffer.add_substringbufferstrstartleninletflush()=letmsg=Buffer.contentsbufferinBuffer.resetbuffer;fmsginset_formatters[Format.make_formatterout_stringflush]channelendmoduletypeGROUP=sigincludeSmoduleSub(_:ChannelGroup):Swithtypechannel=channelendmoduleGroup(G:ChannelGroup):GROUP=structletloggers:(moduleSwithtypechannel=channel)Queue.t=Queue.create()letiter:((moduleSwithtypechannel=channel)->unit)->unit=funf->Queue.iterfloggersincludeMake(G)letset_warning_leveln=set_warning_leveln;iter(funlogger->letmoduleL=(vallogger)inL.set_warning_leveln)letset_info_leveln=set_info_leveln;iter(funlogger->letmoduleL=(vallogger)inL.set_info_leveln)letset_debug_leveln=set_debug_leveln;iter(funlogger->letmoduleL=(vallogger)inL.set_debug_leveln)letset_tagged_entryv=set_tagged_entryv;iter(funlogger->letmoduleL=(vallogger)inL.set_tagged_entryv)letset_log_levelt=set_log_levelt;iter(funlogger->letmoduleL=(vallogger)inL.set_log_levelt)letquiet()=quiet();iter(funlogger->letmoduleL=(vallogger)inL.quiet())letchannel_set_colorvc=channel_set_colorvc;iter(funlogger->letmoduleL=(vallogger)inL.channel_set_colorvc)letset_colorv=set_colorv;iter(funlogger->letmoduleL=(vallogger)inL.set_colorv)letset_loggingfc=set_loggingfc;iter(funlogger->letmoduleL=(vallogger)inL.set_loggingfc)moduleSub(G:ChannelGroup):Swithtypechannel=channel=structmoduleL=Make(G)includeLlet()=Queue.add(moduleL:Swithtypechannel=channel)loggersendend(* default printers *)