• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MinaProtocol / mina / 1612

21 Oct 2024 08:28AM UTC coverage: 61.111% (+0.02%) from 61.093%
1612

push

buildkite

web-flow
Merge pull request #16255 from MinaProtocol/release/3.0.2

682 of 1335 new or added lines in 129 files covered. (51.09%)

148 existing lines in 47 files now uncovered.

47180 of 77204 relevant lines covered (61.11%)

555482.14 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

2.82
/src/lib/node_error_service/node_error_service.ml
1
open Async
8✔
2
open Core
3
open Signature_lib
4

5
(* needs to be kept in sync with the constant in minaprotocol/mina-deployments:src/node-status-error-system-backend/node_error/src/index.js *)
6
let max_report_bytes = 10_000
7

8
type node_state =
9
  { peer_id : string
10
  ; ip_address : string
11
  ; chain_id : string
12
  ; public_key : Public_key.Compressed.t option
13
  ; catchup_job_states : Transition_frontier.Full_catchup_tree.job_states option
14
  ; block_height_at_best_tip : int option
15
  ; sync_status : Sync_status.t
16
  ; hardware_info : string list option
17
  ; uptime_of_node : string
18
  }
19

20
type node_error_report =
×
21
  { version : int
×
22
  ; peer_id : string
×
23
  ; ip_address : string
×
24
  ; public_key : Public_key.Compressed.t option
×
25
  ; commit_hash : string
×
26
  ; chain_id : string
×
27
  ; contact_info : string option
×
28
  ; hardware_info : string list option
×
29
  ; timestamp : string
×
30
  ; id : string
×
31
  ; error : Yojson.Safe.t
×
32
  ; catchup_job_states : Transition_frontier.Full_catchup_tree.job_states option
×
33
  ; sync_status : Sync_status.t
×
34
  ; block_height_at_best_tip : int option
×
35
  ; max_observed_block_height : int
×
36
  ; max_observed_unvalidated_block_height : int
×
37
  ; uptime_of_node : string
×
38
  }
39
[@@deriving to_yojson]
40

41
type config =
42
  { get_node_state : unit -> node_state option Deferred.t
43
  ; node_error_url : Uri.t
44
  ; contact_info : string option
45
  }
46

47
let config = ref None
48

49
let set_config ~get_node_state ~node_error_url ~contact_info =
50
  if Option.is_some !config then
×
51
    failwith "Node_error_service.set_config called more than once"
×
52
  else config := Some { get_node_state; node_error_url; contact_info }
×
53

54
let serialize_report report =
55
  `Assoc [ ("data", node_error_report_to_yojson report) ]
×
56

57
let send_node_error_report ~logger ~url report =
58
  let json = serialize_report report in
×
59
  let json_string = Yojson.Safe.to_string json in
×
60
  (* TODO: move length check to to send_node_error_data *)
61
  if String.length json_string > max_report_bytes then (
×
62
    [%log error]
×
63
      "Could not send error report because generated error exceeded max report \
64
       size" ;
65
    Deferred.unit )
×
66
  else
67
    let headers =
×
68
      Cohttp.Header.of_list [ ("Content-Type", "application/json") ]
69
    in
70
    match%map
71
      Async.try_with ~here:[%here] (fun () ->
×
72
          Cohttp_async.Client.post ~headers
×
73
            ~body:(Cohttp_async.Body.of_string json_string)
×
74
            url )
75
    with
76
    | Ok ({ status; _ }, body) ->
×
77
        let metadata =
78
          [ ("data", json); ("url", `String (Uri.to_string url)) ]
×
79
        in
80
        if Cohttp.Code.code_of_status status = 200 then
×
81
          [%log info] "Sent node error data to URL $url" ~metadata
×
82
        else
83
          let extra_metadata =
×
84
            match body with
85
            | `String s ->
×
86
                [ ("error", `String s) ]
87
            | `Strings ss ->
×
88
                [ ("error", `List (List.map ss ~f:(fun s -> `String s))) ]
×
89
            | `Empty | `Pipe _ ->
×
90
                []
91
          in
92
          [%log error] "Failed to send node error data to URL $url"
×
93
            ~metadata:(metadata @ extra_metadata)
94
    | Error e ->
×
95
        [%log error] "Failed to send node error data to URL $url"
×
96
          ~metadata:
97
            [ ("error", `String (Exn.to_string e))
×
98
            ; ("url", `String (Uri.to_string url))
×
99
            ]
100

101
let with_deps ~logger ~f =
102
  match !config with
×
103
  | None ->
×
104
      [%log error]
×
105
        "Could not send error report: Node_error_service was not configured" ;
106
      Deferred.unit
×
107
  | Some { get_node_state; node_error_url; contact_info } -> (
×
108
      match%bind get_node_state () with
×
109
      | None ->
×
110
          [%log info]
×
111
            "Could not send error report: mina instance has not been created \
112
             yet." ;
113
          Deferred.unit
×
114
      | Some node_state ->
×
115
          f ~node_state ~node_error_url ~contact_info )
116

117
let generate_report ~commit_id ~node_state ~contact_info error =
118
  let timestamp = Rfc3339_time.get_rfc3339_time () in
×
119
  let id = Uuid_unix.create () |> Uuid.to_string in
×
120
  let ({ peer_id
×
121
       ; ip_address
122
       ; public_key
123
       ; chain_id
124
       ; hardware_info
125
       ; catchup_job_states
126
       ; sync_status
127
       ; block_height_at_best_tip
128
       ; uptime_of_node
129
       }
130
        : node_state ) =
131
    node_state
132
  in
133
  Some
134
    { version = 1
135
    ; peer_id
136
    ; ip_address
137
    ; public_key
138
    ; commit_hash = commit_id
139
    ; chain_id
140
    ; contact_info
141
    ; hardware_info
142
    ; timestamp
143
    ; id
144
    ; error
145
    ; catchup_job_states
146
    ; sync_status
147
    ; block_height_at_best_tip
148
    ; max_observed_block_height =
149
        !Mina_metrics.Transition_frontier.max_blocklength_observed
150
    ; max_observed_unvalidated_block_height =
151
        !Mina_metrics.Transition_frontier.max_unvalidated_blocklength_observed
152
    ; uptime_of_node
153
    }
154

155
let send_dynamic_report ~commit_id ~logger ~generate_error =
156
  with_deps ~logger ~f:(fun ~node_state ~node_error_url ~contact_info ->
×
NEW
157
      match
×
158
        generate_report ~commit_id ~node_state ~contact_info (`String "")
159
      with
UNCOV
160
      | None ->
×
161
          Deferred.unit
162
      | Some base_report ->
×
163
          (* subtract 2 bytes for the size of empty string in json *)
164
          let base_report_size =
165
            String.length (Yojson.Safe.to_string @@ serialize_report base_report)
×
166
            - 2
167
          in
168
          let available_bytes = max_report_bytes - base_report_size in
169
          let report =
170
            { base_report with error = generate_error available_bytes }
×
171
          in
172
          send_node_error_report ~logger ~url:node_error_url report )
173

174
let send_report ~commit_id ~logger ~error =
175
  with_deps ~logger ~f:(fun ~node_state ~node_error_url ~contact_info ->
×
176
      match
×
177
        generate_report ~commit_id ~node_state ~contact_info
178
          (Error_json.error_to_yojson error)
×
179
      with
180
      | None ->
×
181
          Deferred.unit
182
      | Some report ->
×
183
          send_node_error_report ~logger ~url:node_error_url report )
16✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc