nautilus_common/logging/
headers.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16use nautilus_core::UUID4;
17use nautilus_model::identifiers::TraderId;
18use sysinfo::System;
19use ustr::Ustr;
20
21use crate::{
22    enums::{LogColor, LogLevel},
23    logging::logger::log,
24};
25
26#[rustfmt::skip]
27pub fn log_header(trader_id: TraderId, machine_id: &str, instance_id: UUID4, component: Ustr) {
28    let mut sys = System::new_all();
29    sys.refresh_all();
30
31    let c = component;
32
33    let kernel_version = System::kernel_version().map_or(String::new(), |v| format!("kernel-{v} "));
34    let os_version = System::long_os_version().unwrap_or_default();
35    let pid = std::process::id();
36
37    header_sepr(c, "=================================================================");
38    header_sepr(c, " NAUTILUS TRADER - Automated Algorithmic Trading Platform");
39    header_sepr(c, " by Nautech Systems Pty Ltd.");
40    header_sepr(c, " Copyright (C) 2015-2025. All rights reserved.");
41    header_sepr(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_line(c, "⠀⠀⠀⠀⠀⠀⠋⠀⠀⠀⡘⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠁⠀⠀⠀⠀⠀⠀⠀");
55    header_line(c, "");
56    header_sepr(c, "=================================================================");
57    header_sepr(c, " SYSTEM SPECIFICATION");
58    header_sepr(c, "=================================================================");
59    header_line(c, &format!("CPU architecture: {}", sys.cpus()[0].brand()));
60    header_line(c, &format!("CPU(s): {} @ {} Mhz", sys.cpus().len(), sys.cpus()[0].frequency()));
61    header_line(c, &format!("OS: {kernel_version}{os_version}"));
62
63    log_sysinfo(component);
64
65    header_sepr(c, "=================================================================");
66    header_sepr(c, " IDENTIFIERS");
67    header_sepr(c, "=================================================================");
68    header_line(c, &format!("trader_id: {trader_id}"));
69    header_line(c, &format!("machine_id: {machine_id}"));
70    header_line(c, &format!("instance_id: {instance_id}"));
71    header_line(c, &format!("PID: {pid}"));
72    header_sepr(c, "=================================================================");
73    header_sepr(c, " VERSIONING");
74    header_sepr(c, "=================================================================");
75    let package = "nautilus_trader";
76    header_line(c, &format!("{package}: {}", python_package_version(package)));
77    header_line(c, &format!("python: {}", python_version()));
78    let package = "numpy";
79    header_line(c, &format!("{package}: {}", python_package_version(package)));
80    let package = "pandas";
81    header_line(c, &format!("{package}: {}", python_package_version(package)));
82    let package = "msgspec";
83    header_line(c, &format!("{package}: {}", python_package_version(package)));
84    let package = "pyarrow";
85    header_line(c, &format!("{package}: {}", python_package_version(package)));
86    let package = "pytz";
87    header_line(c, &format!("{package}: {}", python_package_version(package)));
88    let package = "uvloop";
89    header_line(c, &format!("{package}: {}", python_package_version(package)));
90    header_sepr(c, "=================================================================");
91}
92
93#[rustfmt::skip]
94pub fn log_sysinfo(component: Ustr) {
95    let mut sys = System::new_all();
96    sys.refresh_all();
97
98    let c = component;
99
100    let ram_total = sys.total_memory();
101    let ram_used = sys.used_memory();
102    let ram_used_p = (ram_used as f64 / ram_total as f64) * 100.0;
103    let ram_avail = ram_total - ram_used;
104    let ram_avail_p = (ram_avail as f64 / ram_total as f64) * 100.0;
105
106    let swap_total = sys.total_swap();
107    let swap_used = sys.used_swap();
108    let swap_used_p = (swap_used as f64 / swap_total as f64) * 100.0;
109    let swap_avail = swap_total - swap_used;
110    let swap_avail_p = (swap_avail as f64 / swap_total as f64) * 100.0;
111
112    header_sepr(c, "=================================================================");
113    header_sepr(c, " MEMORY USAGE");
114    header_sepr(c, "=================================================================");
115    header_line(c, &format!("RAM-Total: {:.2} GiB", bytes_to_gib(ram_total)));
116    header_line(c, &format!("RAM-Used: {:.2} GiB ({:.2}%)", bytes_to_gib(ram_used), ram_used_p));
117    header_line(c, &format!("RAM-Avail: {:.2} GiB ({:.2}%)", bytes_to_gib(ram_avail), ram_avail_p));
118    header_line(c, &format!("Swap-Total: {:.2} GiB", bytes_to_gib(swap_total)));
119    header_line(c, &format!("Swap-Used: {:.2} GiB ({:.2}%)", bytes_to_gib(swap_used), swap_used_p));
120    header_line(c, &format!("Swap-Avail: {:.2} GiB ({:.2}%)", bytes_to_gib(swap_avail), swap_avail_p));
121}
122
123fn header_sepr(c: Ustr, s: &str) {
124    log(LogLevel::Info, LogColor::Cyan, c, s);
125}
126
127fn header_line(c: Ustr, s: &str) {
128    log(LogLevel::Info, LogColor::Normal, c, s);
129}
130
131fn bytes_to_gib(b: u64) -> f64 {
132    b as f64 / (2u64.pow(30) as f64)
133}
134
135#[cfg(feature = "python")]
136fn python_package_version(package: &str) -> String {
137    use nautilus_core::python::version::get_python_package_version;
138
139    get_python_package_version(package)
140}
141
142#[cfg(not(feature = "python"))]
143fn python_package_version(_package: &str) -> &str {
144    panic!("`python` feature is not enabled");
145}
146
147#[cfg(feature = "python")]
148fn python_version() -> String {
149    use nautilus_core::python::version::get_python_version;
150
151    get_python_version()
152}
153
154#[cfg(not(feature = "python"))]
155fn python_version() -> String {
156    panic!("`python` feature is not enabled");
157}