DEV Community

yuzurush
yuzurush

Posted on • Updated on

Soroban Contracts 101 : Logging

Hi there! Welcome to my sixth post of my series called "Soroban Contracts 101", where I'll be explaining the basics of Soroban contracts, such as data storage, authentication, custom types, and more. All the code that we're gonna explain throughout this series will mostly come from soroban-contracts-101 github repository.

In this sixth post of the series, I'll be covering soroban contract logging. Logging is a useful tool for both development and transparency/reactivity in blockchain contracts.

The Soroban SDK provides the log! macro for easy logging from contracts. The log! macro allows logging a string from a contract. For example:

log!(&env, "Count is: {}", count);
Enter fullscreen mode Exit fullscreen mode

This would log a string including the count variable.
Some key points about logging in Soroban:

  • Logs are only output if a contract is built with debug assertions enabled (release builds omit logs)
  • Logs are only output in test environments and the soroban-cli (not in actual contract deployments)
  • Logs are output to stdout in the soroban-cli
  • Logs can be asserted on/printed in tests to verify/debug contract behavior

The Contract Code

#![no_std]
use soroban_sdk::{contractimpl, log, Env, Symbol};

pub struct Contract;

#[contractimpl]
impl Contract {
    pub fn hello(env: Env, value: Symbol) {
        log!(&env, "Hello {}", value);
    }
}
Enter fullscreen mode Exit fullscreen mode

This minimal contract Uses the no_std attribute, indicating it uses no Rust standard library. Imports essential parts of the Soroban SDK : Env, Symbol and the log macro. Defines a Contract struct and Implements a contractimpl on Contract.

The main code is the hello function,it will :

  • Takes an Env and a Symbol parameter
  • Logs a "Hello" greeting and the passed in value

The Test Code

extern crate std;

#[test]
fn test() {
    let env = Env::default();
    let contract_id = env.register_contract(None, Contract);
    let client = ContractClient::new(&env, &contract_id);

    client.hello(&symbol!("Dev"));

    let logs = env.logger().all();
    assert_eq!(logs, std::vec!["Hello Symbol(Dev)"]);
    std::println!("{}", logs.join("\n"));
}
Enter fullscreen mode Exit fullscreen mode

This code is a unit test for our contract. It does the following:

  • Imports the standard library (for testing)
  • Creates a test function
  • Creates an Env and registers the Contract
  • Creates a client to call the contract
  • Calls the client's hello function with a "Dev" symbol (to be logged)
  • Gets all logs from the Env and asserts that the expected "Hello Symbol(Dev)" log occurred
  • Also prints out the logs

So this test verifies that logging the passed in symbol parameter works as expected. It's a good practice to include basic logging tests like this in development to ensure your logging is working correctly.

Running Contract Tests

To ensure that the contract functions as intended, you can run the contract tests using the following command:

cargo test -- --nocapture
Enter fullscreen mode Exit fullscreen mode

If the tests are successful, you should see an output similar to:

running 1 test
Hello Symbol(Dev)
test test::test ... ok
Enter fullscreen mode Exit fullscreen mode

Building The Contract

Before we build the contract, we need to change cargo.toml profile in the contract directory,because earlier in this post i mentioned logs are only output if a contract is built with debug assertions enabled. So change the cargo.toml profile into :

[profile.release-with-logs]
inherits = "release"
debug-assertions = true
Enter fullscreen mode Exit fullscreen mode

To build the contract, use the following command:

cargo build --target wasm32-unknown-unknown --profile release-with-logs
Enter fullscreen mode Exit fullscreen mode

This should output a .wasm file in the ../target directory:

../target/wasm32-unknown-unknown/release-with-logs/soroban_logging_contract.wasm
Enter fullscreen mode Exit fullscreen mode

Invoking The Contract

To invoke the hello function of the contract, use the following command with Soroban-CLI:

soroban contract invoke \
    --wasm ../target/wasm32-unknown-unknown/release-with-logs/soroban_logging_contract.wasm \
    --id 1 \
    -- \
    hello \
    --to world
Enter fullscreen mode Exit fullscreen mode

You should see the following output:

null
#0: debug: Hello Symbol(world)
Enter fullscreen mode Exit fullscreen mode

Conclusion

So logging is a useful development/testing tool, and leaving appropriate log statements in contracts can provide transparency, but logs do not impact actual contract deployments. The log! macro provides a simple way to log information from your Soroban contracts. Stay tuned for more post in this "Soroban Contracts 101" Series where we will dive deeper into Soroban Contracts and their functionalities.

Top comments (0)