futu_opend/startup/phase4/
summary.rs1use futu_gateway_core::bridge::GatewayBridge;
2
3use crate::config::RuntimeConfig;
4
5pub(super) fn merge_push_health_snapshots_for_rest(
6 push: serde_json::Value,
7 qot_login: serde_json::Value,
8 backend_connected: bool,
9) -> serde_json::Value {
10 let mut combined = match push {
11 serde_json::Value::Object(map) => map,
12 other => {
13 let mut map = serde_json::Map::new();
14 map.insert(
15 "error".to_string(),
16 serde_json::Value::String(format!(
17 "push_health snapshot serialized to non-object {}",
18 json_value_kind(&other)
19 )),
20 );
21 map
22 }
23 };
24 combined.insert("qot_login_health".to_string(), qot_login);
25 combined.insert(
26 "backend_connected".to_string(),
27 serde_json::Value::Bool(backend_connected),
28 );
29 serde_json::Value::Object(combined)
30}
31
32fn json_value_kind(value: &serde_json::Value) -> &'static str {
33 match value {
34 serde_json::Value::Null => "null",
35 serde_json::Value::Bool(_) => "bool",
36 serde_json::Value::Number(_) => "number",
37 serde_json::Value::String(_) => "string",
38 serde_json::Value::Array(_) => "array",
39 serde_json::Value::Object(_) => "object",
40 }
41}
42
43fn optional_surface_addr(bind_ip: &str, port: Option<u16>) -> String {
44 port.map(|port| format!("{bind_ip}:{port}"))
45 .unwrap_or_else(|| "disabled".to_string())
46}
47
48pub(super) fn http_host_for_bind(ip: &str) -> String {
49 match ip {
50 "0.0.0.0" | "::" => "127.0.0.1".to_string(),
51 value if value.contains(':') && !value.starts_with('[') => format!("[{value}]"),
52 value => value.to_string(),
53 }
54}
55
56fn readyz_url(config: &RuntimeConfig) -> String {
57 config
58 .rest_port
59 .map(|port| format!("http://{}:{port}/readyz", http_host_for_bind(&config.ip)))
60 .unwrap_or_else(|| "disabled".to_string())
61}
62
63pub(super) fn log_startup_summary(
64 config: &RuntimeConfig,
65 listen_addr: &str,
66 bridge: &GatewayBridge,
67) {
68 let status = bridge.snapshot_status();
69 let brokers_total = status.brokers.len();
70 let brokers_connected = status
71 .brokers
72 .iter()
73 .filter(|broker| broker.connected)
74 .count();
75 let attribution = status.login.attribution.as_deref().unwrap_or("unknown");
76 let readyz = readyz_url(config);
77 let websocket_addr = optional_surface_addr(&config.ip, config.websocket_port);
78 let rest_addr = optional_surface_addr(&config.ip, config.rest_port);
79 let grpc_addr = optional_surface_addr(&config.ip, config.grpc_port);
80 let telnet_addr = optional_surface_addr(&config.telnet_ip, config.telnet_port);
81
82 tracing::info!(
83 marker = "startup_summary",
84 version = status.version,
85 uid = ?status.login.user_id,
86 attribution,
87 platform_connected = status.platform.connected,
88 brokers_connected,
89 brokers_total,
90 ftapi_addr = %listen_addr,
91 rest_addr = %rest_addr,
92 grpc_addr = %grpc_addr,
93 websocket_addr = %websocket_addr,
94 telnet_addr = %telnet_addr,
95 readyz = %readyz,
96 "startup summary: version={} uid={:?} attribution={} brokers={}/{} ftapi={} rest={} grpc={} ws={} telnet={} readyz={}",
97 status.version,
98 status.login.user_id,
99 attribution,
100 brokers_connected,
101 brokers_total,
102 listen_addr,
103 rest_addr,
104 grpc_addr,
105 websocket_addr,
106 telnet_addr,
107 readyz
108 );
109}