Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add logging macro #196

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Scarb.lock
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,19 @@ dependencies = [
name = "consensus"
version = "0.1.0"
dependencies = [
"logging",
"raito_macros",
"utils",
]

[[package]]
name = "logging"
version = "0.1.0"

[[package]]
name = "raito_macros"
version = "0.1.0"

[[package]]
name = "utils"
version = "0.1.0"
1 change: 1 addition & 0 deletions Scarb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ license-file = "LICENSE"

[workspace.dependencies]
cairo_test = "2.8.0"

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

5 changes: 3 additions & 2 deletions packages/consensus/Scarb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ edition = "2024_07"

[dependencies]
utils = { path = "../utils" }

raito_macros = { path = "../macros" }
logging = { path = "../logging" }
[dev-dependencies]
cairo_test.workspace = true

[scripts]
# TODO: cairo lint
lint = "scarb fmt"
lint = "scarb fmt"
3 changes: 1 addition & 2 deletions packages/consensus/src/codec.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

use super::types::transaction::{Transaction, TxIn, TxOut, OutPoint};
use utils::hash::Digest;

pub trait Encode<T> {
/// Encode using Bitcoin codec and append to the buffer.
fn encode_to(self: @T, ref dest: ByteArray);
Expand All @@ -12,6 +11,7 @@ pub trait Encode<T> {
self: @T
) -> ByteArray {
let mut dest: ByteArray = Default::default();
if logging::log::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!("tx_encoded: {}", dest)) }
Self::encode_to(self, ref dest);
dest
}
Expand Down Expand Up @@ -767,7 +767,6 @@ mod tests {
"020000000001013ce63f3c9d1375b3d7fc59516dbe57120fe3c912a31ebc29241897b16215cc390000000000fdffffff020f900100000000001976a914998db5e1126bc3a5e04109fbf253a7900462410e88acd9bd150000000000160014579bf4f06510c8683f2451262b6685b00012e46f024730440220537f470c1a18dc1a9d233c0b6af1d2ce18a07f3b244e4d9d54e0e60c34c55e67022058169cd11ac42374cda217d6e28143abd0e79549f7b84acc6542817466dc9b3001210301c1768b48843933bd7f0e8782716e8439fc44723d3745feefde2d57b761f5033f600a00"
);
let total_weight = 3 * tx_encoded.len() + wtx_encoded.len();

assert_eq!(tx_encoded, tx_encoded_expect);
assert_eq!(wtx_encoded, wtx_encoded_expect);
assert_eq!(total_weight, 3 * 116 + 225); //573
Expand Down
2 changes: 0 additions & 2 deletions packages/consensus/src/validation/timestamp.cairo
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
//! Block time validation helpers.
//!
//! Read more: https://learnmeabitcoin.com/technical/block/time/

/// Check that the block time is greater than the median of the 11 most recent timestamps.
pub fn validate_timestamp(prev_timestamps: Span<u32>, block_time: u32) -> Result<(), ByteArray> {
// Sort the last 11 timestamps
Expand Down Expand Up @@ -55,7 +54,6 @@ pub fn next_prev_timestamps(prev_timestamps: Span<u32>, block_time: u32) -> Span
#[cfg(test)]
mod tests {
use super::{validate_timestamp, next_prev_timestamps};

#[test]
fn test_validate_timestamp() {
let prev_timestamps = array![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11].span();
Expand Down
1 change: 1 addition & 0 deletions packages/logging/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
target
14 changes: 14 additions & 0 deletions packages/logging/Scarb.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "logging"
version = "0.1.0"
edition = "2024_07"

# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html
[dev-dependencies]
cairo_test = "2.8.2"

[features]
default = ["log_level_none"]
log_level_trace = []
log_level_debug = []
log_level_none = []
1 change: 1 addition & 0 deletions packages/logging/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod log;
18 changes: 18 additions & 0 deletions packages/logging/src/log.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#[cfg(feature: 'log_level_trace')]
pub const LOG_LEVEL_TRACE: bool = true;

#[cfg(feature: 'log_level_trace')]
pub const LOG_LEVEL_DEBUG: bool = true;

#[cfg(feature: 'log_level_debug')]
pub const LOG_LEVEL_TRACE: bool = false;

#[cfg(feature: 'log_level_debug')]
pub const LOG_LEVEL_DEBUG: bool = true;

#[cfg(feature: 'log_level_none')]
pub const LOG_LEVEL_TRACE: bool = false;

#[cfg(feature: 'log_level_none')]
pub const LOG_LEVEL_DEBUG: bool = false;

1 change: 1 addition & 0 deletions packages/macros/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
target
14 changes: 14 additions & 0 deletions packages/macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Cargo.toml
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Package should be called logging not macros.

[package]
name = "raito_macros"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
bigdecimal = "0.4.5"
cairo-lang-macro = "0.1"
cairo-lang-parser = "2.8.0"
cairo-lang-syntax = "2.8.0"
7 changes: 7 additions & 0 deletions packages/macros/Scarb.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "raito_macros"
version = "0.1.0"
edition = "2024_07"

# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html
[cairo-plugin]
1 change: 1 addition & 0 deletions packages/macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod logging;
152 changes: 152 additions & 0 deletions packages/macros/src/logging.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
use cairo_lang_macro::{inline_macro, Diagnostic, ProcMacroResult, TokenStream};
use cairo_lang_parser::utils::SimpleParserDatabase;
use cairo_lang_syntax::node::kind::SyntaxKind;

#[inline_macro]
pub fn log(token_stream: TokenStream) -> ProcMacroResult {
let db = SimpleParserDatabase::default();
let (parsed, _diag) = db.parse_virtual_with_diagnostics(token_stream);

let mut args = parsed
.descendants(&db)
.filter(|node| matches!(node.kind(&db), SyntaxKind::Arg));

// Extract log level
let level = match args.next() {
Some(node) => node.get_text(&db),
_ => return create_error_result("Invalid log level"),
};

// Validate log level
if !["\"TRACE\"", "\"DEBUG\""].contains(&level.as_str()) {
return create_error_result("Invalid log level. Use TRACE or DEBUG");
}

// Extract format string
let format_string = match args.next() {
Some(node) => node.get_text(&db),
_ => return create_error_result("Invalid format string"),
};

// Extract remaining arguments
let log_args: Vec<String> = args
.map(|node| {
if matches!(node.kind(&db), SyntaxKind::Arg) {
Ok(node.get_text(&db))
} else {
Err(())
}
})
.collect::<Result<Vec<String>, ()>>()
.unwrap_or_else(|_| {
create_error_result("Invalid log argument");
Vec::new()
});

// Generate the log statement
let log_statement = generate_log_statement(&level, &format_string, &log_args);

println!("Log statement: {}", log_statement);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not necessary?

ProcMacroResult::new(TokenStream::new(log_statement))
}

fn create_error_result(message: &str) -> ProcMacroResult {
ProcMacroResult::new(TokenStream::empty()).with_diagnostics(Diagnostic::error(message).into())
}

fn generate_log_statement(level: &str, format_string: &str, log_args: &[String]) -> String {
let level_str = level.trim_matches('"');
let condition = match level_str {
"TRACE" => "LOG_LEVEL_TRACE",
"DEBUG" => "LOG_LEVEL_DEBUG",
_ => unreachable!(),
};
let level_str = format!("{}", level);
let print_statement = if log_args.is_empty() {
format!(
"println!(\"{{}}: {{}}\", format!({}), format!({}))",
level_str, format_string
)
} else {
format!(
"println!(\"{{}}: {{}}\", format!({}), format!({}, {}))",
level_str,
format_string,
log_args.join(", ")
)
};

format!("if logging::{} {{ {} }}", condition, print_statement)
}
mod tests {
use super::*;
use cairo_lang_macro::TokenStream;

// Helper function to expand macros
#[allow(unused)]
fn expand_macro(macro_fn: fn(TokenStream) -> ProcMacroResult, input: &str) -> String {
let token_stream = TokenStream::new(input.to_string());
let result = macro_fn(token_stream);
result.token_stream.to_string()
}

#[test]
fn test_log_macro_debug() {
let expanded = expand_macro(
log_02lvnd9pht92k,
r#"log!("DEBUG", "test message: {}", '123')"#,
);
assert_eq!(
expanded,
r#"if logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!("test message: {}", '123')) }"#
);
}

#[test]
fn test_log_macro_trace() {
let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("TRACE", "entering function")"#);
assert_eq!(
expanded,
r#"if logging::LOG_LEVEL_TRACE { println!("{}: {}", format!("TRACE"), format!("entering function")) }"#
);
}

#[test]
fn test_log_macro_invalid_level() {
let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("INFO", "test message")"#);
assert_eq!(expanded, ""); // Empty TokenStream for error case
}

#[test]
fn test_log_macro_empty_format() {
let expanded = expand_macro(log_02lvnd9pht92k, r#"log!("DEBUG", '')"#);
assert_eq!(
expanded,
r#"if logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!('')) }"#
);
}

#[test]
fn test_log_macro_multiple_arguments() {
let expanded = expand_macro(
log_02lvnd9pht92k,
r#"log!("DEBUG", "Values: {}, {}, {}", '1', '2', '3')"#,
);
assert_eq!(
expanded,
r#"if logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!("Values: {}, {}, {}", '1', '2', '3')) }"#
);
}

#[test]
fn test_log_macro_exact_string() {
let expanded = expand_macro(
log_02lvnd9pht92k,
r#"log!("DEBUG", "Exact {} string", 'test')"#,
);
assert_eq!(
expanded,
r#"if logging::LOG_LEVEL_DEBUG { println!("{}: {}", format!("DEBUG"), format!("Exact {} string", 'test')) }"#
);
}
}
Loading