pondrs 0.2.5

A pipeline execution library
Documentation
# Built-in Hooks

pondrs provides two built-in hook implementations.

## `LoggingHook`

*Requires the `std` feature.*

Logs pipeline and node lifecycle events using the `log` crate, with automatic timing:

```rust,ignore
use pondrs::hooks::LoggingHook;

App::new(catalog, params)
    .with_hooks((LoggingHook::new(),))
    .execute(pipeline)?;
```

Output (with `env_logger` at `info` level):

```text
[INFO] [pipeline] processing - starting
[INFO] [node] clean - starting
[INFO] [node] clean - completed (12.3ms)
[INFO] [node] transform - starting
[INFO] [node] transform - completed (5.1ms)
[INFO] [pipeline] processing - completed (17.8ms)
```

At `debug` level, dataset load/save events are also logged:

```text
[DEBUG]   loading readings
[DEBUG]   loaded readings (8.2ms)
[DEBUG]   saving summary
[DEBUG]   saved summary (0.1ms)
```

`LoggingHook` uses a `TimingTracker` internally to measure durations between before/after pairs.

## `VizHook`

*Requires the `viz` feature.*

Posts live execution events to a running viz server via HTTP. This enables the interactive visualization to show real-time node status during `app run`:

```rust,ignore
use pondrs::viz::VizHook;

App::new(catalog, params)
    .with_hooks((LoggingHook::new(), VizHook::new("http://localhost:8080".into())))
    .execute(pipeline)?;
```

The typical workflow is:

1. Start the viz server: `my_app viz --port 8080`
2. In another terminal, run the pipeline with `VizHook` attached

`VizHook` is **fire-and-forget** — it silently ignores HTTP errors, so a missing viz server won't crash your pipeline. It tracks:

- Node start/end/error events
- Dataset load/save durations

Each event is posted as a `VizEvent` to `POST /api/status`, which the viz server broadcasts to connected WebSocket clients.

## Combining hooks

Hooks compose as tuples:

```rust,ignore
.with_hooks((
    LoggingHook::new(),
    VizHook::new("http://localhost:8080".into()),
    my_custom_hook,
))
```

Each hook receives every event independently. Order in the tuple determines call order, but hooks should not depend on ordering.