123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188(*
* Copyright (C) Citrix Systems Inc.
*
* 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; version 2.1 only. with the special
* exception on linking described in file LICENSE.
*
* 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.
*)openLwtopenPrintftypelogger={stream:stringLwt_stream.t;push:string->unit;elements:intref;max_elements:int;dropped_elements:intref;}letcreatemax_elements=letelements=ref(ref0)inletdropped_elements=ref(ref0)inletstream,stream_push=Lwt_stream.create()inletpushline=if!(!elements)>max_elementsthenbeginincr!dropped_elementsendelsebeginstream_push(Someline);incr!elementsendin{stream=stream;push=push;elements=!elements;max_elements=max_elements;dropped_elements=!dropped_elements;}letget(logger:logger)=letreturn_linesall=logger.elements:=!(logger.elements)-(List.lengthall);letdropped=!(logger.dropped_elements)inlogger.dropped_elements:=0;return(ifdropped<>0thenPrintf.sprintf"<-- dropped %d log lines"dropped::allelseall)in(* Grab as many elements as we can without blocking *)letall=Lwt_stream.get_availablelogger.streaminifall<>[]thenreturn_linesallelsebegin(* Block for at least one line *)Lwt_stream.nget1logger.stream>>=funall->return_linesallend(* General system logging *)letlogger=create512(* Operation logging *)letaccess_logger=create512typelevel=Debug|Info|Warn|Error|Nullletlog_level=refWarnletint_of_level=function|Debug->0|Info->1|Warn->2|Error->3|Null->max_intletstring_of_level=function|Debug->"debug"|Info->"info"|Warn->"warn"|Error->"error"|Null->"null"letloglevelkey(fmt:(_,_,_,_)format4)=letlevel=string_of_levellevelinPrintf.ksprintflogger.push("[%5s|%s] "^^fmt)levelkeyletdebugkey=logDebugkeyletinfokey=logInfokeyletwarnkey=logWarnkeyleterrorkey=logErrorkey(* Access logger *)typeaccess_type=|Coalesce|Conflict|Commit|Newconn|Endconn|Debugofstring|Start_transaction|End_transaction|RequestofXs_protocol.Request.payload|ResponseofXs_protocol.Response.payload*stringoptionletstring_of_tid~contid=iftid=0lthensprintf"%-12s"conelsesprintf"%-12s"(sprintf"%s.%li"contid)letstring_of_access_type=function|Coalesce->"coalesce "|Conflict->"conflict "|Commit->"commit "|Newconn->"newconn "|Endconn->"endconn "|Debugx->" "^x|Start_transaction->"t start "|End_transaction->"t end "|Requestr->" <- in "^(Xs_protocol.Request.prettyprint_payloadr)|Response(r,info_opt)->" -> out "^(Xs_protocol.Response.prettyprint_payloadr)^(matchinfo_optwithSomex->" ("^x^")"|None->"")letdisable_coalesce=reffalseletdisable_conflict=reffalseletdisable_commit=reffalseletdisable_newconn=reffalseletdisable_endconn=reffalseletdisable_transaction=reffalseletdisable_request=ref["read"]letdisable_reply_ok=ref["read";"directory";"getperms";"watch";"unwatch";"transaction_start";"transaction_end";"introduce";"release";"getdomainpath";"write";"mkdir";"rm";"setperms";(* "watchevent"; *)"isintroduced";"resume";"set_target";"restrict"]letdisable_reply_err=ref["read"]letaccess_type_disabled=function|Coalesce->!disable_coalesce|Conflict->!disable_conflict|Commit->!disable_commit|Newconn->!disable_newconn|Endconn->!disable_endconn|Debug_->false|Start_transaction|End_transaction->!disable_transaction|Requestr->List.mem(Xs_protocol.(Op.to_string(Request.ty_of_payloadr)))!disable_request|Response(r,_)->beginmatchrwith|Xs_protocol.Response.Errorx->List.memx!disable_reply_err|_->letty=Xs_protocol.Response.ty_of_payloadrinList.mem(Xs_protocol.Op.to_stringty)!disable_reply_okendletaccess_type_enabledx=not(access_type_disabledx)letsanitize_datadata=letdata=Bytes.of_stringdatainfori=0toBytes.lengthdata-1doifBytes.getdatai='\000'thenBytes.setdatai' 'done;String.escaped(Bytes.to_stringdata)letaccess_logging~con~tid?(data="")access_type=ifaccess_type_enabledaccess_typethenbeginlettid=string_of_tid~contidinletaccess_type=string_of_access_typeaccess_typeinletdata=sanitize_datadatainPrintf.ksprintflogger.push"%s %s %s"tidaccess_typedataendletnew_connection=access_loggingNewconnletend_connection=access_loggingEndconnletread_coalesce~tid~condata=access_loggingCoalesce~tid~con~data:("read "^data)letwrite_coalescedata=access_loggingCoalesce~data:("write "^data)letconflict=access_loggingConflictletcommit=access_loggingCommitletrequest~tid~conrequest=access_logging~tid~con(Requestrequest)letresponse~tid~con?inforesponse=access_logging~tid~con(Response(response,info))letdebug_print~tid~conx=access_logging~tid~con(Debugx)letstart_transaction~tid~con=access_logging~tid~con(Start_transaction)letend_transaction~tid~con=access_logging~tid~con(End_transaction)