mirror of
https://gh.catmak.name/https://github.com/mihomo-party-org/mihomo-party
synced 2026-02-10 19:50:28 +08:00
feat: separate app logs from core logs
This commit is contained in:
parent
a8f8cd0fd3
commit
d030a8722d
@ -1,5 +1,6 @@
|
||||
import { getAppConfig } from './app'
|
||||
import { addOverrideItem, removeOverrideItem, getOverrideItem } from './override'
|
||||
import { overrideLogger } from '../utils/logger'
|
||||
|
||||
const SMART_OVERRIDE_ID = 'smart-core-override'
|
||||
|
||||
@ -237,7 +238,7 @@ export async function createSmartOverride(): Promise<void> {
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to create Smart override:', error)
|
||||
await overrideLogger.error('Failed to create Smart override', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
@ -252,7 +253,7 @@ export async function removeSmartOverride(): Promise<void> {
|
||||
await removeOverrideItem(SMART_OVERRIDE_ID)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to remove Smart override:', error)
|
||||
await overrideLogger.error('Failed to remove Smart override', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { ChildProcess, exec, execFile, spawn } from 'child_process'
|
||||
import {
|
||||
dataDir,
|
||||
logPath,
|
||||
coreLogPath,
|
||||
mihomoCoreDir,
|
||||
mihomoCorePath,
|
||||
mihomoProfileWorkDir,
|
||||
@ -41,6 +41,7 @@ import { uploadRuntimeConfig } from '../resolve/gistApi'
|
||||
import { startMonitor } from '../resolve/trafficMonitor'
|
||||
import { safeShowErrorBox } from '../utils/init'
|
||||
import i18next from '../../shared/i18n'
|
||||
import { managerLogger } from '../utils/logger'
|
||||
|
||||
chokidar.watch(path.join(mihomoCoreDir(), 'meta-update'), {}).on('unlinkDir', async () => {
|
||||
try {
|
||||
@ -96,13 +97,12 @@ export async function startCore(detached = false): Promise<Promise<void>[]> {
|
||||
try {
|
||||
await setPublicDNS()
|
||||
} catch (error) {
|
||||
await writeFile(logPath(), `[Manager]: set dns failed, ${error}`, {
|
||||
flag: 'a'
|
||||
})
|
||||
await managerLogger.error('set dns failed', error)
|
||||
}
|
||||
}
|
||||
const stdout = createWriteStream(logPath(), { flags: 'a' })
|
||||
const stderr = createWriteStream(logPath(), { flags: 'a' })
|
||||
// 内核日志输出到独立的 core-日期.log 文件
|
||||
const stdout = createWriteStream(coreLogPath(), { flags: 'a' })
|
||||
const stderr = createWriteStream(coreLogPath(), { flags: 'a' })
|
||||
const env = {
|
||||
DISABLE_LOOPBACK_DETECTOR: String(disableLoopbackDetector),
|
||||
DISABLE_EMBED_CA: String(disableEmbedCA),
|
||||
@ -128,11 +128,9 @@ export async function startCore(detached = false): Promise<Promise<void>[]> {
|
||||
})
|
||||
}
|
||||
child.on('close', async (code, signal) => {
|
||||
await writeFile(logPath(), `[Manager]: Core closed, code: ${code}, signal: ${signal}\n`, {
|
||||
flag: 'a'
|
||||
})
|
||||
await managerLogger.info(`Core closed, code: ${code}, signal: ${signal}`)
|
||||
if (retry) {
|
||||
await writeFile(logPath(), `[Manager]: Try Restart Core\n`, { flag: 'a' })
|
||||
await managerLogger.info('Try Restart Core')
|
||||
retry--
|
||||
await restartCore()
|
||||
} else {
|
||||
@ -194,9 +192,7 @@ export async function stopCore(force = false): Promise<void> {
|
||||
await recoverDNS()
|
||||
}
|
||||
} catch (error) {
|
||||
await writeFile(logPath(), `[Manager]: recover dns failed, ${error}`, {
|
||||
flag: 'a'
|
||||
})
|
||||
await managerLogger.error('recover dns failed', error)
|
||||
}
|
||||
|
||||
if (child) {
|
||||
@ -214,9 +210,7 @@ export async function restartCore(): Promise<void> {
|
||||
await startCore()
|
||||
} catch (e) {
|
||||
// 记录错误到日志而不是显示阻塞对话框
|
||||
await writeFile(logPath(), `[Manager]: restart core failed, ${e}\n`, {
|
||||
flag: 'a'
|
||||
})
|
||||
await managerLogger.error('restart core failed', e)
|
||||
// 重新抛出错误,让调用者处理
|
||||
throw e
|
||||
}
|
||||
@ -260,12 +254,12 @@ async function checkProfile(): Promise<void> {
|
||||
mihomoTestDir()
|
||||
], { env })
|
||||
} catch (error) {
|
||||
console.error('Profile check failed:', error)
|
||||
await managerLogger.error('Profile check failed', error)
|
||||
|
||||
if (error instanceof Error && 'stdout' in error) {
|
||||
const { stdout, stderr } = error as { stdout: string; stderr?: string }
|
||||
console.log('Profile check stdout:', stdout)
|
||||
console.log('Profile check stderr:', stderr)
|
||||
await managerLogger.info('Profile check stdout', stdout)
|
||||
await managerLogger.info('Profile check stderr', stderr)
|
||||
|
||||
const errorLines = stdout
|
||||
.split('\n')
|
||||
@ -377,15 +371,15 @@ export async function restartAsAdmin(): Promise<void> {
|
||||
command = `powershell -Command "Start-Process -FilePath '${escapedExePath}' -Verb RunAs"`
|
||||
}
|
||||
|
||||
console.log('Restarting as administrator with command:', command)
|
||||
await managerLogger.info('Restarting as administrator with command', command)
|
||||
|
||||
// 执行PowerShell命令
|
||||
exec(command, { windowsHide: true }, (error, _stdout, stderr) => {
|
||||
exec(command, { windowsHide: true }, async (error, _stdout, stderr) => {
|
||||
if (error) {
|
||||
console.error('PowerShell execution error:', error)
|
||||
console.error('stderr:', stderr)
|
||||
await managerLogger.error('PowerShell execution error', error)
|
||||
await managerLogger.error('stderr', stderr)
|
||||
} else {
|
||||
console.log('PowerShell command executed successfully')
|
||||
await managerLogger.info('PowerShell command executed successfully')
|
||||
}
|
||||
})
|
||||
|
||||
@ -394,7 +388,7 @@ export async function restartAsAdmin(): Promise<void> {
|
||||
const { app } = await import('electron')
|
||||
app.quit()
|
||||
} catch (error) {
|
||||
console.error('Failed to restart as administrator:', error)
|
||||
await managerLogger.error('Failed to restart as administrator', error)
|
||||
throw new Error(`Failed to restart as administrator: ${error}`)
|
||||
}
|
||||
}
|
||||
@ -437,7 +431,7 @@ export async function requestTunPermissions(): Promise<void> {
|
||||
|
||||
export async function checkAdminRestartForTun(): Promise<void> {
|
||||
if (process.argv.includes('--admin-restart-for-tun')) {
|
||||
console.log('Detected admin restart for TUN mode, auto-enabling TUN...')
|
||||
await managerLogger.info('Detected admin restart for TUN mode, auto-enabling TUN...')
|
||||
|
||||
try {
|
||||
if (process.platform === 'win32') {
|
||||
@ -446,17 +440,17 @@ export async function checkAdminRestartForTun(): Promise<void> {
|
||||
await patchControledMihomoConfig({ tun: { enable: true }, dns: { enable: true } })
|
||||
await restartCore()
|
||||
|
||||
console.log('TUN mode auto-enabled after admin restart')
|
||||
await managerLogger.info('TUN mode auto-enabled after admin restart')
|
||||
|
||||
const { mainWindow } = await import('../index')
|
||||
mainWindow?.webContents.send('controledMihomoConfigUpdated')
|
||||
ipcMain.emit('updateTrayMenu')
|
||||
} else {
|
||||
console.warn('Admin restart detected but no admin privileges found')
|
||||
await managerLogger.warn('Admin restart detected but no admin privileges found')
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to auto-enable TUN after admin restart:', error)
|
||||
await managerLogger.error('Failed to auto-enable TUN after admin restart', error)
|
||||
}
|
||||
} else {
|
||||
// 检查TUN配置与权限的匹配
|
||||
@ -475,7 +469,7 @@ export async function validateTunPermissionsOnStartup(): Promise<void> {
|
||||
const hasPermissions = await checkMihomoCorePermissions()
|
||||
|
||||
if (!hasPermissions) {
|
||||
console.warn('TUN is enabled but insufficient permissions detected, auto-disabling TUN...')
|
||||
await managerLogger.warn('TUN is enabled but insufficient permissions detected, auto-disabling TUN...')
|
||||
|
||||
await patchControledMihomoConfig({ tun: { enable: false } })
|
||||
|
||||
@ -483,12 +477,12 @@ export async function validateTunPermissionsOnStartup(): Promise<void> {
|
||||
mainWindow?.webContents.send('controledMihomoConfigUpdated')
|
||||
ipcMain.emit('updateTrayMenu')
|
||||
|
||||
console.log('TUN auto-disabled due to insufficient permissions')
|
||||
await managerLogger.info('TUN auto-disabled due to insufficient permissions')
|
||||
} else {
|
||||
console.log('TUN permissions validated successfully')
|
||||
await managerLogger.info('TUN permissions validated successfully')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to validate TUN permissions on startup:', error)
|
||||
await managerLogger.error('Failed to validate TUN permissions on startup', error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@ import { startMonitor } from './resolve/trafficMonitor'
|
||||
import { showFloatingWindow } from './resolve/floatingWindow'
|
||||
import { initI18n } from '../shared/i18n'
|
||||
import i18next from 'i18next'
|
||||
import { logger } from './utils/logger'
|
||||
|
||||
// 错误处理
|
||||
function showSafeErrorBox(titleKey: string, message: string): void {
|
||||
@ -198,7 +199,7 @@ app.whenReady().then(async () => {
|
||||
try {
|
||||
await showFloatingWindow()
|
||||
} catch (error) {
|
||||
console.error('Failed to create floating window on startup:', error)
|
||||
await logger.error('Failed to create floating window on startup', error)
|
||||
}
|
||||
}
|
||||
if (!disableTray) {
|
||||
|
||||
@ -12,6 +12,7 @@ import {
|
||||
subStoreDir,
|
||||
themesDir
|
||||
} from '../utils/dirs'
|
||||
import { systemLogger } from '../utils/logger'
|
||||
|
||||
export async function webdavBackup(): Promise<boolean> {
|
||||
const { createClient } = await import('webdav/dist/node/index.js')
|
||||
@ -75,7 +76,7 @@ export async function webdavBackup(): Promise<boolean> {
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to clean up old backup files:', error)
|
||||
await systemLogger.error('Failed to clean up old backup files', error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -5,33 +5,13 @@ import { join } from 'path'
|
||||
import { getAppConfig, patchAppConfig } from '../config'
|
||||
import { applyTheme } from './theme'
|
||||
import { buildContextMenu, showTrayIcon } from './tray'
|
||||
import { writeFile } from 'fs/promises'
|
||||
import { logDir } from '../utils/dirs'
|
||||
import path from 'path'
|
||||
import { floatingWindowLogger } from '../utils/logger'
|
||||
|
||||
export let floatingWindow: BrowserWindow | null = null
|
||||
|
||||
// 悬浮窗日志记录
|
||||
// 悬浮窗日志记录 - 使用统一的日志工具
|
||||
async function logFloatingWindow(message: string, error?: any): Promise<void> {
|
||||
try {
|
||||
const timestamp = new Date().toISOString()
|
||||
const logMessage = error
|
||||
? `[${timestamp}] [FloatingWindow] ${message}: ${error}\n`
|
||||
: `[${timestamp}] [FloatingWindow] ${message}\n`
|
||||
|
||||
const logPath = path.join(logDir(), 'floating-window.log')
|
||||
await writeFile(logPath, logMessage, { flag: 'a' })
|
||||
|
||||
if (error) {
|
||||
console.error(`[FloatingWindow] ${message}:`, error)
|
||||
} else {
|
||||
console.log(`[FloatingWindow] ${message}`)
|
||||
}
|
||||
} catch (logError) {
|
||||
|
||||
console.error('[FloatingWindow] Failed to write log:', logError)
|
||||
console.log(`[FloatingWindow] Original message: ${message}`, error)
|
||||
}
|
||||
await floatingWindowLogger.log(message, error)
|
||||
}
|
||||
|
||||
async function createFloatingWindow(): Promise<void> {
|
||||
|
||||
@ -11,6 +11,7 @@ import { nativeImage } from 'electron'
|
||||
import express from 'express'
|
||||
import axios from 'axios'
|
||||
import AdmZip from 'adm-zip'
|
||||
import { systemLogger } from '../utils/logger'
|
||||
|
||||
export let pacPort: number
|
||||
export let subStorePort: number
|
||||
@ -168,7 +169,6 @@ export async function downloadSubStore(): Promise<void> {
|
||||
)
|
||||
await writeFile(tempBackendPath, Buffer.from(backendRes.data))
|
||||
// 下载前端文件
|
||||
const tempFrontendDir = path.join(tempDir, 'dist')
|
||||
const frontendRes = await axios.get(
|
||||
'https://github.com/sub-store-org/Sub-Store-Front-End/releases/latest/download/dist.zip',
|
||||
{
|
||||
@ -192,7 +192,7 @@ export async function downloadSubStore(): Promise<void> {
|
||||
await cp(path.join(tempDir, 'dist'), frontendDir, { recursive: true })
|
||||
await rm(tempDir, { recursive: true })
|
||||
} catch (error) {
|
||||
console.error('substore.downloadFailed:', error)
|
||||
await systemLogger.error('substore.downloadFailed', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,14 +22,15 @@ import { triggerSysProxy } from '../sys/sysproxy'
|
||||
import { quitWithoutCore, restartCore, checkMihomoCorePermissions, requestTunPermissions, restartAsAdmin } from '../core/manager'
|
||||
import { floatingWindow, triggerFloatingWindow } from './floatingWindow'
|
||||
import { t } from 'i18next'
|
||||
import { trayLogger } from '../utils/logger'
|
||||
|
||||
export let tray: Tray | null = null
|
||||
|
||||
export const buildContextMenu = async (): Promise<Menu> => {
|
||||
// 添加调试日志
|
||||
console.log('Current translation for tray.showWindow:', t('tray.showWindow'))
|
||||
console.log('Current translation for tray.hideFloatingWindow:', t('tray.hideFloatingWindow'))
|
||||
console.log('Current translation for tray.showFloatingWindow:', t('tray.showFloatingWindow'))
|
||||
await trayLogger.debug('Current translation for tray.showWindow', t('tray.showWindow'))
|
||||
await trayLogger.debug('Current translation for tray.hideFloatingWindow', t('tray.hideFloatingWindow'))
|
||||
await trayLogger.debug('Current translation for tray.showFloatingWindow', t('tray.showFloatingWindow'))
|
||||
|
||||
const { mode, tun } = await getControledMihomoConfig()
|
||||
const {
|
||||
@ -187,7 +188,7 @@ export const buildContextMenu = async (): Promise<Menu> => {
|
||||
try {
|
||||
await restartAsAdmin()
|
||||
} catch (error) {
|
||||
console.error('Failed to restart as admin from tray:', error)
|
||||
await trayLogger.error('Failed to restart as admin from tray', error)
|
||||
item.checked = false
|
||||
ipcMain.emit('updateTrayMenu')
|
||||
return
|
||||
@ -196,7 +197,7 @@ export const buildContextMenu = async (): Promise<Menu> => {
|
||||
try {
|
||||
await requestTunPermissions()
|
||||
} catch (error) {
|
||||
console.error('Failed to grant TUN permissions from tray:', error)
|
||||
await trayLogger.error('Failed to grant TUN permissions from tray', error)
|
||||
item.checked = false
|
||||
ipcMain.emit('updateTrayMenu')
|
||||
return
|
||||
@ -204,7 +205,7 @@ export const buildContextMenu = async (): Promise<Menu> => {
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Permission check failed in tray:', error)
|
||||
await trayLogger.warn('Permission check failed in tray', error)
|
||||
}
|
||||
|
||||
await patchControledMihomoConfig({ tun: { enable }, dns: { enable: true } })
|
||||
@ -418,13 +419,13 @@ export async function closeTrayIcon(): Promise<void> {
|
||||
}
|
||||
|
||||
export async function showDockIcon(): Promise<void> {
|
||||
if (process.platform === 'darwin' && !app.dock.isVisible()) {
|
||||
if (process.platform === 'darwin' && app.dock && !app.dock.isVisible()) {
|
||||
await app.dock.show()
|
||||
}
|
||||
}
|
||||
|
||||
export async function hideDockIcon(): Promise<void> {
|
||||
if (process.platform === 'darwin' && app.dock.isVisible()) {
|
||||
if (process.platform === 'darwin' && app.dock && app.dock.isVisible()) {
|
||||
app.dock.hide()
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ import { resourcesFilesDir } from '../utils/dirs'
|
||||
import { net } from 'electron'
|
||||
import axios from 'axios'
|
||||
import fs from 'fs'
|
||||
import { proxyLogger } from '../utils/logger'
|
||||
|
||||
let defaultBypass: string[]
|
||||
let triggerSysProxyTimer: NodeJS.Timeout | null = null
|
||||
@ -175,7 +176,7 @@ async function requestSocketRecreation(): Promise<void> {
|
||||
// Wait a bit for socket recreation
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
} catch (error) {
|
||||
console.log('Failed to send signal to helper:', error)
|
||||
await proxyLogger.error('Failed to send signal to helper', error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
@ -197,16 +198,16 @@ async function helperRequest(requestFn: () => Promise<unknown>, maxRetries = 1):
|
||||
(error as Error).message?.includes('connect ECONNREFUSED') ||
|
||||
(error as Error).message?.includes('ENOENT'))) {
|
||||
|
||||
console.log(`Helper request failed (attempt ${attempt + 1}), checking socket file...`)
|
||||
|
||||
await proxyLogger.info(`Helper request failed (attempt ${attempt + 1}), checking socket file...`)
|
||||
|
||||
if (!isSocketFileExists()) {
|
||||
console.log('Socket file missing, requesting recreation...')
|
||||
await proxyLogger.info('Socket file missing, requesting recreation...')
|
||||
try {
|
||||
await requestSocketRecreation()
|
||||
console.log('Socket recreation requested, retrying...')
|
||||
await proxyLogger.info('Socket recreation requested, retrying...')
|
||||
continue
|
||||
} catch (signalError) {
|
||||
console.log('Failed to request socket recreation:', signalError)
|
||||
await proxyLogger.warn('Failed to request socket recreation', signalError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,12 +134,27 @@ export function logDir(): string {
|
||||
|
||||
export function logPath(): string {
|
||||
const date = new Date()
|
||||
const name = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`
|
||||
const year = date.getFullYear()
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(date.getDate()).padStart(2, '0')
|
||||
const name = `mihomo-party-${year}-${month}-${day}`
|
||||
return path.join(logDir(), `${name}.log`)
|
||||
}
|
||||
|
||||
export function substoreLogPath(): string {
|
||||
const date = new Date()
|
||||
const name = `sub-store-${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`
|
||||
const year = date.getFullYear()
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(date.getDate()).padStart(2, '0')
|
||||
const name = `sub-store-${year}-${month}-${day}`
|
||||
return path.join(logDir(), `${name}.log`)
|
||||
}
|
||||
|
||||
export function coreLogPath(): string {
|
||||
const date = new Date()
|
||||
const year = date.getFullYear()
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(date.getDate()).padStart(2, '0')
|
||||
const name = `core-${year}-${month}-${day}`
|
||||
return path.join(logDir(), `${name}.log`)
|
||||
}
|
||||
|
||||
@ -42,6 +42,7 @@ import {
|
||||
import { app, dialog } from 'electron'
|
||||
import { startSSIDCheck } from '../sys/ssid'
|
||||
import i18next from '../../shared/i18n'
|
||||
import { initLogger } from './logger'
|
||||
|
||||
// 安全错误处理
|
||||
export function safeShowErrorBox(titleKey: string, message: string): void {
|
||||
@ -115,7 +116,7 @@ async function initDirs(): Promise<void> {
|
||||
await mkdir(dir, { recursive: true })
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Failed to create directory ${dir}:`, error)
|
||||
await initLogger.error(`Failed to create directory ${dir}`, error)
|
||||
throw new Error(`Failed to create directory ${dir}: ${error}`)
|
||||
}
|
||||
}
|
||||
@ -136,7 +137,7 @@ async function initConfig(): Promise<void> {
|
||||
await writeFile(config.path, yaml.stringify(config.content))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Failed to create ${config.name} at ${config.path}:`, error)
|
||||
await initLogger.error(`Failed to create ${config.name} at ${config.path}`, error)
|
||||
throw new Error(`Failed to create ${config.name}: ${error}`)
|
||||
}
|
||||
}
|
||||
@ -163,7 +164,7 @@ async function initFiles(): Promise<void> {
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Failed to copy ${file}:`, error)
|
||||
await initLogger.error(`Failed to copy ${file}`, error)
|
||||
if (['country.mmdb', 'geoip.dat', 'geosite.dat'].includes(file)) {
|
||||
throw new Error(`Failed to copy critical file ${file}: ${error}`)
|
||||
}
|
||||
|
||||
108
src/main/utils/logger.ts
Normal file
108
src/main/utils/logger.ts
Normal file
@ -0,0 +1,108 @@
|
||||
import { writeFile } from 'fs/promises'
|
||||
import { logPath } from './dirs'
|
||||
|
||||
export type LogLevel = 'debug' | 'info' | 'warn' | 'error'
|
||||
|
||||
class Logger {
|
||||
private moduleName: string
|
||||
|
||||
constructor(moduleName: string) {
|
||||
this.moduleName = moduleName
|
||||
}
|
||||
|
||||
private formatTimestamp(): string {
|
||||
return new Date().toISOString()
|
||||
}
|
||||
|
||||
private formatLogMessage(level: LogLevel, message: string, error?: any): string {
|
||||
const timestamp = this.formatTimestamp()
|
||||
const errorStr = error ? `: ${error}` : ''
|
||||
return `[${timestamp}] [${level.toUpperCase()}] [${this.moduleName}] ${message}${errorStr}\n`
|
||||
}
|
||||
|
||||
private async writeToFile(level: LogLevel, message: string, error?: any): Promise<void> {
|
||||
try {
|
||||
const appLogPath = logPath()
|
||||
const logMessage = this.formatLogMessage(level, message, error)
|
||||
await writeFile(appLogPath, logMessage, { flag: 'a' })
|
||||
} catch (logError) {
|
||||
// 如果写入日志文件失败,仍然输出到控制台
|
||||
console.error(`[Logger] Failed to write to log file:`, logError)
|
||||
console.error(`[Logger] Original message: [${level.toUpperCase()}] [${this.moduleName}] ${message}`, error)
|
||||
}
|
||||
}
|
||||
|
||||
private logToConsole(level: LogLevel, message: string, error?: any): void {
|
||||
const prefix = `[${this.moduleName}] ${message}`
|
||||
|
||||
switch (level) {
|
||||
case 'debug':
|
||||
console.debug(prefix, error || '')
|
||||
break
|
||||
case 'info':
|
||||
console.log(prefix, error || '')
|
||||
break
|
||||
case 'warn':
|
||||
console.warn(prefix, error || '')
|
||||
break
|
||||
case 'error':
|
||||
console.error(prefix, error || '')
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
async debug(message: string, error?: any): Promise<void> {
|
||||
await this.writeToFile('debug', message, error)
|
||||
this.logToConsole('debug', message, error)
|
||||
}
|
||||
|
||||
async info(message: string, error?: any): Promise<void> {
|
||||
await this.writeToFile('info', message, error)
|
||||
this.logToConsole('info', message, error)
|
||||
}
|
||||
|
||||
async warn(message: string, error?: any): Promise<void> {
|
||||
await this.writeToFile('warn', message, error)
|
||||
this.logToConsole('warn', message, error)
|
||||
}
|
||||
|
||||
async error(message: string, error?: any): Promise<void> {
|
||||
await this.writeToFile('error', message, error)
|
||||
this.logToConsole('error', message, error)
|
||||
}
|
||||
|
||||
// 兼容原有的 logFloatingWindow 函数签名
|
||||
async log(message: string, error?: any): Promise<void> {
|
||||
if (error) {
|
||||
await this.error(message, error)
|
||||
} else {
|
||||
await this.info(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 创建不同模块的日志实例
|
||||
export const createLogger = (moduleName: string): Logger => {
|
||||
return new Logger(moduleName)
|
||||
}
|
||||
|
||||
// 统一的应用日志实例 - 所有模块共享同一个日志文件
|
||||
export const appLogger = createLogger('app')
|
||||
|
||||
// 为了保持向后兼容性,创建各模块的日志实例(都指向同一个应用日志)
|
||||
export const floatingWindowLogger = createLogger('floating-window')
|
||||
export const coreLogger = createLogger('mihomo-core')
|
||||
export const apiLogger = createLogger('mihomo-api')
|
||||
export const configLogger = createLogger('config')
|
||||
export const systemLogger = createLogger('system')
|
||||
export const trafficLogger = createLogger('traffic-monitor')
|
||||
export const trayLogger = createLogger('tray')
|
||||
export const initLogger = createLogger('init')
|
||||
export const ipcLogger = createLogger('ipc')
|
||||
export const proxyLogger = createLogger('sysproxy')
|
||||
export const managerLogger = createLogger('manager')
|
||||
export const factoryLogger = createLogger('factory')
|
||||
export const overrideLogger = createLogger('override')
|
||||
|
||||
// 默认日志实例
|
||||
export const logger = appLogger
|
||||
@ -22,6 +22,10 @@ export const defaultConfig: IAppConfig = {
|
||||
controlDns: true,
|
||||
controlSniff: true,
|
||||
floatingWindowCompatMode: true,
|
||||
disableLoopbackDetector: false,
|
||||
disableEmbedCA: false,
|
||||
disableSystemCA: false,
|
||||
skipSafePathCheck: false,
|
||||
nameserverPolicy: {},
|
||||
siderOrder: [
|
||||
'sysproxy',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user