123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289(**************************************************************************)(* *)(* This file is part of Frama-C. *)(* *)(* Copyright (C) 2007-2023 *)(* 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). *)(* *)(**************************************************************************)openDatamoduleMd=MarkdownmodulePkg=PackagemoduleSenv=Server_parameters(* -------------------------------------------------------------------------- *)(* --- Frama-C Kernel Services --- *)(* -------------------------------------------------------------------------- *)letpackage=Pkg.package~name:"services"~title:"Kernel Services"~readme:"kernel.md"()(* -------------------------------------------------------------------------- *)(* --- Config --- *)(* -------------------------------------------------------------------------- *)let()=letsignature=Request.signature~input:(moduleJunit)()inletresultnamedescr=Request.resultsignature~name~descr:(Md.plaindescr)(moduleJstring)inletresult_listnamedescr=Request.resultsignature~name~descr:(Md.plaindescr)(moduleJlist(Jstring))inletset_version=result"version""Frama-C version"inletset_datadir=result_list"datadir""Shared directory (FRAMAC_SHARE)"inletset_pluginpath=result_list"pluginpath""Plugin directories (FRAMAC_PLUGIN)"inRequest.register_sig~package~kind:`GET~name:"getConfig"~descr:(Md.plain"Frama-C Kernel configuration")signaturebeginfunrq()->set_versionrqFc_config.version;set_datadirrq(Filepath.Normalized.to_string_listFc_config.datadirs);set_pluginpathrq(Filepath.Normalized.to_string_listFc_config.plugin_dir);end(* -------------------------------------------------------------------------- *)(* --- Load saves --- *)(* -------------------------------------------------------------------------- *)let()=Request.register~package~kind:`SET~name:"load"~descr:(Md.plain"Load a save file. Returns an error, if not successfull.")~input:(moduleJstring)~output:(moduleJoption(Jstring))(funfile->tryProject.load_all(Filepath.Normalized.of_stringfile);NonewithProject.IOErrorerr->Someerr)let()=Request.register~package~kind:`SET~name:"save"~descr:(Md.plain"Save the current session. Returns an error, if not successfull.")~input:(moduleJstring)~output:(moduleJoption(Jstring))(funfile->tryProject.save_all(Filepath.Normalized.of_stringfile);NonewithProject.IOErrorerr->Someerr)(* -------------------------------------------------------------------------- *)(* --- Log Lind --- *)(* -------------------------------------------------------------------------- *)moduleLogKind=structletkinds=Enum.dictionary()lett_kindvaluenamedescr=Enum.tag~name~descr:(Md.plaindescr)~valuekindslett_error=t_kindLog.Error"ERROR""User Error"lett_warning=t_kindLog.Warning"WARNING""User Warning"lett_feedback=t_kindLog.Feedback"FEEDBACK""Plugin Feedback"lett_result=t_kindLog.Result"RESULT""Plugin Result"lett_failure=t_kindLog.Failure"FAILURE""Plugin Failure"lett_debug=t_kindLog.Debug"DEBUG""Analyser Debug"let()=Enum.set_lookupkindsbeginfunction|Log.Error->t_error|Log.Warning->t_warning|Log.Feedback->t_feedback|Log.Result->t_result|Log.Failure->t_failure|Log.Debug->t_debugendletdata=Request.dictionary~package~name:"logkind"~descr:(Md.plain"Log messages categories.")kindsinclude(valdata:Swithtypet=Log.kind)end(* -------------------------------------------------------------------------- *)(* --- Synchronized array of log events --- *)(* -------------------------------------------------------------------------- *)letmodel=States.model()let()=States.columnmodel~name:"kind"~descr:(Md.plain"Message kind")~data:(moduleLogKind)~get:(fun(evt,_)->evt.Log.evt_kind)let()=States.columnmodel~name:"plugin"~descr:(Md.plain"Emitter plugin")~data:(moduleJalpha)~get:(fun(evt,_)->evt.Log.evt_plugin)let()=States.columnmodel~name:"message"~descr:(Md.plain"Message text")~data:(moduleJstring)~get:(fun(evt,_)->evt.Log.evt_message)let()=States.optionmodel~name:"category"~descr:(Md.plain"Message category (only for debug or warning messages)")~data:(moduleJstring)~get:(fun(evt,_)->evt.Log.evt_category)let()=States.optionmodel~name:"source"~descr:(Md.plain"Source file position")~data:(moduleKernel_ast.Position)~get:(fun(evt,_)->evt.Log.evt_source)letgetMarker(evt,_id)=Option.bindevt.Log.evt_sourcePrinter_tag.loc_to_localizableletgetFunctiont=Option.bind(getMarkert)Printer_tag.kf_of_localizablelet()=States.optionmodel~name:"marker"~descr:(Md.plain"Marker at the message position (if any)")~data:(moduleKernel_ast.Marker)~get:getMarkerlet()=States.optionmodel~name:"fct"~descr:(Md.plain"Function containing the message position (if any)")~data:(moduleKernel_ast.Function)~get:getFunctionletiterf=ignore(Messages.fold(funievt->f(evt,i);succi)0)let_array=States.register_array~package~name:"message"~descr:(Md.plain"Log messages")~key:(fun(_evt,i)->string_of_inti)~iter:iter~add_reload_hook:Messages.add_global_hookmodel(* -------------------------------------------------------------------------- *)(* --- Log Events --- *)(* -------------------------------------------------------------------------- *)moduleLogEvent=structtyperlogletjlog:rlogRecord.signature=Record.signature()letkind=Record.fieldjlog~name:"kind"~descr:(Md.plain"Message kind")(moduleLogKind)letplugin=Record.fieldjlog~name:"plugin"~descr:(Md.plain"Emitter plugin")(moduleJalpha)letmessage=Record.fieldjlog~name:"message"~descr:(Md.plain"Message text")(moduleJstring)letcategory=Record.optionjlog~name:"category"~descr:(Md.plain"Message category (DEBUG or WARNING)")(moduleJstring)letsource=Record.optionjlog~name:"source"~descr:(Md.plain"Source file position")(moduleKernel_ast.Position)letdata=Record.publish~package~name:"log"~descr:(Md.plain"Message event record.")jlogmoduleR:Record.Swithtyper=rlog=(valdata)typet=Log.eventletjtype=R.jtypeletto_jsonevt=R.default|>R.setpluginevt.Log.evt_plugin|>R.setkindevt.Log.evt_kind|>R.setcategoryevt.Log.evt_category|>R.setsourceevt.Log.evt_source|>R.setmessageevt.Log.evt_message|>R.to_jsonletof_jsonjs=letr=R.of_jsonjsin{Log.evt_plugin=R.getpluginr;Log.evt_kind=R.getkindr;Log.evt_category=R.getcategoryr;Log.evt_source=R.getsourcer;Log.evt_message=R.getmessager;}end(* -------------------------------------------------------------------------- *)(* --- Log Monitoring --- *)(* -------------------------------------------------------------------------- *)letmonitoring=reffalseletmonitored=reffalseletevents:Log.eventQueue.t=Queue.create()letset_monitoringflag=ifflag!=!monitoringthenmonitoring:=flag;if!monitoring&¬!monitoredthenbeginmonitored:=true;Log.add_listener(funevt->if!monitoringthenQueue.addevtevents)endletmonitor_serveractivity=ifnot(Senv.AutoLog.get())thenset_monitoringactivityletmonitor_autologs()=ifSenv.AutoLog.get()thenbeginSenv.feedback"Auto-log started.";set_monitoringtrue;endlet()=Main.onmonitor_server;Cmdline.run_after_configuring_stagemonitor_autologs(* -------------------------------------------------------------------------- *)(* --- Log Requests --- *)(* -------------------------------------------------------------------------- *)(* TODO:LC: shall have an array here. *)let()=Request.register~package~kind:`SET~name:"setLogs"~descr:(Md.plain"Turn logs monitoring on/off")~input:(moduleJbool)~output:(moduleJunit)set_monitoringlet()=Request.register~package~kind:`GET~name:"getLogs"~descr:(Md.plain"Flush the last emitted logs since last call (max 100)")~input:(moduleJunit)~output:(moduleJlist(LogEvent))beginfun()->letpool=ref[]inletcount=ref100inwhilenot(Queue.is_emptyevents)&&!count>0dodecrcount;pool:=Queue.popevents::!pooldone;List.rev!poolend(* -------------------------------------------------------------------------- *)