feat(logger): sync renderer log level cache and support verbose IPC
- Add LOGGER_LEVEL_CHANGED IPC channel for broadcasting level changes - setLogLevel() now notifies all BrowserWindows when level changes - Add verbose case in IPC forwardToWinston (was falling through to info) - Renderer logger API listens for level changes and updates cached level - Add cleanup() method to remove level change listener Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -9,7 +9,7 @@
|
|||||||
* - Error-level logs bypass circuit breaker
|
* - Error-level logs bypass circuit breaker
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ipcMain } from 'electron'
|
import { ipcMain, BrowserWindow } from 'electron'
|
||||||
import winston from 'winston'
|
import winston from 'winston'
|
||||||
import { createLogger } from '../services/logger'
|
import { createLogger } from '../services/logger'
|
||||||
import logger from '../services/logger'
|
import logger from '../services/logger'
|
||||||
@@ -161,6 +161,9 @@ class LoggerHandlerState {
|
|||||||
: entry.message
|
: entry.message
|
||||||
|
|
||||||
switch (entry.level) {
|
switch (entry.level) {
|
||||||
|
case 'verbose':
|
||||||
|
childLogger.verbose(message, entry.context)
|
||||||
|
break
|
||||||
case 'debug':
|
case 'debug':
|
||||||
childLogger.debug(message, entry.context)
|
childLogger.debug(message, entry.context)
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -11,8 +11,10 @@
|
|||||||
import winston from 'winston'
|
import winston from 'winston'
|
||||||
import DailyRotateFile from 'winston-daily-rotate-file'
|
import DailyRotateFile from 'winston-daily-rotate-file'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
import { BrowserWindow } from 'electron'
|
||||||
import { serializeError, sanitizeError } from './error-utils'
|
import { serializeError, sanitizeError } from './error-utils'
|
||||||
import { getLogDir, isProduction } from './shared'
|
import { getLogDir, isProduction } from './shared'
|
||||||
|
import { IPC_CHANNELS } from '../../../shared/ipc-channels'
|
||||||
|
|
||||||
// Cache isProduction() at module load — app.isPackaged never changes at runtime
|
// Cache isProduction() at module load — app.isPackaged never changes at runtime
|
||||||
const IS_PROD = isProduction()
|
const IS_PROD = isProduction()
|
||||||
@@ -113,11 +115,18 @@ const logger = winston.createLogger({
|
|||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the logger level dynamically
|
* Update the logger level dynamically and notify renderer processes
|
||||||
* @param level - The new log level
|
* @param level - The new log level
|
||||||
*/
|
*/
|
||||||
export function setLogLevel(level: string): void {
|
export function setLogLevel(level: string): void {
|
||||||
logger.level = level
|
logger.level = level
|
||||||
|
|
||||||
|
// Broadcast level change to all renderer windows so they update their cached level
|
||||||
|
for (const win of BrowserWindow.getAllWindows()) {
|
||||||
|
if (!win.isDestroyed()) {
|
||||||
|
win.webContents.send(IPC_CHANNELS.LOGGER_LEVEL_CHANGED, level)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -20,6 +20,11 @@ function shouldLog(level: LogLevel): boolean {
|
|||||||
return (priorities[level] ?? 0) >= (priorities[cachedLevel] ?? 2)
|
return (priorities[level] ?? 0) >= (priorities[cachedLevel] ?? 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Listener for level change broadcasts from main process
|
||||||
|
function onLevelChanged(_event: Electron.IpcRendererEvent, level: LogLevel): void {
|
||||||
|
cachedLevel = level
|
||||||
|
}
|
||||||
|
|
||||||
export const loggerApi = {
|
export const loggerApi = {
|
||||||
log: (level: LogLevel, message: string, context?: Record<string, unknown>): void => {
|
log: (level: LogLevel, message: string, context?: Record<string, unknown>): void => {
|
||||||
// Drop messages below the configured log level
|
// Drop messages below the configured log level
|
||||||
@@ -34,10 +39,19 @@ export const loggerApi = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch the current log level from main process and cache it
|
* Fetch the current log level from main process and cache it.
|
||||||
* Should be called early in renderer initialization
|
* Also registers a listener for future level changes.
|
||||||
|
* Should be called early in renderer initialization.
|
||||||
*/
|
*/
|
||||||
fetchLevel: async (): Promise<void> => {
|
fetchLevel: async (): Promise<void> => {
|
||||||
cachedLevel = (await ipcRenderer.invoke(IPC_CHANNELS.LOGGER_GET_LEVEL)) as LogLevel
|
cachedLevel = (await ipcRenderer.invoke(IPC_CHANNELS.LOGGER_GET_LEVEL)) as LogLevel
|
||||||
|
ipcRenderer.on(IPC_CHANNELS.LOGGER_LEVEL_CHANGED, onLevelChanged)
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the level change listener (call on cleanup/unmount)
|
||||||
|
*/
|
||||||
|
cleanup: (): void => {
|
||||||
|
ipcRenderer.removeListener(IPC_CHANNELS.LOGGER_LEVEL_CHANGED, onLevelChanged)
|
||||||
}
|
}
|
||||||
} as const
|
} as const
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ export const IPC_CHANNELS = {
|
|||||||
// Logger
|
// Logger
|
||||||
LOGGER_FORWARD: 'logger:forward',
|
LOGGER_FORWARD: 'logger:forward',
|
||||||
LOGGER_GET_LEVEL: 'logger:getLevel',
|
LOGGER_GET_LEVEL: 'logger:getLevel',
|
||||||
|
LOGGER_LEVEL_CHANGED: 'logger:levelChanged',
|
||||||
|
|
||||||
// Report
|
// Report
|
||||||
REPORT_LIST_ALL: 'report:listAll',
|
REPORT_LIST_ALL: 'report:listAll',
|
||||||
|
|||||||
Reference in New Issue
Block a user