Soroban Contracts 101 : Logging
Tags: soroban, sorobanathon, stellar, smartcontract
Published: 2023-03-17 21:36:34

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](https://github.com/yuzurush/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:

```rust
log!(&env, "Count is: {}", count);
```
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
```rust
#![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);
    }
}
```
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

```rust
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"));
}
```
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
```
If the tests are successful, you should see an output similar to:
```
running 1 test
Hello Symbol(Dev)
test test::test ... ok
```

##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 : 

```rust
[profile.release-with-logs]
inherits = "release"
debug-assertions = true
```

To build the contract, use the following command:
```
cargo build --target wasm32-unknown-unknown --profile release-with-logs
```
This should output a .wasm file in the ../target directory:
```
../target/wasm32-unknown-unknown/release-with-logs/soroban_logging_contract.wasm
```

##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
```
You should see the following output:

```
null
#0: debug: Hello Symbol(world)
```

##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.