Lightweight log utility for Solana programs.
Overview
Currently, logging messages that require formatting are a bit heavy on the CU consumption. There are two aspects when comes to determining the cost of a log message:
-
base cost: this is the cost of the log syscall. It will either be thesyscall_base_cost(currently100CU) or a number of CUs equal to the length of the message, whichever value is higher. -
formatting cost: the compute units required to format the message. This is variable and depends on the number and type of the arguments. Formatting is performed using Rust built-informat!routines, which in turn useformat_args!.
It is known that Rust formatting routines are CPU-intensive for constrained environments. This has been noted on both the solana-program msg! documentation and more generally on rust development.
While the cost related to (1) is fixed, in the sense that it does not change with the addition of formatting, it is possible to improve the overall cost of logging a formatted message using a lightweight formatting routine — this is what this crate does.
This crate defines a lightweight Logger type to format log messages and a companion log! macro. The logger is a fixed size buffer that can be used to format log messages before sending them to the log output. Any type that implements the Log trait can be appended to the logger.
Below is a sample of the improvements observed when formatting log messages, measured in terms of compute units (CU):
| Ouput message | log! |
msg! |
Improvement (%) |
|---|---|---|---|
"Hello world!" |
103 | 103 | - |
"lamports={}" + u64 |
374 | 627 (+253) | 40% |
"{}" + [&str; 2] |
384 | 1648 (+1264) | 76% |
"{}" + [u64; 2] |
601 | 1060 (+459) | 44% |
"lamports={}" + i64 |
389 | 660 (+271) | 41% |
"{}" + [u8; 32] (pubkey bytes) |
3147 | 8401 (+5254) | 62% |
Note: The improvement in CU is accumulative, meaning that if you are logging multiple
u64values, there will be a 40% improvement per formattedu64value.
Features
- Zero dependencies and
no_stdcrate - Independent of SDK (i.e., works with
pinocchio,solana-programoranchor) - Support for
&str, unsigned and signed integer types log!macro to facilitate log message formatting
Getting Started
From your project folder:
Usage
The Logger can be used directly:
use Logger;
let mut logger = default;
logger.append;
logger.append;
logger.log;
or via the log! macro:
use log
let amount = 1_000_000_000;
log!;
Since the formatting routine does not perform additional allocations, the Logger type has a fixed size specified on its creation. When using the log! macro, it is also possible to specify the size of the logger buffer:
use log
let amount = 1_000_000_000;
log!;
Limitations
Currently the log! macro does not offer extra formatting options apart from the placeholder "{}" for argument values.
License
The code is licensed under the Apache License Version 2.0