canic/
log.rs

1use candid::CandidType;
2use derive_more::Display;
3use serde::{Deserialize, Serialize};
4
5///
6/// Debug
7///
8
9#[derive(
10    Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, CandidType, Display, Serialize, Deserialize,
11)]
12pub enum Level {
13    Debug, // least severe
14    Info,
15    Ok,
16    Warn,
17    Error, // most severe
18}
19
20///
21/// Topic
22///
23
24#[derive(Clone, Copy, Display, Eq, PartialEq)]
25pub enum Topic {
26    App,
27    CanisterLifecycle,
28    CanisterReserve,
29    CanisterState,
30    Cycles,
31    Init,
32    Memory,
33    Sharding,
34    Topology,
35    Wasm,
36}
37
38#[macro_export]
39macro_rules! log {
40    // =========================================
41    // (1) With topic (normal + trailing comma)
42    // =========================================
43    ($topic:expr, $level:ident, $fmt:expr $(, $arg:expr)* $(,)?) => {{
44        $crate::log!(@inner Some(&$topic.to_string()), $crate::log::Level::$level, $fmt $(, $arg)*);
45    }};
46
47    // =========================================
48    // (2) No topic (normal + trailing comma)
49    // =========================================
50    ($level:ident, $fmt:expr $(, $arg:expr)* $(,)?) => {{
51        $crate::log!(@inner None::<&str>, $crate::log::Level::$level, $fmt $(, $arg)*);
52    }};
53
54    // =========================================
55    // INTERNAL
56    // =========================================
57    (@inner $topic:expr, $level:expr, $fmt:expr $(, $arg:expr)*) => {{
58        let level = $level;
59        let topic_opt: Option<&str> = $topic;
60        let message = format!($fmt $(, $arg)*);
61
62        // append entry
63        let crate_name = env!("CARGO_PKG_NAME");
64        let _ = $crate::ops::model::memory::log::LogOps::append(crate_name, topic_opt, level, &message);
65
66        let ty_raw = $crate::ops::model::memory::env::EnvOps::try_get_canister_type()
67            .map(|ty| ty.to_string())
68            .unwrap_or_else(|_| "...".to_string());
69
70        let ty_disp = $crate::utils::format::ellipsize_middle(&ty_raw, 9, 4, 4);
71        let ty_centered = format!("{:^9}", ty_disp);
72
73        let final_msg = if let Some(t) = topic_opt {
74            format!("[{t}] {message}")
75        } else {
76            message
77        };
78
79        let (color, reset) = match level {
80            $crate::log::Level::Ok    => ("\x1b[32m", "\x1b[0m"),
81            $crate::log::Level::Info  => ("\x1b[34m", "\x1b[0m"),
82            $crate::log::Level::Warn  => ("\x1b[33m", "\x1b[0m"),
83            $crate::log::Level::Error => ("\x1b[31m", "\x1b[0m"),
84            $crate::log::Level::Debug => ("", ""),
85        };
86
87        let label = format!("{color}{:^5}{reset}", level.to_string().to_uppercase());
88        let line = format!("{label}|{ty_centered}| {final_msg}");
89
90        $crate::cdk::println!("{line}");
91    }};
92}