junobuild_satellite/logs/
loggers.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
use crate::logs::types::logs::{Log, LogLevel};
use crate::memory::STATE;
use crate::{set_doc_store, Key, SetDoc};
use ic_cdk::api::time;
use ic_cdk::id;
use junobuild_collections::constants::LOG_COLLECTION_KEY;
use junobuild_utils::encode_doc_data;
use rand::Rng;
use serde::Serialize;

/// Logs a message at the `Info` level.
///
/// # Arguments
///
/// * `message` - A string slice that holds the message to be logged.
///
/// # Returns
///
/// A result indicating success (`Ok(())`) or containing an error message (`Err(String)`).
pub fn log(message: String) -> Result<(), String> {
    set_log::<()>(LogLevel::Info, message, None)
}

/// Logs a message at the `Info` level with additional serialized data.
///
/// # Arguments
///
/// * `message` - The message to be logged.
/// * `data` - A reference to the data to be logged. The data must implement the `Serialize` trait.
///
/// # Returns
///
/// A result indicating success or containing an error message.
pub fn log_with_data<T: Serialize>(message: String, data: &T) -> Result<(), String> {
    set_log::<T>(LogLevel::Info, message, Some(data))
}

/// Logs an informational message.
///
/// This function is a convenience wrapper for `log`, setting the log level to `Info`.
pub fn info(message: String) -> Result<(), String> {
    set_log::<()>(LogLevel::Info, message, None)
}

/// Logs an informational message with additional serialized data.
pub fn info_with_data<T: Serialize>(message: String, data: &T) -> Result<(), String> {
    set_log::<T>(LogLevel::Info, message, Some(data))
}

/// Logs a debug-level message.
pub fn debug(message: String) -> Result<(), String> {
    set_log::<()>(LogLevel::Debug, message, None)
}

/// Logs a debug-level message with additional serialized data.
pub fn debug_with_data<T: Serialize>(message: String, data: &T) -> Result<(), String> {
    set_log::<T>(LogLevel::Debug, message, Some(data))
}

/// Logs a warning message.
pub fn warn(message: String) -> Result<(), String> {
    set_log::<()>(LogLevel::Warning, message, None)
}

/// Logs a warning message with additional serialized data.
pub fn warn_with_data<T: Serialize>(message: String, data: &T) -> Result<(), String> {
    set_log::<T>(LogLevel::Warning, message, Some(data))
}

/// Logs an error message.
pub fn error(message: String) -> Result<(), String> {
    set_log::<()>(LogLevel::Error, message, None)
}

/// Logs an error message with additional serialized data.
pub fn error_with_data<T: Serialize>(message: String, data: &T) -> Result<(), String> {
    set_log::<T>(LogLevel::Error, message, Some(data))
}

fn set_log<T: Serialize>(level: LogLevel, message: String, data: Option<&T>) -> Result<(), String> {
    let nonce = random()?;

    let key: Key = format!("{}-{}", time(), nonce);

    let log_data = data.map(encode_doc_data).transpose()?;

    let log: Log = Log {
        level,
        message,
        data: log_data,
    };

    let doc: SetDoc = SetDoc {
        description: None,
        data: encode_doc_data(&log)?,
        version: None,
    };

    set_doc_store(id(), LOG_COLLECTION_KEY.to_string(), key, doc)?;

    Ok(())
}

fn random() -> Result<i32, String> {
    STATE.with(|state| {
        let rng = &mut state.borrow_mut().runtime.rng;

        match rng {
            None => Err("The random number generator has not been initialized.".to_string()),
            Some(rng) => Ok(rng.gen()),
        }
    })
}