Files
clash-verge-rev/src/services/global-log-service.ts
2025-10-18 16:11:42 +08:00

192 lines
5.1 KiB
TypeScript

// 全局日志服务,使应用在任何页面都能收集日志
import { create } from "zustand";
import {
fetchLogsViaIPC,
stopLogsStreaming,
clearLogs as clearLogsIPC,
} from "@/services/ipc-log-service";
// 最大日志数量
const MAX_LOG_NUM = 1000;
export type LogLevel = "debug" | "info" | "warning" | "error" | "all";
interface ILogItem {
time?: string;
type: string;
payload: string;
[key: string]: any;
}
interface GlobalLogStore {
logs: ILogItem[];
enabled: boolean;
isConnected: boolean;
currentLevel: LogLevel;
setEnabled: (enabled: boolean) => void;
setCurrentLevel: (level: LogLevel) => void;
clearLogs: () => void;
appendLog: (log: ILogItem) => void;
setLogs: (logs: ILogItem[]) => void;
}
// 创建全局状态存储
export const useGlobalLogStore = create<GlobalLogStore>((set) => ({
logs: [],
enabled: false,
isConnected: false,
currentLevel: "info",
setEnabled: (enabled) => set({ enabled }),
setCurrentLevel: (currentLevel) => set({ currentLevel }),
clearLogs: () => set({ logs: [] }),
appendLog: (log: ILogItem) =>
set((state) => {
const newLogs =
state.logs.length >= MAX_LOG_NUM
? [...state.logs.slice(1), log]
: [...state.logs, log];
return { logs: newLogs };
}),
setLogs: (logs: ILogItem[]) => set({ logs }),
}));
// IPC 日志获取函数
export const fetchLogsViaIPCPeriodically = async () => {
try {
const logs = await fetchLogsViaIPC();
useGlobalLogStore.getState().setLogs(logs);
console.log(`[GlobalLog-IPC] 成功获取 ${logs.length} 条日志`);
} catch (error) {
console.error("[GlobalLog-IPC] 获取日志失败:", error);
}
};
// 初始化全局日志服务 (仅IPC模式)
let ipcPollingInterval: ReturnType<typeof setInterval> | null = null;
let isInitializing = false; // 添加初始化标志
export const initGlobalLogService = (
enabled: boolean = false,
logLevel: LogLevel = "info",
) => {
// 防止重复初始化
if (isInitializing) {
console.log("[GlobalLog-IPC] 正在初始化中,跳过重复调用");
return;
}
const { setEnabled, setCurrentLevel } = useGlobalLogStore.getState();
// 更新启用状态
setEnabled(enabled);
setCurrentLevel(logLevel);
// 如果不启用,则不初始化
if (!enabled) {
clearIpcPolling();
useGlobalLogStore.setState({ isConnected: false });
return;
}
isInitializing = true;
// 使用IPC流式模式
console.log("[GlobalLog-IPC] 启用IPC流式日志服务");
// 启动流式监控
// startLogsStreaming(logLevel);
// 立即获取一次日志
fetchLogsViaIPCPeriodically();
// 设置定期轮询来同步流式缓存的数据
clearIpcPolling();
ipcPollingInterval = setInterval(() => {
fetchLogsViaIPCPeriodically();
}, 1000); // 每1秒同步一次流式缓存
// 设置连接状态
useGlobalLogStore.setState({ isConnected: true });
isInitializing = false;
};
// 清除IPC轮询
const clearIpcPolling = () => {
if (ipcPollingInterval) {
clearInterval(ipcPollingInterval);
ipcPollingInterval = null;
console.log("[GlobalLog-IPC] 轮询已停止");
}
};
// 停止日志监控 (仅IPC模式)
export const stopGlobalLogMonitoring = async () => {
clearIpcPolling();
isInitializing = false; // 重置初始化标志
// 调用后端停止监控
await stopLogsStreaming();
useGlobalLogStore.setState({ isConnected: false });
console.log("[GlobalLog-IPC] 日志监控已停止");
};
// 关闭全局日志连接 (仅IPC模式) - 保持向后兼容
export const closeGlobalLogConnection = async () => {
await stopGlobalLogMonitoring();
};
// 切换日志级别 (仅IPC模式)
export const changeLogLevel = (level: LogLevel) => {
const { enabled } = useGlobalLogStore.getState();
useGlobalLogStore.setState({ currentLevel: level });
// 如果正在初始化,则跳过,避免重复启动
if (isInitializing) {
console.log("[GlobalLog-IPC] 正在初始化中,跳过级别变更流启动");
return;
}
if (enabled) {
// IPC流式模式下重新启动监控
// startLogsStreaming(level);
fetchLogsViaIPCPeriodically();
}
};
// 切换启用状态 (仅IPC模式)
export const toggleLogEnabled = async () => {
const { enabled, currentLevel } = useGlobalLogStore.getState();
const newEnabled = !enabled;
useGlobalLogStore.setState({ enabled: newEnabled });
if (newEnabled) {
// IPC模式下直接启动
initGlobalLogService(newEnabled, currentLevel);
} else {
await stopGlobalLogMonitoring();
}
};
// 获取日志清理函数 - 只清理前端日志,不停止监控
export const clearGlobalLogs = () => {
useGlobalLogStore.getState().clearLogs();
// 同时清理后端缓存的日志,但不停止监控
clearLogsIPC();
};
// 自定义钩子,用于获取过滤后的日志数据
export const useGlobalLogData = (logLevel: LogLevel = "info") => {
const logs = useGlobalLogStore((state) => state.logs);
// 根据当前选择的日志等级过滤日志
if (logLevel === "info") {
return logs;
} else {
return logs.filter((log) => log.type.toLowerCase() === logLevel);
}
};