# How iloader Forwards Logs to the Frontend: A Tauri Event System Deep Dive

> Discover how iloader forwards logs to the frontend using Tauri events. Learn about the custom FrontendLoggingLayer and its role in streaming Rust backend logs to your React app.

- Repository: [Nicholas Sharp/iloader](https://github.com/nab138/iloader)
- Tags: deep-dive
- Published: 2026-09-13

---

**iloader uses Tauri's event system to stream log records from the Rust backend to the React frontend via a custom `FrontendLoggingLayer` that emits `"log-record"` events consumed by a React context.**

The nab138/iloader repository implements a real-time log forwarding pipeline that bridges Rust's tracing ecosystem with a React user interface. This architecture enables developers to monitor backend operations directly within the frontend application using Tauri's cross-process communication primitives.

## Backend Log Emission in Rust

The Rust backend leverages `tracing_subscriber` to intercept log events and forward them through Tauri's event bus.

### FrontendLoggingLayer Implementation

In [`src-tauri/src/logging.rs`](https://github.com/nab138/iloader/blob/main/src-tauri/src/logging.rs), the `FrontendLoggingLayer` struct implements the `tracing_subscriber::Layer` trait. This layer acts as an interceptor for every tracing event generated by the application. When a log event occurs, the layer constructs an `ExtendedLogRecord` containing the log level, message, target module, and timestamp.

### Emitting Events via AppHandle

The layer forwards structured log data to the frontend using Tauri's `AppHandle.emit` method. According to the iloader source code, the specific event name **`"log-record"`** broadcasts the serialized record:

```rust
// src-tauri/src/logging.rs
let _ = self.app_handle.emit("log-record", &record);

```

This single call transmits the `ExtendedLogRecord` across the Tauri boundary, making it available to all registered frontend listeners.

## Frontend Log Consumption in React

The React application consumes these events through a dedicated context provider that manages log state and subscription lifecycle.

### Setting Up the Event Listener

In [`src/LogContext.tsx`](https://github.com/nab138/iloader/blob/main/src/LogContext.tsx), the application imports `listen` from `@tauri-apps/api/event` and registers a type-safe listener for the `"log-record"` event. The listener callback appends each incoming payload to a stateful array:

```tsx
// src/LogContext.tsx
unlistenRef.current = await listen<ExtendedLogRecord>("log-record", (event) => {
  setLogs((prevLogs) => [...prevLogs, event.payload]);
});

```

The `unlistenRef` preserves the cleanup function to prevent memory leaks when the component unmounts.

### Providing Logs via React Context

The `LogContext` exposes the accumulated logs through a custom hook. Any component calling `useLogs()` receives the live array of `ExtendedLogRecord` objects. For example, [`src/components/OperationView.tsx`](https://github.com/nab138/iloader/blob/main/src/components/OperationView.tsx) renders these logs to display real-time backend activity.

## Complete Log Flow Example

To generate a log entry that appears in the frontend, use the standard tracing macros in Rust:

```rust
use tracing::info;

// Within any Tauri command
info!("Device discovery started");

```

The `info!` macro triggers the `FrontendLoggingLayer`, which packages the message into an `ExtendedLogRecord` and emits it via `app_handle.emit("log-record")`.

On the frontend, consume the stream using the context hook:

```tsx
import { useLogs } from "./LogContext";

function LogViewer() {
  const logs = useLogs();

  return (
    <pre>
      {logs.map((log, i) => (
        <div key={i}>
          [{log.timestamp}] {log.level}: {log.message}
        </div>
      ))}
    </pre>
  );
}

```

This component automatically re-renders whenever the backend emits a new log record.

## Key Implementation Files

- **[`src-tauri/src/logging.rs`](https://github.com/nab138/iloader/blob/main/src-tauri/src/logging.rs)** – Implements `FrontendLoggingLayer` that converts tracing events into `ExtendedLogRecord` and emits them via `app_handle.emit("log-record")`
- **[`src/LogContext.tsx`](https://github.com/nab138/iloader/blob/main/src/LogContext.tsx)** – Sets up the Tauri listener for `"log-record"` and provides the collected logs through a React context
- **[`src/components/OperationView.tsx`](https://github.com/nab138/iloader/blob/main/src/components/OperationView.tsx)** – Example consumer that uses `useLogs()` to render log output in the UI

## Summary

- **iloader forwards logs** using Tauri's event system with the `"log-record"` event name
- The **Rust backend** implements a custom `tracing_subscriber::Layer` in [`logging.rs`](https://github.com/nab138/iloader/blob/main/logging.rs) that emits structured log records via `AppHandle.emit`
- The **React frontend** listens for these events in [`LogContext.tsx`](https://github.com/nab138/iloader/blob/main/LogContext.tsx) using `@tauri-apps/api/event` and stores them in React state
- Components access logs through the **`useLogs()`** hook provided by `LogContext`
- The pipeline uses the **`ExtendedLogRecord`** struct to transfer timestamp, level, message, and target metadata

## Frequently Asked Questions

### What Tauri API does iloader use to forward logs from Rust to the frontend?

iloader uses the **`AppHandle.emit`** method with the event name `"log-record"` to transmit log data from the Rust backend to the frontend. This API is part of Tauri's event system and enables one-way communication from backend to frontend without requiring an explicit command invocation.

### How does the React frontend receive logs in iloader?

The frontend uses the **`listen`** function from `@tauri-apps/api/event` to register a callback for the `"log-record"` event in [`src/LogContext.tsx`](https://github.com/nab138/iloader/blob/main/src/LogContext.tsx). This listener receives typed payloads of `ExtendedLogRecord` and appends them to a React state array, which is then exposed via the `useLogs()` context hook.

### What information does iloader include in the forwarded log records?

Each log record is encapsulated in an **`ExtendedLogRecord`** struct that includes the log level (INFO, WARN, ERROR, etc.), the message content, the target module path, and a timestamp. This structure provides complete context for each backend log entry displayed in the frontend.

### Can I filter log levels in the iloader frontend?

While the provided source code shows the basic forwarding mechanism in [`LogContext.tsx`](https://github.com/nab138/iloader/blob/main/LogContext.tsx), the React context stores all received logs in a single array. You can implement filtering by applying array methods like `.filter()` to the `logs` array returned by `useLogs()` based on the `level` property of each `ExtendedLogRecord`.