Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file lwt_log_core.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374(* OCaml promise library
* http://www.ocsigen.org/lwt
* Copyright (C) 2002 Shawn Wagner <raevnos@pennmush.org>
* 2009 Jérémie Dimino <jeremie@dimino.org>
*
* This program is free software; 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, with linking exceptions;
* either version 2.1 of the License, or (at your option) any later
* version. See COPYING file for details.
*
* This program 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.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*)(* This code is an adaptation of [syslog-ocaml] *)(* Errors happening in this module are always logged to [stderr]: *)letlog_internfmt=Printf.eprintf("Lwt_log: "^^fmt^^"\n%!")(* +-----------------------------------------------------------------+
| Log levels |
+-----------------------------------------------------------------+ *)typelevel=|Debug|Info|Notice|Warning|Error|Fatalletstring_of_level=function|Debug->"debug"|Info->"info"|Notice->"notice"|Warning->"warning"|Error->"error"|Fatal->"fatal"letlevel_of_stringstr=letstr=String.lowercase_asciistrinmatchstrwith|"debug"->SomeDebug|"info"->SomeInfo|"notice"->SomeNotice|"warning"->SomeWarning|"error"->SomeError|"fatal"->SomeFatal|_->None(* +-----------------------------------------------------------------+
| Patterns and rules |
+-----------------------------------------------------------------+ *)(* A pattern is represented by a list of literals:
For example ["foo*bar*"] is represented by ["foo"; "bar"; ""]. *)letsub_equalstrofspatt=letstr_len=String.lengthstrandpatt_len=String.lengthpattinletrecloopofsofs_patt=ofs_patt=patt_len||(str.[ofs]=patt.[ofs_patt]&&loop(ofs+1)(ofs_patt+1))inofs+patt_len<=str_len&&loopofs0letpattern_matchpatternstring=letlength=String.lengthstringinletrecloopoffsetpattern=ifoffset=lengththenpattern=[]||pattern=[""]elsematchpatternwith|[]->false|literal::pattern->letliteral_length=String.lengthliteralinletmax_offset=length-literal_lengthinletrecsearchoffset=offset<=max_offset&&((sub_equalstringoffsetliteral&&loop(offset+literal_length)pattern)||search(offset+1))insearchoffsetinmatchpatternwith|[]->string=""|literal::pattern->sub_equalstring0literal&&loop(String.lengthliteral)patternletsplitpattern=letlen=String.lengthpatterninletrecloopofs=ifofs=lenthen[""]elsematchtrySome(String.index_frompatternofs'*')withNot_found->Nonewith|Someofs'->String.subpatternofs(ofs'-ofs)::loop(ofs'+1)|None->[String.subpatternofs(len-ofs)]inloop0letrules=ref[]letload_rules'strfail_on_error=letrecloop=function|[]->[]|(pattern,level_str)::rest->letpattern=splitpatterninletlevel=level_of_stringlevel_strinmatchlevelwith|Somelevel->(pattern,level)::looprest|None->iffail_on_errorthenraise(Failure"Invalid log rules")elselog_intern"invalid log level (%s)"level_str;looprestinmatchLwt_log_rules.rules(Lexing.from_stringstr)with|None->iffail_on_errorthenraise(Failure"Invalid log rules")elsePrintf.eprintf"Invalid log rules\n%!"|Somel->rules:=loopllet_=matchtrySome(Sys.getenv"LWT_LOG")withNot_found->Nonewith|Somestr->load_rules'strfalse|None->()(* +-----------------------------------------------------------------+
| Sections |
+-----------------------------------------------------------------+ *)moduleSection=structtypet={name:string;mutablelevel:level;mutablemodified:bool;}typesection=tmoduleSections=Weak.Make(structtypet=sectionletequalab=a.name=b.namelethashs=Hashtbl.hashs.nameend)letsections=Sections.create32letfind_levelname=letrecloop=function|[]->Notice|(pattern,level)::rest->ifpattern_matchpatternnamethenlevelelselooprestinloop!rulesletrecompute_levels()=Sections.iter(funsection->ifnotsection.modifiedthensection.level<-find_levelsection.name)sectionsletmakename=letsection={name=name;level=Notice;modified=false}intrySections.findsectionssectionwithNot_found->section.level<-find_levelname;Sections.addsectionssection;sectionletnamesection=section.nameletmain=make"main"letlevelsection=section.levelletset_levelsectionlevel=section.level<-level;section.modified<-trueletreset_levelsection=ifsection.modifiedthenbeginsection.modified<-false;section.level<-find_levelsection.nameendendtypesection=Section.tletload_rules?(fail_on_error=false)str=load_rules'strfail_on_error;Section.recompute_levels()letadd_rulepatternlevel=rules:=(splitpattern,level)::!rules;Section.recompute_levels()letappend_rulepatternlevel=rules:=!rules@[(splitpattern,level)];Section.recompute_levels()letreset_rules()=rules:=[];Section.recompute_levels()(* +-----------------------------------------------------------------+
| Loggers |
+-----------------------------------------------------------------+ *)exceptionLogger_closedtypelogger={mutablelg_closed:bool;lg_output:section->level->stringlist->unitLwt.t;lg_close:unitLwt.tLazy.t;}letcloselogger=logger.lg_closed<-true;Lazy.forcelogger.lg_closeletmake~output~close={lg_closed=false;lg_output=output;lg_close=Lazy.from_funclose;}letbroadcastloggers=make~output:(funsectionlevellines->Lwt_list.iter_p(funlogger->logger.lg_outputsectionlevellines)loggers)~close:Lwt.returnletdispatchf=make~output:(funsectionlevellines->(fsectionlevel).lg_outputsectionlevellines)~close:Lwt.return(* +-----------------------------------------------------------------+
| Templates |
+-----------------------------------------------------------------+ *)typetemplate=stringletlocation_key=Lwt.new_key()letrender~buffer~template~section~level~message=letfile,line,column=matchLwt.getlocation_keywith|Someloc->loc|None->("<unknown>",-1,-1)inBuffer.add_substitutebuffer(function|"message"->message|"level"->string_of_levellevel|"section"->Section.namesection|"loc-file"->file|"loc-line"->string_of_intline|"loc-column"->string_of_intcolumn|var->Printf.ksprintfinvalid_arg"Lwt_log_core.render: unknown variable %S"var)template(* +-----------------------------------------------------------------+
| Predefined loggers |
+-----------------------------------------------------------------+ *)letnull=make~output:(fun_section_level_lines->Lwt.return_unit)~close:Lwt.returnletdefault=refnull(* +-----------------------------------------------------------------+
| Logging functions |
+-----------------------------------------------------------------+ *)(* knicked from stdlib/string.ml; available since 4.04.0 *)letsplit_on_charseps=letr=ref[]inletj=ref(String.lengths)infori=String.lengths-1downto0doifString.unsafe_getsi=septhenbeginr:=String.subs(i+1)(!j-i-1)::!r;j:=ienddone;String.subs0!j::!rletsplitstr=split_on_char'\n'strletlog?exn?(section=Section.main)?location?logger~levelmessage=letlogger=matchloggerwith|None->!default|Somelogger->loggeriniflogger.lg_closedthenLwt.failLogger_closedelseiflevel>=section.Section.levelthenmatchexnwith|None->Lwt.with_valuelocation_keylocation(fun()->logger.lg_outputsectionlevel(splitmessage))|Someexn->letbt=ifPrintexc.backtrace_status()thenPrintexc.get_backtrace()else""inletmessage=message^": "^Printexc.to_stringexninletmessage=ifString.lengthbt=0thenmessageelsemessage^"\nbacktrace:\n"^btinLwt.with_valuelocation_keylocation(fun()->logger.lg_outputsectionlevel(splitmessage))elseLwt.return_unitletlog_f?exn?section?location?logger~levelformat=Printf.ksprintf(log?exn?section?location?logger~level)formatletign_log?exn?section?location?logger~levelmessage=tryignore(log?exn?section?location?logger~levelmessage)with_->()letign_log_f?exn?section?location?logger~levelformat=Printf.ksprintf(ign_log?exn?section?location?logger~level)formatletdebug?exn?section?location?loggermsg=log?exn?section?location?logger~level:Debugmsgletdebug_f?exn?section?location?loggerfmt=Printf.ksprintf(debug?exn?section?location?logger)fmtletinfo?exn?section?location?loggermsg=log?exn?section?location?logger~level:Infomsgletinfo_f?exn?section?location?loggerfmt=Printf.ksprintf(info?exn?section?location?logger)fmtletnotice?exn?section?location?loggermsg=log?exn?section?location?logger~level:Noticemsgletnotice_f?exn?section?location?loggerfmt=Printf.ksprintf(notice?exn?section?location?logger)fmtletwarning?exn?section?location?loggermsg=log?exn?section?location?logger~level:Warningmsgletwarning_f?exn?section?location?loggerfmt=Printf.ksprintf(warning?exn?section?location?logger)fmtleterror?exn?section?location?loggermsg=log?exn?section?location?logger~level:Errormsgleterror_f?exn?section?location?loggerfmt=Printf.ksprintf(error?exn?section?location?logger)fmtletfatal?exn?section?location?loggermsg=log?exn?section?location?logger~level:Fatalmsgletfatal_f?exn?section?location?loggerfmt=Printf.ksprintf(fatal?exn?section?location?logger)fmtletign_debug?exn?section?location?loggermsg=ign_log?exn?section?location?logger~level:Debugmsgletign_debug_f?exn?section?location?loggerfmt=Printf.ksprintf(ign_debug?exn?section?location?logger)fmtletign_info?exn?section?location?loggermsg=ign_log?exn?section?location?logger~level:Infomsgletign_info_f?exn?section?location?loggerfmt=Printf.ksprintf(ign_info?exn?section?location?logger)fmtletign_notice?exn?section?location?loggermsg=ign_log?exn?section?location?logger~level:Noticemsgletign_notice_f?exn?section?location?loggerfmt=Printf.ksprintf(ign_notice?exn?section?location?logger)fmtletign_warning?exn?section?location?loggermsg=ign_log?exn?section?location?logger~level:Warningmsgletign_warning_f?exn?section?location?loggerfmt=Printf.ksprintf(ign_warning?exn?section?location?logger)fmtletign_error?exn?section?location?loggermsg=ign_log?exn?section?location?logger~level:Errormsgletign_error_f?exn?section?location?loggerfmt=Printf.ksprintf(ign_error?exn?section?location?logger)fmtletign_fatal?exn?section?location?loggermsg=ign_log?exn?section?location?logger~level:Fatalmsgletign_fatal_f?exn?section?location?loggerfmt=Printf.ksprintf(ign_fatal?exn?section?location?logger)fmt