From d686ff151987010edd64263483ef1685420838ac Mon Sep 17 00:00:00 2001 From: Alain Mebsout Date: Mon, 16 Jun 2025 16:07:14 +0200 Subject: [PATCH 1/4] Octez_telemetry: add helper for tracing Resto callbacks --- manifest/product_octez.ml | 1 + src/lib_telemetry/HTTP_server.ml | 97 +++++++++++++++++++++++++++++++ src/lib_telemetry/HTTP_server.mli | 32 ++++++++++ src/lib_telemetry/dune | 3 +- 4 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 src/lib_telemetry/HTTP_server.ml create mode 100644 src/lib_telemetry/HTTP_server.mli diff --git a/manifest/product_octez.ml b/manifest/product_octez.ml index b804bea6aa70..d95d9a45e191 100644 --- a/manifest/product_octez.ml +++ b/manifest/product_octez.ml @@ -9235,6 +9235,7 @@ let octez_telemetry = opentelemetry_lwt; resto; octez_rpc_http; + octez_rpc_http_server; ] let _octez_scoru_wasm_regressions = diff --git a/src/lib_telemetry/HTTP_server.ml b/src/lib_telemetry/HTTP_server.ml new file mode 100644 index 000000000000..1361fd0ad37e --- /dev/null +++ b/src/lib_telemetry/HTTP_server.ml @@ -0,0 +1,97 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2025 Nomadic Labs *) +(* Copyright (c) 2025 Functori *) +(* *) +(*****************************************************************************) + +let attributes ~port ~meth io req () = + let uri = Cohttp.Request.uri req in + let scheme = + match Uri.scheme uri with None -> `None | Some scheme -> `String scheme + in + let host = + match Uri.host uri with None -> `None | Some host -> `String host + in + let path, query = + match String.split_on_char '?' (Uri.path_and_query uri) with + | [] -> ("", `None) + | [p] -> (p, `None) + | p :: q :: _ -> (p, `String q) + in + let transport, client_addr, peer_addr, peer_port = + match io with + | Conduit_lwt_unix.TCP {ip; port; _} -> + let ip = Ipaddr.to_string ip in + (`String "tcp", `String ip, `String ip, `Int port) + | Conduit_lwt_unix.Tunnel (t, _, _) -> + (`String "tunnel", `None, `String t, `None) + | Conduit_lwt_unix.Domain_socket {path; _} -> + (`String "unix socket", `None, `String path, `None) + | Conduit_lwt_unix.Vchan {domid; port} -> + ( `String "vchan", + `None, + `String (Format.sprintf "dom%d" domid), + `String port ) + in + let headers_attrs = + List.map + (fun (header, v) -> ("http.request.header." ^ header, `String v)) + (Cohttp.Header.to_list req.headers) + in + [ + ("http.request.method", `String meth); + ("url.scheme", scheme); + ("url.path", `String path); + ("url.query", query); + ("network.protocol.name", `String "http"); + ("server.port", `Int port); + ("client.address", client_addr); + ("network.peer.address", peer_addr); + ("network.peer.port", peer_port); + ( "network.protocol.version", + `String (Cohttp.Code.string_of_version req.version) ); + ("network.transport", transport); + ("server.address", host); + ] + @ headers_attrs + +let result_attributes scope action () = + match action with + | `Expert (resp, _) | `Response (resp, _) -> + let headers_attrs = + List.map + (fun (header, v) -> ("http.response.header." ^ header, `String v)) + (Cohttp.Header.to_list (Cohttp_lwt.Response.headers resp)) + in + let status = Cohttp_lwt.Response.status resp in + let status_code = Cohttp.Code.code_of_status status in + Opentelemetry.Scope.set_status + scope + (let code = + if status_code >= 300 then + Opentelemetry.Span_status.Status_code_error + else Status_code_ok + in + Opentelemetry.Span_status.make + ~message:(Cohttp.Code.string_of_status status) + ~code) ; + [("http.response.status_code", `Int status_code)] @ headers_attrs + +let resto_callback ~port server ((io, _conn) as iconn) (req : Cohttp.Request.t) + body = + let open Lwt_syntax in + let meth = Cohttp.Code.string_of_method req.meth in + let trace_name = String.concat " " [meth; req.resource] in + Opentelemetry_lwt.Trace.with_ + ~kind:Span_kind_server + ~service_name:"HTTP_server" + trace_name + @@ fun scope -> + Opentelemetry.Scope.add_attrs scope (attributes ~port ~meth io req) ; + let* action = + Tezos_rpc_http_server.RPC_server.resto_callback server iconn req body + in + Opentelemetry.Scope.add_attrs scope (result_attributes scope action) ; + return action diff --git a/src/lib_telemetry/HTTP_server.mli b/src/lib_telemetry/HTTP_server.mli new file mode 100644 index 000000000000..33907a6fe50e --- /dev/null +++ b/src/lib_telemetry/HTTP_server.mli @@ -0,0 +1,32 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2025 Nomadic Labs *) +(* Copyright (c) 2025 Functori *) +(* *) +(*****************************************************************************) + +(** Module providing OpenTelemetry tracing capabilities for Resto-based RPC + services. This allows for profiling of RPC requests and responses. *) + +(** [resto_callback ~port server conn request body] is a wrapper around the + standard Resto callback that adds OpenTelemetry tracing information to RPC + calls. + + This function intercepts RPC requests, creates spans with appropriate + attributes (method, path, status code), and measures the duration of request + processing. + + @param port The port number on which the RPC server is listening + @param server The Resto RPC server instance + @param conn The connection information from the HTTP server + @param request The HTTP request being processed + @param body The request body + @return The HTTP response action to be taken by the server *) +val resto_callback : + port:int -> + Tezos_rpc_http_server.RPC_server.server -> + Conduit_lwt_unix.flow * Cohttp.Connection.t -> + Cohttp.Request.t -> + Cohttp_lwt.Body.t -> + Cohttp_lwt_unix.Server.response_action Lwt.t diff --git a/src/lib_telemetry/dune b/src/lib_telemetry/dune index 6a49854fc37c..7168f14767b9 100644 --- a/src/lib_telemetry/dune +++ b/src/lib_telemetry/dune @@ -10,7 +10,8 @@ opentelemetry opentelemetry-lwt octez-libs.resto - octez-libs.rpc-http) + octez-libs.rpc-http + octez-libs.rpc-http-server) (flags (:standard) -open Tezos_base.TzPervasives -- GitLab From eeab55b525b06b2f7d32e8d425c6e1fb58c199cf Mon Sep 17 00:00:00 2001 From: Alain Mebsout Date: Sun, 15 Jun 2025 18:59:11 +0200 Subject: [PATCH 2/4] Rollup node: Opentelemetry traces for Resto server --- manifest/product_octez.ml | 33 ++++++++++--------- src/lib_smart_rollup_node/dune | 3 +- .../rpc_directory_helpers.ml | 18 ++-------- src/lib_smart_rollup_node/rpc_server.ml | 3 +- 4 files changed, 23 insertions(+), 34 deletions(-) diff --git a/manifest/product_octez.ml b/manifest/product_octez.ml index d95d9a45e191..63ae2dda8ea4 100644 --- a/manifest/product_octez.ml +++ b/manifest/product_octez.ml @@ -4515,6 +4515,22 @@ let _octez_rpc_http_server_tests = alcotezt; ] +let octez_telemetry = + octez_lib + "octez-telemetry" + ~internal_name:"Octez_telemetry" + ~path:"src/lib_telemetry" + ~synopsis:"Convenient wrappers to trace Octez libraries with Opentelemetry" + ~deps: + [ + octez_base |> open_ ~m:"TzPervasives" |> open_; + opentelemetry; + opentelemetry_lwt; + resto; + octez_rpc_http; + octez_rpc_http_server; + ] + let _bip39_generator = private_exe "bip39_generator" @@ -5551,6 +5567,7 @@ let octez_smart_rollup_node_lib = opentelemetry_lwt; opentelemetry_client_cohttp_lwt; opentelemetry_ambient_context_lwt; + octez_telemetry; ] let wasm_helpers_intf_modules = ["wasm_utils_intf"] @@ -9222,22 +9239,6 @@ let _octez_scoru_wasm_debugger = octez_scoru_wasm_debugger_lib |> open_; ] -let octez_telemetry = - octez_lib - "octez-telemetry" - ~internal_name:"Octez_telemetry" - ~path:"src/lib_telemetry" - ~synopsis:"Convenient wrappers to trace Octez libraries with Opentelemetry" - ~deps: - [ - octez_base |> open_ ~m:"TzPervasives" |> open_; - opentelemetry; - opentelemetry_lwt; - resto; - octez_rpc_http; - octez_rpc_http_server; - ] - let _octez_scoru_wasm_regressions = tezt ["tezos_scoru_wasm_regressions"] diff --git a/src/lib_smart_rollup_node/dune b/src/lib_smart_rollup_node/dune index c16a7c505a40..ed3a48c24cd2 100644 --- a/src/lib_smart_rollup_node/dune +++ b/src/lib_smart_rollup_node/dune @@ -50,7 +50,8 @@ octez-l2-libs.scoru-wasm-fast opentelemetry-lwt octez-libs.opentelemetry-client-cohttp-lwt - opentelemetry.ambient-context.lwt) + opentelemetry.ambient-context.lwt + octez-libs.octez-telemetry) (flags (:standard) -open Tezos_base.TzPervasives diff --git a/src/lib_smart_rollup_node/rpc_directory_helpers.ml b/src/lib_smart_rollup_node/rpc_directory_helpers.ml index 0e5faac135f4..4a28e12a5c0a 100644 --- a/src/lib_smart_rollup_node/rpc_directory_helpers.ml +++ b/src/lib_smart_rollup_node/rpc_directory_helpers.ml @@ -59,22 +59,8 @@ module Make_sub_directory (S : PARAM) = struct ~kind:Span_kind_server ~service_name trace_name - @@ fun scope -> - Opentelemetry.Scope.add_attrs scope (fun () -> - let req = Tezos_rpc.Service.forge_partial_request service a q in - let path, query = - match String.split_on_char '?' (Uri.path_and_query req.uri) with - | [] -> ("", `None) - | [p] -> (p, `None) - | p :: q :: _ -> (p, `String q) - in - [ - ("http.request.method", `String meth); - ("http.route", `String route); - ("url.path", `String path); - ("url.query", query); - ]) ; - f a q i + ~attrs:[("http.route", `String route)] + @@ fun _scope -> f a q i in directory := Tezos_rpc.Directory.register !directory service f diff --git a/src/lib_smart_rollup_node/rpc_server.ml b/src/lib_smart_rollup_node/rpc_server.ml index 75bb005108c4..4f7252fde229 100644 --- a/src/lib_smart_rollup_node/rpc_server.ml +++ b/src/lib_smart_rollup_node/rpc_server.ml @@ -83,7 +83,8 @@ let start ~rpc_addr ~rpc_port ~acl ~cors dir = RPC_server.launch ~host server - ~callback:(RPC_server.resto_callback server) + ~callback: + (Octez_telemetry.HTTP_server.resto_callback ~port:rpc_port server) node in return {server; host; node; acl} -- GitLab From f3673a4c40d8362724f13b341aa648d74385806e Mon Sep 17 00:00:00 2001 From: Alain Mebsout Date: Sun, 15 Jun 2025 19:38:09 +0200 Subject: [PATCH 3/4] EVM node: Opentelemetry traces for Resto server --- etherlink/bin_node/lib_dev/rpc_server.ml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/etherlink/bin_node/lib_dev/rpc_server.ml b/etherlink/bin_node/lib_dev/rpc_server.ml index 8b5e83c72c75..fc1d31dbae38 100644 --- a/etherlink/bin_node/lib_dev/rpc_server.ml +++ b/etherlink/bin_node/lib_dev/rpc_server.ml @@ -18,7 +18,7 @@ type evm_services_methods = { type block_production = [`Single_node | `Disabled] module Resto = struct - let callback server Evm_directory.{dir; extra} = + let callback ~port server Evm_directory.{dir; extra} = let open Cohttp in let open Lwt_syntax in let callback_log conn req body = @@ -31,7 +31,8 @@ module Resto = struct let meth = req |> Request.meth |> Code.string_of_method in let* body_str = body |> Cohttp_lwt.Body.to_string in let* () = Events.callback_log ~uri ~meth ~body:body_str in - Tezos_rpc_http_server.RPC_server.resto_callback + Octez_telemetry.HTTP_server.resto_callback + ~port server conn req @@ -89,7 +90,7 @@ module Resto = struct ~max_active_connections ~host server - ~callback:(callback server directory) + ~callback:(callback ~port server directory) ~conn_closed node in -- GitLab From 1b00efe037618d028fa804fe01fda3e0d49aa86e Mon Sep 17 00:00:00 2001 From: Alain Mebsout Date: Tue, 17 Jun 2025 14:56:35 +0200 Subject: [PATCH 4/4] Octez_telemetry: rename RPC_client to HTTP_client To better match the name of the service. --- etherlink/bin_node/lib_dev/rollup_services.ml | 2 +- src/lib_telemetry/{RPC_client.ml => HTTP_client.ml} | 0 src/lib_telemetry/{RPC_client.mli => HTTP_client.mli} | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename src/lib_telemetry/{RPC_client.ml => HTTP_client.ml} (100%) rename src/lib_telemetry/{RPC_client.mli => HTTP_client.mli} (100%) diff --git a/etherlink/bin_node/lib_dev/rollup_services.ml b/etherlink/bin_node/lib_dev/rollup_services.ml index 0a0a1c5f3df3..e326bdf8bb0a 100644 --- a/etherlink/bin_node/lib_dev/rollup_services.ml +++ b/etherlink/bin_node/lib_dev/rollup_services.ml @@ -281,7 +281,7 @@ let retry_connection (f : Uri.t -> 'a tzresult Lwt.t) endpoint : let call_service ~base ?(media_types = Media_type.all_media_types) rpc b c input = let open Lwt_result_syntax in - Octez_telemetry.RPC_client.trace_call ~media_types base rpc b c @@ fun _ -> + Octez_telemetry.HTTP_client.trace_call ~media_types base rpc b c @@ fun _ -> let*! res = Tezos_rpc_http_client_unix.RPC_client_unix.call_service media_types diff --git a/src/lib_telemetry/RPC_client.ml b/src/lib_telemetry/HTTP_client.ml similarity index 100% rename from src/lib_telemetry/RPC_client.ml rename to src/lib_telemetry/HTTP_client.ml diff --git a/src/lib_telemetry/RPC_client.mli b/src/lib_telemetry/HTTP_client.mli similarity index 100% rename from src/lib_telemetry/RPC_client.mli rename to src/lib_telemetry/HTTP_client.mli -- GitLab