How to Access and Interpret Logs for Diagnostics in Clash Verge Rev

To access and interpret logs for diagnostics in Clash Verge Rev, open the Logs page to view live WebSocket streams from the Mihomo core, filter entries by severity level (debug, info, warn, or error), and use the search bar to query specific payloads or timestamps.

Clash Verge Rev provides a comprehensive logging interface that aggregates runtime diagnostics from the underlying Mihomo core. Whether you are troubleshooting connection issues or monitoring proxy performance, understanding how to access and interpret logs for diagnostics in Clash Verge Rev is essential for effective network management.

Understanding the Log Architecture

The logging pipeline in Clash Verge Rev consists of three distinct layers that work together to deliver real-time diagnostics.

Log Settings and Preferences

User preferences are persisted in localStorage via the useClashLog hook located in src/hooks/use-clash-log.ts.

const defaultClashLog: IClashLog = {
  enable: true,
  logLevel: "info",
  logFilter: "all",
  logOrder: "asc",
};
export const useClashLog = () =>
  useLocalStorage<IClashLog>("clash-log", defaultClashLog, {
    serializer: JSON.stringify,
    deserializer: JSON.parse,
  });

This hook stores the enable toggle, logLevel (debug/info/warn/error), logFilter, and logOrder settings under the localStorage key clash-log.

Live Log Streaming and Retrieval

The useLogData hook in src/hooks/use-log-data.ts manages the WebSocket connection to Mihomo and buffers incoming messages.

Step Implementation Detail
Subscription Key Builds getClashLog-${date} topic based on logLevel and enable settings
WebSocket Connection Calls MihomoWebSocket.connect_logs(logLevel) to establish the stream
Buffering Incoming messages are buffered and flushed every 50 ms (FLUSH_DELAY_MS = 50) to prevent UI churn
Parsing Raw JSON messages are parsed into ILogItem objects; entries not matching the selected logLevel are filtered out
Timestamping Human-readable timestamps are added using dayjs in MM-DD HH:mm:ss format
Initial Load On first WS connection, the hook calls getClashLogs() (Tauri command) to fetch historic logs from the core's filesystem
Reactivity Whenever logLevel changes, the subscription refreshes automatically

Historic Log Parsing

The getClashLogs function in [src/services/cmds.ts](https://github.com/clash-verge-rev/clash-verge-rev/blob/dev/src/services/cmds.ts#L223-L244) parses raw log files from the Mihomo core using two regex patterns:

export async function getClashLogs() {
  const regex = /time="(.+?)"\s+level=(.+?)\s+msg="(.+?)"/;
  const newRegex = /(.+?)\s+(.+?)\s+(.+)/;
  const logs = await invoke<string[]>("get_clash_logs");

  return logs.reduce<ILogItem[]>((acc, log) => {
    const result = log.match(regex);
    if (result) {
      const [_, _time, type, payload] = result;
      const time = dayjs(_time).format("MM-DD HH:mm:ss");
      acc.push({ time, type, payload });
      return acc;
    }
    const result2 = log.match(newRegex);
    if (result2) {
      const [_, time, type, payload] = result2;
      acc.push({ time, type, payload });
    }
    return acc;
  }, []);
}

This function handles both legacy and new log formats, normalizing them into structured objects with time, type, and payload properties.

The LogPage component in src/pages/logs.tsx provides the diagnostic interface with several interactive features.

Filtering and Searching

The UI applies client-side filtering on the array returned by useLogData:

const filteredLogs = useMemo(() => {
  return logData.filter((data) => {
    const searchText = `${data.time || ""} ${data.type} ${data.payload}`.toLowerCase();
    const matchesSearch = match(searchText);
    return (logState == "all" ? true : data.type.includes(logState)) && matchesSearch;
  });
}, [logData, logState, match]);
  • Level Filter: Select all, debug, info, warn, or error to show only entries of that severity.
  • Search: The search box queries across timestamps, log types, and message payloads simultaneously.

Sorting and Display

  • Order Toggle: Switch between ascending and descending chronological order using the logOrder setting from useClashLog.
  • Virtualized Rendering: The interface uses react-virtuoso to render only visible log rows, maintaining performance even with thousands of entries.
  • Clear History: The clear button calls refreshGetClashLog(true), which resets the SWR cache and empties the displayed list without affecting stored files.

Programmatic Log Access

For advanced diagnostics or integration with external tools, you can interact with the logging system programmatically.

Fetching Raw Logs via Tauri Command

import { getClashLogs } from '@/services/cmds';

// Example: fetch and print the last 20 error-level logs
async function printRecentErrors() {
  const all = await getClashLogs();
  const errors = all.filter(l => l.type === 'error').slice(-20);
  errors.forEach(l => console.log(`[${l.time}] ${l.payload}`));
}
printRecentErrors();

Adjusting Log Verbosity at Runtime

import { useClashLog } from '@/hooks/use-clash-log';

// Switch to "debug" level to capture all diagnostics
const [, setClashLog] = useClashLog();
setClashLog(prev => ({ ...prev, logLevel: 'debug' }));

Subscribing to Real-Time Logs via WebSocket

import { MihomoWebSocket } from 'tauri-plugin-mihomo-api';

async function subscribeToLogs() {
  const ws = await MihomoWebSocket.connect_logs('info');
  ws.onMessage(msg => console.log('WS LOG →', msg));
}
subscribeToLogs();

Clearing the Log Buffer

import { useLogData } from '@/hooks/use-log-data';

const { refreshGetClashLog } = useLogData();
// Force reset of the SWR cache to wipe the UI list
refreshGetClashLog(true);

Key Files for Log Diagnostics

Understanding the source structure helps when extending or debugging the logging functionality:

File Purpose Location
use-clash-log.ts Manages localStorage preferences for log settings src/hooks/use-clash-log.ts
use-log-data.ts Handles WebSocket connections, buffering, and real-time data flow src/hooks/use-log-data.ts
cmds.ts Parses raw Mihomo log files into structured data src/services/cmds.ts (lines 223-244)
logs.tsx Main UI component with filtering, search, and virtualization src/pages/logs.tsx
log-item.tsx Renders individual log entry rows src/components/log/log-item.tsx

Summary

  • Three-layer architecture: Settings (use-clash-log.ts), data streaming (use-log-data.ts), and UI presentation (logs.tsx) work together to deliver diagnostics.
  • Real-time and historic data: WebSocket connections provide live logs with 50ms buffering, while getClashLogs() fetches persisted entries from the filesystem.
  • Flexible filtering: Client-side filtering supports severity levels (debug/info/warn/error), text search across timestamps and payloads, and ascending/descending sort order.
  • Programmatic access: Developers can invoke getClashLogs(), subscribe to WebSocket streams via MihomoWebSocket, or manipulate log settings through the useClashLog hook.

Frequently Asked Questions

How do I change the log verbosity level in Clash Verge Rev?

Navigate to the Logs page and use the level selector to switch between debug, info, warn, and error. This updates the logLevel property in useClashLog, which triggers a WebSocket resubscription to the Mihomo core with the new verbosity filter. Lower levels like "debug" capture all diagnostics, while "error" shows only critical failures.

Where are the log files stored on my system?

Clash Verge Rev retrieves historic logs via the Tauri command get_clash_logs, which reads files generated by the Mihomo core from the application's data directory. The exact filesystem path depends on your operating system (typically within the OS-specific app data folder), but you do not need to access these files directly since the UI and getClashLogs() function parse and display them automatically.

Why are my logs not updating in real-time?

Real-time updates require the enable setting to be true in useClashLog and an active WebSocket connection to the Mihomo core. If logs appear stale, verify that live logging is enabled in the UI settings. The system uses a 50ms buffer (FLUSH_DELAY_MS) to batch updates, so there is a brief delay between core events and UI rendering. If the connection drops, the hook automatically attempts to reconnect and fetch historic logs via getClashLogs().

Can I export logs from Clash Verge Rev for external analysis?

While the application does not include a built-in export button in the standard UI, you can programmatically retrieve structured log data using the getClashLogs() function from src/services/cmds.ts. This returns an array of ILogItem objects with time, type, and payload properties that you can serialize to JSON or CSV. For real-time export, subscribe to the WebSocket stream via MihomoWebSocket.connect_logs() and write incoming messages to a file.

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 →