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();
26 sys.refresh_cpu_all();
27 sys.refresh_memory();
28
29 let c = component;
30
31 let kernel_version = System::kernel_version().map_or(String::new(), |v| format!("kernel-{v} "));
32 let os_version = System::long_os_version().unwrap_or_default();
33 let pid = std::process::id();
34
35 header_sepr(c, "=================================================================");
36 header_sepr(c, " NAUTILUS TRADER - Automated Algorithmic Trading Platform");
37 header_sepr(c, " by Nautech Systems Pty Ltd.");
38 header_sepr(c, " Copyright (C) 2015-2026. All rights reserved.");
39 header_sepr(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_line(c, "");
54 header_sepr(c, "=================================================================");
55 header_sepr(c, " SYSTEM SPECIFICATION");
56 header_sepr(c, "=================================================================");
57
58 if let Some(cpu) = sys.cpus().first() {
59 header_line(c, &format!("CPU architecture: {}", cpu.brand()));
60 header_line(c, &format!("CPU(s): {} @ {} MHz", sys.cpus().len(), cpu.frequency()));
61 } else {
62 header_line(c, "CPU: unknown");
63 }
64 header_line(c, &format!("OS: {kernel_version}{os_version}"));
65
66 log_sysinfo(component);
67
68 header_sepr(c, "=================================================================");
69 header_sepr(c, " IDENTIFIERS");
70 header_sepr(c, "=================================================================");
71 header_line(c, &format!("trader_id: {trader_id}"));
72 header_line(c, &format!("machine_id: {machine_id}"));
73 header_line(c, &format!("instance_id: {instance_id}"));
74 header_line(c, &format!("PID: {pid}"));
75
76 header_sepr(c, "=================================================================");
77 header_sepr(c, " VERSIONING");
78 header_sepr(c, "=================================================================");
79
80 #[cfg(not(feature = "python"))]
81 log_rust_versioning(c);
82
83 #[cfg(feature = "python")]
84 log_python_versioning(c);
85}
86
87#[cfg(not(feature = "python"))]
88#[rustfmt::skip]
89fn log_rust_versioning(c: Ustr) {
90 use nautilus_core::consts::NAUTILUS_VERSION;
91 header_line(c, &format!("nautilus_trader: {NAUTILUS_VERSION}"));
92}
93
94#[cfg(feature = "python")]
95#[rustfmt::skip]
96fn log_python_versioning(c: Ustr) {
97 if !python_available() {
98 return;
99 }
100
101 let package = "nautilus_trader";
102 header_line(c, &format!("{package}: {}", python_package_version(package)));
103 header_line(c, &format!("python: {}", python_version()));
104
105 for package in ["numpy", "pandas", "msgspec", "pyarrow", "pytz", "uvloop"] {
107 if let Some(version) = python_package_version_opt(package) {
108 header_line(c, &format!("{package}: {version}"));
109 }
110 }
111
112 header_sepr(c, "=================================================================");
113}
114
115#[cfg(feature = "python")]
116#[inline]
117#[allow(unsafe_code)]
118fn python_available() -> bool {
119 unsafe { pyo3::ffi::Py_IsInitialized() != 0 }
122}
123
124#[rustfmt::skip]
125pub fn log_sysinfo(component: Ustr) {
126 let mut sys = System::new();
127 sys.refresh_memory();
128
129 let c = component;
130
131 let ram_total = sys.total_memory();
132 let ram_used = sys.used_memory();
133 let ram_used_p = (ram_used as f64 / ram_total as f64) * 100.0;
134 let ram_avail = ram_total - ram_used;
135 let ram_avail_p = (ram_avail as f64 / ram_total as f64) * 100.0;
136
137 header_sepr(c, "=================================================================");
138 header_sepr(c, " MEMORY USAGE");
139 header_sepr(c, "=================================================================");
140 header_line(c, &format!("RAM-Total: {:.2} GiB", bytes_to_gib(ram_total)));
141 header_line(c, &format!("RAM-Used: {:.2} GiB ({:.2}%)", bytes_to_gib(ram_used), ram_used_p));
142 header_line(c, &format!("RAM-Avail: {:.2} GiB ({:.2}%)", bytes_to_gib(ram_avail), ram_avail_p));
143
144 let swap_total = sys.total_swap();
145 if swap_total > 0 {
146 let swap_used = sys.used_swap();
147 let swap_used_p = (swap_used as f64 / swap_total as f64) * 100.0;
148 let swap_avail = swap_total.saturating_sub(swap_used);
149 let swap_avail_p = (swap_avail as f64 / swap_total as f64) * 100.0;
150 header_line(c, &format!("Swap-Total: {:.2} GiB", bytes_to_gib(swap_total)));
151 header_line(c, &format!("Swap-Used: {:.2} GiB ({:.2}%)", bytes_to_gib(swap_used), swap_used_p));
152 header_line(c, &format!("Swap-Avail: {:.2} GiB ({:.2}%)", bytes_to_gib(swap_avail), swap_avail_p));
153 } else {
154 header_line(c, "Swap: disabled");
155 }
156}
157
158fn header_sepr(c: Ustr, s: &str) {
159 log_info!("{}", s, color = LogColor::Cyan, component = c.as_str());
160}
161
162fn header_line(c: Ustr, s: &str) {
163 log_info!("{}", s, component = c.as_str());
164}
165
166fn bytes_to_gib(b: u64) -> f64 {
167 b as f64 / (2u64.pow(30) as f64)
168}
169
170#[cfg(feature = "python")]
171fn python_package_version(package: &str) -> String {
172 nautilus_core::python::version::get_python_package_version(package)
173}
174
175#[cfg(feature = "python")]
176fn python_package_version_opt(package: &str) -> Option<String> {
177 nautilus_core::python::version::get_python_package_version_opt(package)
178}
179
180#[cfg(feature = "python")]
181fn python_version() -> String {
182 nautilus_core::python::version::get_python_version()
183}