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

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

// 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, 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:

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

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:

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 – Implements FrontendLoggingLayer that converts tracing events into ExtendedLogRecord and emits them via app_handle.emit("log-record")
  • src/LogContext.tsx – Sets up the Tauri listener for "log-record" and provides the collected logs through a React context
  • 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 that emits structured log records via AppHandle.emit
  • The React frontend listens for these events in 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. 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, 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →