123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2022 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. *)(* *)(*****************************************************************************)openPrometheusletsc_rollup_node_registry=CollectorRegistry.create()letnamespace=Tezos_version.Node_version.namespaceletsubsystem="sc_rollup_node"(** Registers a labeled counter in [sc_rollup_node_registry] *)letv_labels_counter=Counter.v_labels~registry:sc_rollup_node_registry~namespace~subsystem(** Registers a gauge in [sc_rollup_node_registry] *)letv_gauge=Gauge.v~registry:sc_rollup_node_registry~namespace~subsystem(** Creates a metric with a given [collector] *)letmetric~help~namecollector=letinfo={MetricInfo.name=MetricName.v(String.concat"_"[namespace;subsystem;name]);help;metric_type=Gauge;label_names=[];}inletcollect()=LabelSetMap.singleton[][Prometheus.Sample_set.sample(collector())]in(info,collect)(** Registers a metric defined with [info] associated to its [collector] *)letadd_metric(info,collector)=CollectorRegistry.(registersc_rollup_node_registry)infocollectormoduleCohttp(Server:Cohttp_lwt.S.Server)=structletcallback_connreq_body=letopenCohttpinletopenLwt_syntaxinleturi=Request.urireqinmatch(Request.methreq,Uri.pathuri)with|`GET,"/metrics"->let*data=CollectorRegistry.(collectsc_rollup_node_registry)inletbody=Fmt.to_to_stringPrometheus_app.TextFormat_0_0_4.outputdatainletheaders=Header.init_with"Content-Type""text/plain; version=0.0.4"inServer.respond_string~status:`OK~headers~body()|_->Server.respond_error~status:`Bad_request~body:"Bad request"()endmoduleMetrics_server=Cohttp(Cohttp_lwt_unix.Server)letmetrics_servemetrics_addr=letopenLwt_result_syntaxinmatchmetrics_addrwith|Somemetrics_addr->let*addrs=Octez_node_config.Config_file.resolve_metrics_addrs~default_metrics_port:Configuration.default_metrics_portmetrics_addrinlet*!()=List.iter_p(fun(addr,port)->lethost=Ipaddr.V6.to_stringaddrinlet*!()=Node_events.starting_metrics_server~host~portinlet*!ctx=Conduit_lwt_unix.init~src:host()inletctx=Cohttp_lwt_unix.Net.init~ctx()inletmode=`TCP(`Portport)inletcallback=Metrics_server.callbackinCohttp_lwt_unix.Server.create~ctx~mode(Cohttp_lwt_unix.Server.make~callback()))addrsinreturn_unit|None->return_unitletmetric_type_to_string=function|Counter->"Counter"|Gauge->"Gauge"|Summary->"Summary"|Histogram->"Histogram"letpp_label_namesfmt=Format.pp_print_list~pp_sep:(funfmt()->Format.fprintffmt";")(funfmtv->Format.fprintffmt"%a"LabelName.ppv)fmtletprint_csv_metricsppfmetrics=letopenPrometheusinFormat.fprintfppf"@[<v>Name,Type,Description,Labels";List.iter(fun(v,_)->Format.fprintfppf"@,@[%a@],%s,\"%s\",%a"MetricName.ppv.MetricInfo.name(metric_type_to_stringv.MetricInfo.metric_type)v.MetricInfo.helppp_label_namesv.MetricInfo.label_names)(Prometheus.MetricFamilyMap.to_listmetrics);Format.fprintfppf"@]@."moduleInfo=structopenTezos_versionletnode_general_info=v_labels_counter~help:"General information on the node"~label_names:["version";"commit_hash";"commit_date"]"node_info"letrollup_node_info=lethelp="Rollup node info"inv_labels_counter~help~label_names:["rollup_address";"mode";"genesis_level";"pvm_kind"]"rollup_node_info"letinit_rollup_node_info~id~mode~genesis_level~pvm_kind=letid=Tezos_crypto.Hashed.Smart_rollup_address.to_b58checkidinletmode=Configuration.string_of_modemodeinletgenesis_level=Int32.to_stringgenesis_levelinignore@@Counter.labelsrollup_node_info[id;mode;genesis_level;pvm_kind];()let()=letversion=Version.to_stringCurrent_git_info.versioninletcommit_hash=Current_git_info.commit_hashinletcommit_date=Current_git_info.committer_dateinlet_=Counter.labelsnode_general_info[version;commit_hash;commit_date]in()endmoduleInbox=structtypet={head_inbox_level:Gauge.t}moduleStats=structletinternal_messages_number=ref0.letexternal_messages_number=ref0.letzero()=internal_messages_number:=0.;external_messages_number:=0.letset~is_internall=zero();List.iter(funx->letr=ifis_internalxtheninternal_messages_numberelseexternal_messages_numberinr:=!r+.1.)lendletmetrics=lethead_inbox_level=v_gauge~help:"The level of the last inbox""head_inbox_level"inlethead_internal_messages_number=metric~help:"The number of internal messages in head's inbox"~name:"head_inbox_internal_messages_number"(fun()->!Stats.internal_messages_number)inlethead_external_messages_number=metric~help:"The number of external messages in head's inbox"~name:"head_inbox_external_messages_number"(fun()->!Stats.external_messages_number)inList.iteradd_metric[head_internal_messages_number;head_external_messages_number];{head_inbox_level}end