Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Execution Tracing

The Forester tracer records a tick-by-tick log of node evaluations as the behavior tree runs. It captures node IDs, tick results, node state parameters, and any custom messages emitted by actions — making it the primary tool for debugging and post-execution analysis.


Reading Trace Output

Each trace line follows the format:

[tick]  node_id : Status(parameters...)
  • [tick]: The current tick number.
  • Indent: Reflects nesting depth in the tree.
  • node_id: Unique integer ID of the node being evaluated.
  • Status(...): Result state (Running, Success, Failure) with relevant parameters (cursor position, child count, key-value pairs, etc.).

Example Trace

[1]  1 : Running(cursor=0,len=1)
[1]    2 : Running(cursor=0,len=3)
[1]      3 : Success(key=x,value=tick)
[1]    2 : Running(cursor=1,len=3)
[1]      4 : Success(name=tick)
[1]    2 : Running(cursor=2,len=3)
[1]      5 : Running(cursor=0,len=2)
[1]        6 : Success(k=a,i=1)
[1]      5 : Running(cursor=1,len=2)
[1]        7 : Running(cursor=0,len=2)
[1]          8 : Failure(key=x,expected=10,reason=1 != 10)
[1]        7 : Running(cursor=1,len=2)
[1]          9 : Running()
[2]  next tick
[2]    2 : Running(cursor=0,len=3)
[2]      3 : Success(key=x,value=tick)
...

Enabling the Tracer

Enable tracing in ForesterBuilder before running the engine:

#![allow(unused)]
fn main() {
use forester_rs::tracer::{Tracer, TracerConfiguration};
use forester_rs::runtime::builder::ForesterBuilder;

let mut fb = ForesterBuilder::from_file_system();
fb.main_file("main.tree".to_string());

// Default tracer (stdout output)
fb.tracer(Tracer::default());

// Configured tracer (output to file, custom indent)
fb.tracer(Tracer::create(TracerConfiguration {
    indent: 2,
    to_file: Some("output/main.trace".to_string()),
    time_format: None,
}));
}

Configuration Options

OptionTypeDescription
indentusizeNumber of spaces per nesting level in the trace output.
to_fileOption<String>If set, writes the trace to the specified file path instead of stdout.
time_formatOption<String>If set, prepends a formatted timestamp to each trace line.

Custom Trace Messages

Actions can emit custom messages inline within the trace output using ctx.trace(). This is useful for logging intermediate Blackboard values or action-specific diagnostic information:

import "std::actions"

impl tracked_action();

root main repeat(3) {
    tracked_action()
}
#![allow(unused)]
fn main() {
use forester_rs::runtime::action::{Impl, RtArgs, Tick, TickResult};
use forester_rs::runtime::context::TreeContextRef;

struct TrackedAction;

impl Impl for TrackedAction {
    fn tick(&self, args: RtArgs, ctx: TreeContextRef) -> Tick {
        let mut ctx = ctx.lock()?;
        
        // Read current counter from Blackboard
        let i = ctx.bb()
            .get("counter".to_string())?
            .and_then(|v| v.clone().as_int())
            .map(|v| v + 1)
            .unwrap_or(0);
        
        ctx.bb().put("counter".to_string(), RtValue::int(i))?;
        
        // Emit a custom trace message
        ctx.trace(format!("counter = {:?}", i));
        
        Ok(TickResult::success())
    }
}
}

This produces inline messages in the trace output:

[1]    2 : Running(len=1)
[1]      counter = 0
[1]      3 : Success()
[2]  next tick
[2]      counter = 1
[2]      3 : Success()
[3]  next tick
[3]      counter = 2
[3]      3 : Success()
[3]  1 : Success(cursor=0,len=1)

Accessing the Tracer via HTTP

When the engine HTTP server is running, the tracer output can be fetched or appended to at runtime:

# Print current trace
curl http://localhost:10000/tracer/print

# Append a custom event to the trace
curl -X POST http://localhost:10000/tracer/custom \
  -H "Content-Type: application/json" \
  -d '{"message": "external checkpoint reached"}'