nautilus_common/logging/
headers.rs1use nautilus_core::UUID4;
17use nautilus_model::identifiers::TraderId;
18use sysinfo::System;
19use ustr::Ustr;
20
21use crate::{enums::LogColor, logging::log_info};
22
23#[rustfmt::skip]
24pub fn log_header(trader_id: TraderId, machine_id: &str, instance_id: UUID4, component: Ustr) {
25 let mut sys = System::new_all();
26 sys.refresh_all();
27
28 let c = component;
29
30 let kernel_version = System::kernel_version().map_or(String::new(), |v| format!("kernel-{v} "));
31 let os_version = System::long_os_version().unwrap_or_default();
32 let pid = std::process::id();
33
34 header_sepr(c, "=================================================================");
35 header_sepr(c, " NAUTILUS TRADER - Automated Algorithmic Trading Platform");
36 header_sepr(c, " by Posei Systems Pty Ltd.");
37 header_sepr(c, " Copyright (C) 2015-2025. All rights reserved.");
38 header_sepr(c, "=================================================================");
39 header_line(c, "");
40 header_line(c, "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣴⣶⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀");
41 header_line(c, "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣾⣿⣿⣿⠀⢸⣿⣿⣿⣿⣶⣶⣤⣀⠀⠀⠀⠀⠀");
42 header_line(c, "⠀⠀⠀⠀⠀⠀⢀⣴⡇⢀⣾⣿⣿⣿⣿⣿⠀⣾⣿⣿⣿⣿⣿⣿⣿⠿⠓⠀⠀⠀⠀");
43 header_line(c, "⠀⠀⠀⠀⠀⣰⣿⣿⡀⢸⣿⣿⣿⣿⣿⣿⠀⣿⣿⣿⣿⣿⣿⠟⠁⣠⣄⠀⠀⠀⠀");
44 header_line(c, "⠀⠀⠀⠀⢠⣿⣿⣿⣇⠀⢿⣿⣿⣿⣿⣿⠀⢻⣿⣿⣿⡿⢃⣠⣾⣿⣿⣧⡀⠀⠀");
45 header_line(c, "⠀⠀⠀⠠⣾⣿⣿⣿⣿⣿⣧⠈⠋⢀⣴⣧⠀⣿⡏⢠⡀⢸⣿⣿⣿⣿⣿⣿⣿⡇⠀");
46 header_line(c, "⠀⠀⠀⣀⠙⢿⣿⣿⣿⣿⣿⠇⢠⣿⣿⣿⡄⠹⠃⠼⠃⠈⠉⠛⠛⠛⠛⠛⠻⠇⠀");
47 header_line(c, "⠀⠀⢸⡟⢠⣤⠉⠛⠿⢿⣿⠀⢸⣿⡿⠋⣠⣤⣄⠀⣾⣿⣿⣶⣶⣶⣦⡄⠀⠀⠀");
48 header_line(c, "⠀⠀⠸⠀⣾⠏⣸⣷⠂⣠⣤⠀⠘⢁⣴⣾⣿⣿⣿⡆⠘⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀");
49 header_line(c, "⠀⠀⠀⠀⠛⠀⣿⡟⠀⢻⣿⡄⠸⣿⣿⣿⣿⣿⣿⣿⡀⠘⣿⣿⣿⣿⠟⠀⠀⠀⠀");
50 header_line(c, "⠀⠀⠀⠀⠀⠀⣿⠇⠀⠀⢻⡿⠀⠈⠻⣿⣿⣿⣿⣿⡇⠀⢹⣿⠿⠋⠀⠀⠀⠀⠀");
51 header_line(c, "⠀⠀⠀⠀⠀⠀⠋⠀⠀⠀⡘⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠁⠀⠀⠀⠀⠀⠀⠀");
52 header_line(c, "");
53 header_sepr(c, "=================================================================");
54 header_sepr(c, " SYSTEM SPECIFICATION");
55 header_sepr(c, "=================================================================");
56 header_line(c, &format!("CPU architecture: {}", sys.cpus()[0].brand()));
57 header_line(c, &format!("CPU(s): {} @ {} Mhz", sys.cpus().len(), sys.cpus()[0].frequency()));
58 header_line(c, &format!("OS: {kernel_version}{os_version}"));
59
60 log_sysinfo(component);
61
62 header_sepr(c, "=================================================================");
63 header_sepr(c, " IDENTIFIERS");
64 header_sepr(c, "=================================================================");
65 header_line(c, &format!("trader_id: {trader_id}"));
66 header_line(c, &format!("machine_id: {machine_id}"));
67 header_line(c, &format!("instance_id: {instance_id}"));
68 header_line(c, &format!("PID: {pid}"));
69
70 header_sepr(c, "=================================================================");
71 header_sepr(c, " VERSIONING");
72 header_sepr(c, "=================================================================");
73
74 #[cfg(not(feature = "python"))]
75 log_rust_versioning(c);
76
77 #[cfg(feature = "python")]
78 log_python_versioning(c);
79}
80
81#[cfg(not(feature = "python"))]
82#[rustfmt::skip]
83fn log_rust_versioning(c: Ustr) {
84 use nautilus_core::consts::NAUTILUS_VERSION;
85 header_line(c, &format!("posei_trader: {NAUTILUS_VERSION}"));
86}
87
88#[cfg(feature = "python")]
89#[rustfmt::skip]
90fn log_python_versioning(c: Ustr) {
91 if !python_available() {
92 return;
93 }
94
95 let package = "posei_trader";
96 header_line(c, &format!("{package}: {}", python_package_version(package)));
97 header_line(c, &format!("python: {}", python_version()));
98
99 for package in ["numpy", "pandas", "msgspec", "pyarrow", "pytz", "uvloop"] {
100 header_line(c, &format!("{package}: {}", python_package_version(package)));
101 }
102
103 header_sepr(c, "=================================================================");
104}
105
106#[cfg(feature = "python")]
107#[inline]
108#[allow(unsafe_code)]
109fn python_available() -> bool {
110 unsafe { pyo3::ffi::Py_IsInitialized() != 0 }
113}
114
115#[rustfmt::skip]
116pub fn log_sysinfo(component: Ustr) {
117 let mut sys = System::new_all();
118 sys.refresh_all();
119
120 let c = component;
121
122 let ram_total = sys.total_memory();
123 let ram_used = sys.used_memory();
124 let ram_used_p = (ram_used as f64 / ram_total as f64) * 100.0;
125 let ram_avail = ram_total - ram_used;
126 let ram_avail_p = (ram_avail as f64 / ram_total as f64) * 100.0;
127
128 let swap_total = sys.total_swap();
129 let swap_used = sys.used_swap();
130 let swap_used_p = (swap_used as f64 / swap_total as f64) * 100.0;
131 let swap_avail = swap_total - swap_used;
132 let swap_avail_p = (swap_avail as f64 / swap_total as f64) * 100.0;
133
134 header_sepr(c, "=================================================================");
135 header_sepr(c, " MEMORY USAGE");
136 header_sepr(c, "=================================================================");
137 header_line(c, &format!("RAM-Total: {:.2} GiB", bytes_to_gib(ram_total)));
138 header_line(c, &format!("RAM-Used: {:.2} GiB ({:.2}%)", bytes_to_gib(ram_used), ram_used_p));
139 header_line(c, &format!("RAM-Avail: {:.2} GiB ({:.2}%)", bytes_to_gib(ram_avail), ram_avail_p));
140 header_line(c, &format!("Swap-Total: {:.2} GiB", bytes_to_gib(swap_total)));
141 header_line(c, &format!("Swap-Used: {:.2} GiB ({:.2}%)", bytes_to_gib(swap_used), swap_used_p));
142 header_line(c, &format!("Swap-Avail: {:.2} GiB ({:.2}%)", bytes_to_gib(swap_avail), swap_avail_p));
143}
144
145fn header_sepr(c: Ustr, s: &str) {
146 log_info!("{}", s, color = LogColor::Cyan, component = c.as_str());
147}
148
149fn header_line(c: Ustr, s: &str) {
150 log_info!("{}", s, component = c.as_str());
151}
152
153fn bytes_to_gib(b: u64) -> f64 {
154 b as f64 / (2u64.pow(30) as f64)
155}
156
157#[cfg(feature = "python")]
158fn python_package_version(package: &str) -> String {
159 nautilus_core::python::version::get_python_package_version(package)
160}
161
162#[cfg(feature = "python")]
163fn python_version() -> String {
164 nautilus_core::python::version::get_python_version()
165}