-
-
Notifications
You must be signed in to change notification settings - Fork 41
✨ feat: implement isomorphic logging system and add comprehensive debug logging #1798
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
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
|
WalkthroughThis change introduces comprehensive debug and informational logging throughout the EVM codebase. Logging statements are added to key operations in modules such as state, memory, stack, VM, and jump table, providing runtime diagnostics and traceability. A new isomorphic logging infrastructure is implemented to support consistent logging across native, WASI, and WASM platforms. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant EVM_Module
participant Logger
participant Platform (Native/WASI/WASM)
User->>EVM_Module: Invoke operation (e.g., stack.push, vm.init)
EVM_Module->>Logger: Call log function (debug/info/warn/err)
Logger->>Platform: Dispatch to platform-appropriate log handler
Platform-->>Logger: Log message handled (console, buffer, stderr, etc.)
Possibly related PRs
Poem
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
…ug logging Implement cross-platform logging system using std_options.logFn that works consistently across all target architectures including native platforms, WASI, and WASM environments. Add comprehensive debug logging throughout core EVM components for better development experience and debugging. ## Implementation Strategy ### Step 1: Create std_options configuration - Created src/std_options.zig with custom logFn for multi-platform support - Compile-time target detection for zero runtime overhead - Platform-specific backends: native (stderr), WASI (stderr), WASM (buffer + JS interop) - Dead code elimination removes unused backends ### Step 2: Platform-specific logging backends - Native platforms: Use std.log.defaultLog for stderr/stdout - WASI: stderr writer with proper error handling - WASM (freestanding): Dual approach with buffer + optional JS console interop - Export functions for JS integration: getLogBuffer(), getLogBufferLen(), clearLogBuffer() - Thread-safe buffer management with mutex protection ### Step 3: Update existing logging module - Modified src/evm/log.zig to use std.log for isomorphic behavior - Removed inline keywords for consistent bundle size optimization - Added info() function for general information logging - Maintained EVM-specific log prefixing for easy identification ### Step 4: Add comprehensive debug logging - VM execution: initialization, interpretation context, depth tracking - Jump table: opcode execution, gas consumption, validation errors - State management: storage operations, initialization tracking - Stack operations: push/pop operations, overflow/underflow detection - Memory management: resize operations, byte access, limit enforcement ## Technical Specifications ### File Structure - src/std_options.zig (new): Isomorphic logging configuration - src/evm/log.zig (modified): Updated API using std.log - src/evm/vm.zig (modified): Added VM execution logging - src/evm/jump_table.zig (modified): Added opcode dispatch logging - src/evm/evm_state.zig (modified): Added state operation logging - src/evm/stack.zig (modified): Added stack operation logging - src/evm/memory.zig (modified): Added memory operation logging ### Target Platform Support - linux, macos, windows, freebsd: Native stderr/stdout logging - wasi: WASM with system interface support - freestanding + wasm32/wasm64: Browser/Node.js WASM environments - Other platforms: Fallback to default or no-op logging ### Performance Considerations - Compile-time target detection (zero runtime overhead) - Debug logs optimized away in release builds - Efficient buffer management for WASM (8KB buffer with wraparound) - Mutex protection for thread-safe buffer access - Minimal memory footprint for embedded targets ### Error Handling - All logging errors are non-fatal - Graceful fallback when JS interop unavailable - Buffer overflow protection with safe wraparound - Memory allocation failure handling - Silent operation in resource-constrained environments ## Success Criteria Achieved ### Functional ✅ Logging works identically across all target platforms ✅ WASM builds compile and run without logging errors ✅ Existing codebase requires no changes to logging calls ✅ JavaScript can read logs from WASM modules via exported functions ✅ Comprehensive debug logging added to core EVM components ### Quality ✅ Code follows project style guidelines (snake_case, 120 char width) ✅ Implementation is maintainable and well-documented ✅ Performance overhead is minimal (compile-time optimization) ✅ Error handling is robust and non-intrusive ✅ All tests pass (zig build test-all) ### Integration ✅ Seamless replacement of existing logging system ✅ No disruption to development workflow ✅ Clear path for future logging enhancements ✅ Compatible with existing build system and CI ✅ Maintains API compatibility while improving functionality The isomorphic logging system enables consistent debugging across all deployment targets while the comprehensive debug logging provides detailed insights into EVM execution flow, making development and troubleshooting significantly more effective. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (2)
src/std_options.zig (2)
136-140
: Consider making the JS message buffer size configurableThe fixed buffer size of 2048 bytes might be insufficient for complex log messages with multiple arguments. While truncation is handled gracefully, important debugging information could be lost.
Consider making this configurable or using a larger default:
- var buf: [2048]u8 = undefined; + const js_log_buffer_size = if (@hasDecl(@import("root"), "js_log_buffer_size")) + @import("root").js_log_buffer_size + else + 4096; + var buf: [js_log_buffer_size]u8 = undefined;
14-48
: Excellent isomorphic logging architecture!The platform detection and dispatching logic provides comprehensive coverage across different target architectures. The separation of platform-specific implementations makes the code maintainable and extensible.
For future enhancements, consider:
- Adding log rotation for long-running WASM applications
- Implementing configurable log levels per module/scope
- Adding structured logging support for easier parsing by external tools
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
src/evm/evm_state.zig
(4 hunks)src/evm/jump_table.zig
(2 hunks)src/evm/log.zig
(1 hunks)src/evm/memory.zig
(2 hunks)src/evm/stack.zig
(3 hunks)src/evm/vm.zig
(2 hunks)src/std_options.zig
(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
- GitHub Check: Nx Cloud - Main Job
- GitHub Check: Analyze (javascript-typescript)
- GitHub Check: CI Checks
🔇 Additional comments (10)
src/evm/memory.zig (2)
154-159
: LGTM: Clear and useful debug logging for memory operations.The debug logs provide valuable visibility into memory resize operations and limit violations without affecting the core logic. Format strings correctly match the provided arguments.
246-246
: LGTM: Helpful debug logging for memory write operations.The hex formatting of the byte value (0x{x:0>2}) provides clear visibility into memory writes during debugging.
src/evm/vm.zig (2)
74-74
: LGTM: Clear VM initialization lifecycle logging.The debug logs provide useful tracing of VM initialization start and completion, enhancing observability without affecting functionality.
Also applies to: 82-82
144-144
: LGTM: Comprehensive execution context logging.The debug log captures key execution parameters (depth, gas, static mode) that are essential for debugging EVM execution flows.
src/evm/evm_state.zig (3)
92-92
: LGTM: Consistent state initialization logging.The debug logs follow the same clear pattern as VM initialization, providing useful lifecycle tracing for the EVM state component.
Also applies to: 112-112
167-169
: LGTM: Valuable storage read tracing.The debug logging provides excellent visibility into storage access patterns. The use of
Address.to_u256(address)
for consistent address formatting is appropriate.
190-190
: LGTM: Consistent storage write logging.The debug log maintains consistency with the get_storage logging format, providing complete traceability for storage operations.
src/evm/jump_table.zig (1)
127-127
: LGTM: Comprehensive opcode execution tracing.The debug logging provides excellent visibility into opcode execution flow:
- Execution context (opcode, PC, gas, stack size)
- Invalid opcode detection
- Gas consumption tracking
- Execution completion status
All format strings correctly match their arguments and the logging enhances debugging capabilities without affecting performance in release builds.
Also applies to: 130-130, 139-139, 144-144
src/evm/stack.zig (1)
2-2
: Well-placed debug logging for stack operations!The debug logging additions provide excellent visibility into stack operations:
- Overflow/underflow conditions are logged with current state
- Successful operations log the values and new size
- All debug logs will be optimized out in release builds
Also applies to: 104-108, 144-151
src/evm/log.zig (1)
1-29
: Clean and idiomatic logging API!The refactored logging module properly leverages Zig's standard logging system with appropriate EVM-specific prefixing. The direct use of
std.log
functions ensures platform compatibility through thestd_options
configuration.
/// Global log buffer for WASM environments | ||
var log_buffer: [8192]u8 = undefined; | ||
var log_buffer_pos: usize = 0; | ||
var log_buffer_mutex: std.Thread.Mutex = .{}; | ||
|
||
/// Write log message to buffer that JavaScript can read | ||
fn writeToLogBuffer( | ||
comptime level: std.log.Level, | ||
comptime scope: @Type(.enum_literal), | ||
comptime format: []const u8, | ||
args: anytype, | ||
) void { | ||
log_buffer_mutex.lock(); | ||
defer log_buffer_mutex.unlock(); | ||
|
||
// Reserve space for potential wraparound | ||
const available_space = log_buffer.len - log_buffer_pos; | ||
if (available_space < 512) { | ||
log_buffer_pos = 0; // Wrap around if near end | ||
} | ||
|
||
var fbs = std.io.fixedBufferStream(log_buffer[log_buffer_pos..]); | ||
const writer = fbs.writer(); | ||
|
||
writer.print("[{s}] ({s}): " ++ format ++ "\n", .{ | ||
@tagName(level), @tagName(scope) | ||
} ++ args) catch return; | ||
|
||
log_buffer_pos += fbs.pos; | ||
} | ||
|
||
/// Export function to get log buffer pointer for JavaScript | ||
export fn getLogBuffer() [*]const u8 { | ||
return &log_buffer; | ||
} | ||
|
||
/// Export function to get current log buffer length | ||
export fn getLogBufferLen() usize { | ||
return log_buffer_pos; | ||
} | ||
|
||
/// Export function to clear the log buffer | ||
export fn clearLogBuffer() void { | ||
log_buffer_mutex.lock(); | ||
defer log_buffer_mutex.unlock(); | ||
log_buffer_pos = 0; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
❓ Verification inconclusive
Thread safety concern in WASM log buffer implementation
The mutex only protects write operations but not the exported read functions. This could lead to race conditions where JavaScript reads partially written or corrupted data while Zig is writing.
Additionally, the wraparound logic at lines 95-98 silently discards old logs without any indication. Consider implementing a proper circular buffer or at least adding a marker to indicate log truncation.
Apply this diff to add read protection:
export fn getLogBuffer() [*]const u8 {
+ log_buffer_mutex.lock();
+ defer log_buffer_mutex.unlock();
return &log_buffer;
}
export fn getLogBufferLen() usize {
+ log_buffer_mutex.lock();
+ defer log_buffer_mutex.unlock();
return log_buffer_pos;
}
Note: This assumes JavaScript calls are synchronous. If async access is needed, consider implementing a double-buffering strategy.
Improve WASM log buffer initialization, wraparound handling, and read consistency
A few safety and observability issues remain in the current implementation:
- Uninitialized buffer:
var log_buffer: [8192]u8 = undefined;
exposes arbitrary memory on the first read. - Silent wraparound:
Whenavailable_space < 512
, the code resetslog_buffer_pos = 0
without any marker, losing the fact that older entries were discarded. - Inconsistent reads:
Separately exportinggetLogBuffer()
andgetLogBufferLen()
allows logs to be written between calls, leading to mismatched pointer/length and potential corruption.
Suggested fixes:
• Initialize the buffer (e.g. zero it out) either at declaration or in clearLogBuffer()
.
• At wraparound, write a truncation marker (e.g. "[...truncated...]\n"
) before resetting, or convert to a true circular buffer.
• Replace the two getters with a single snapshot function that locks, copies the active slice under one lock, then returns both pointer and length atomically.
Pinpoint locations:
- src/std_options.zig: line 79 (
var log_buffer: [8192]u8 = undefined;
) - src/std_options.zig: lines 95–98 (wraparound logic)
- src/std_options.zig: lines 107–113 (
getLogBuffer()
/getLogBufferLen()
)
Example snapshot API:
pub fn snapshotLogBuffer(allocator: *std.mem.Allocator) ![]u8 {
log_buffer_mutex.lock();
defer log_buffer_mutex.unlock();
const len = log_buffer_pos;
var out = try allocator.alloc(u8, len);
std.mem.copy(u8, out, log_buffer[0..len]);
return out;
}
🤖 Prompt for AI Agents
In src/std_options.zig around lines 79 to 125, fix the uninitialized log_buffer
by zero-initializing it at declaration or in clearLogBuffer(). Modify the
wraparound logic at lines 95-98 to write a truncation marker like
"[...truncated...]\n" before resetting log_buffer_pos to 0 to indicate discarded
logs. Replace the separate getLogBuffer() and getLogBufferLen() functions at
lines 107-113 with a single snapshotLogBuffer() function that locks the mutex,
copies the current log slice into a newly allocated buffer, and returns it
atomically to ensure consistent reads without race conditions.
Description
Added comprehensive logging infrastructure to the EVM implementation to improve debugging and traceability. The changes include:
log.zig
module with isomorphic logging that works across all target architectures (native, WASI, WASM)evm_state.zig
jump_table.zig
memory.zig
stack.zig
vm.zig
std_options.zig
file with a custom logging function that adapts to different environmentsTesting
The logging system has been tested across multiple platforms to ensure consistent behavior. Debug logs are optimized away in release builds to maintain performance. The implementation follows best practices for thread safety with mutex protection for the shared log buffer.
Additional Information
Your ENS/address:
Summary by CodeRabbit
New Features
Improvements