123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2023 Nomadic Labs, <contact@nomadic-labs.com> *)(* *)(* Permission is hereby granted, free of charge, to any person obtaining a *)(* copy of this software and associated documentation files (the "Software"),*)(* to deal in the Software without restriction, including without limitation *)(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)(* and/or sell copies of the Software, and to permit persons to whom the *)(* Software is furnished to do so, subject to the following conditions: *)(* *)(* The above copyright notice and this permission notice shall be included *)(* in all copies or substantial portions of the Software. *)(* *)(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)(* DEALINGS IN THE SOFTWARE. *)(* *)(*****************************************************************************)openError_monadtypefacility=|Auth|Authpriv|Cron|Daemon|FTP|Kernel|Local0|Local1|Local2|Local3|Local4|Local5|Local6|Local7|LPR|Mail|News|Syslog|User|UUCP|NTP|Security|Consoleletlevel_code=function|Tezos_event_logging.Internal_event.Fatal->0|Error->3|Warning->4|Notice->5|Info->6|Debug->7letfacility_code=function|Kernel->0|User->1|Mail->2|Daemon->3|Auth->4|Syslog->5|LPR->6|News->7|UUCP->8|Cron->9|Authpriv->10|FTP->11|NTP->12|Security->13|Console->14|Local0->16|Local1->17|Local2->18|Local3->19|Local4->20|Local5->21|Local6->22|Local7->23letfacility_to_string=function|Auth->"auth"|Authpriv->"authpriv"|Cron->"cron"|Daemon->"daemon"|FTP->"ftp"|Kernel->"kernel"|Local0->"local0"|Local1->"local1"|Local2->"local2"|Local3->"local3"|Local4->"local4"|Local5->"local5"|Local6->"local6"|Local7->"local7"|LPR->"lpr"|Mail->"mail"|News->"news"|Syslog->"syslog"|User->"user"|UUCP->"uucp"|NTP->"ntp"|Security->"security"|Console->"console"letfacility_of_string_opt=function|"auth"->SomeAuth|"authpriv"->SomeAuthpriv|"cron"->SomeCron|"daemon"->SomeDaemon|"ftp"->SomeFTP|"kernel"->SomeKernel|"local0"->SomeLocal0|"local1"->SomeLocal1|"local2"->SomeLocal2|"local3"->SomeLocal3|"local4"->SomeLocal4|"local5"->SomeLocal5|"local6"->SomeLocal6|"local7"->SomeLocal7|"lpr"->SomeLPR|"mail"->SomeMail|"news"->SomeNews|"syslog"->SomeSyslog|"user"->SomeUser|"uucp"->SomeUUCP|"ntp"->SomeNTP|"security"->SomeSecurity|"console"->SomeConsole|_->NoneexceptionSyslog_errorofstringletshow_dateUnix.{tm_sec;tm_min;tm_hour;tm_mday;tm_mon;_}=letasc_mon=matchtm_monwith|0->"Jan"|1->"Feb"|2->"Mar"|3->"Apr"|4->"May"|5->"Jun"|6->"Jul"|7->"Aug"|8->"Sep"|9->"Oct"|10->"Nov"|11->"Dec"|_->Format.ksprintfStdlib.failwith"Lwt_log.date_string: invalid month, %d"tm_moninFormat.sprintf"%s %2d %02d:%02d:%02d"asc_montm_mdaytm_hourtm_mintm_secletopen_fdpath=letopenLwt_syntaxin(matchpathwith|""->raise(Syslog_error"unable to find the syslog socket or pipe")|_->());let*{st_kind;_}=Lwt_unix.statpathinmatchst_kindwith|Unix.S_SOCK->letlogaddr=Unix.ADDR_UNIXpathinletfd=tryLwt_unix.socket~cloexec:trueUnix.PF_UNIXSOCK_DGRAM0withUnix.Unix_error(Unix.EPROTOTYPE,_,_)->Lwt_unix.socket~cloexec:trueUnix.PF_UNIXSOCK_STREAM0inlet*()=Lwt.catch(fun()->Lwt_unix.connectfdlogaddr)(function|Unix.Unix_error(error,_,_)->let*()=Lwt_unix.closefdinraise(Syslog_error(Format.sprintf"can not connect to \"%s\": %s"path(Unix.error_messageerror)))|exn->raiseexn)inLwt.returnfd|Unix.S_FIFO->Lwt_unix.openfilepath[Unix.O_WRONLY;O_CLOEXEC]0o666|_->raise(Syslog_error"invalid log path, not a socket or pipe")(* Write the whole contents of a string on the given file
descriptor *)letwrite_stringfdstr=letopenLwt_syntaxinletlen=String.lengthstrinletrecauxstart_ofs=assert(start_ofs<=len);ifstart_ofs=lenthenLwt.return_unitelselet*n=Lwt_unix.write_stringfdstrstart_ofs(len-start_ofs)inifn<>0thenaux(start_ofs+n)elseLwt.return_unitinaux0letshutdownfd=Lwt_unix.shutdownfdUnix.SHUTDOWN_ALL;Lwt_unix.closefdtypet={mutablefd:Lwt_unix.file_descr;tag:string;facility:facility;with_pid:bool;path:string;}letcreate~tag?path?(with_pid=false)facility=letpath=matchpathwith|Somep->p|None->ifSys.file_exists"/dev/log"then"/dev/log"elseifSys.file_exists"/var/run/syslog"then"/var/run/syslog"else""inletopenLwt_syntaxinlet*fd=open_fdpathinLwt.return{fd;tag;facility;with_pid;path}letformat_message?(max_buflen=1024)?timestamp~tag~facility~with_pidlevelstr=(* For efficiency reason, the buffer is used both directy using
Buffer.add_* functions, and as a formatter. *)letmsg_buf=Buffer.create128inletmsg_fmt=Format.formatter_of_buffermsg_bufinletlevel_facility=(facility_codefacilitylsl3)lorlevel_codelevelinlettimestamp=matchtimestampwithNone->Unix.time()|Somet->tinletnow=show_dateUnix.(localtimetimestamp)inFormat.fprintfmsg_fmt"<%d>%s @?"level_facilitynow;ifString.lengthtag>32thenBuffer.add_substringmsg_buftag032elseBuffer.add_stringmsg_buftag;ifwith_pidthenFormat.fprintfmsg_fmt"[%d]@?"(Unix.getpid());Buffer.add_stringmsg_buf": ";letbuf_len=Buffer.lengthmsg_bufinifbuf_len+String.lengthstr>max_buflenthen(letblit_len=max_buflen-3-buf_leninBuffer.add_substringmsg_bufstr0blit_len;Buffer.add_stringmsg_buf"...")elseBuffer.add_stringmsg_bufstr;Buffer.contentsmsg_bufletsyslog?max_buflen?timestamploggerlevelstr=letopenLwt_syntaxinletmsg=format_message?timestamp?max_buflen~tag:logger.tag~facility:logger.facility~with_pid:logger.with_pidlevelstrinLwt.catch(fun()->write_stringlogger.fdmsg)(function|Unix.Unix_error(_,_,_)->let*()=shutdownlogger.fdinlet*fd=open_fdlogger.pathinlogger.fd<-fd;write_stringlogger.fdmsg|exn->raiseexn)letcloselogger=shutdownlogger.fd