fix(logging): fix four review issues in unified logger

- Front-end error reporter was posting to /_web/_web/logs/report (double
  base URL prefix); fixed to /logs/report
- uncaughtException/unhandledRejection handlers in CLI and Electron did not
  exit after logging, overriding Node's default crash behavior; added
  process.exit(1)
- NodePathProvider constructor in run() and chatlab status triggered
  migrateFromElectronIfNeeded() as a side effect; added getSystemLogsDir()
  to get the system logs path without resolving user data
- formatData() was called outside write()'s try/catch, so errors with
  circular cause objects could escape appLogger.error(); moved inside

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
diguaandClaude Sonnet 4.6 committed 2026-06-24 15:28:09 +08:00
1 parent 7c21d1c879
commit 2dbe569f2a
6 files changed
+16 -6

No files matched your search

+5 -2
View File
@@ -17,6 +17,7 @@ import {
verifyCliDataPath,
initAppLogger,
appLogger,
getSystemLogsDir,
} from '@openchatlab/node-runtime'
import {
getSessionMeta,
@@ -486,7 +487,7 @@ program
console.log('\nChatLab Status')
console.log('─'.repeat(36))
console.log(` Logs: ${new NodePathProvider().getLogsDir()}`)
console.log(` Logs: ${getSystemLogsDir()}`)
if (svc.installed) {
const portStr = svc.port ? `http://${svc.host ?? '127.0.0.1'}:${svc.port}` : ''
@@ -611,14 +612,16 @@ function printTable(columns: string[], rows: Record<string, unknown>[]): void {
/** CLI entry function */
export function run(argv?: string[]): void {
// Logs go to ~/.chatlab/logs/app.log regardless of configured user data dir.
initAppLogger(new NodePathProvider().getLogsDir())
initAppLogger(getSystemLogsDir())
process.on('uncaughtException', (error) => {
console.error('Uncaught Exception:', error)
appLogger.error('crash', 'uncaughtException', error)
process.exit(1)
})
process.on('unhandledRejection', (reason) => {
console.error('Unhandled Rejection:', reason)
appLogger.error('crash', 'unhandledRejection', reason)
process.exit(1)
})
program.parse(argv)
}
+2
View File
@@ -429,12 +429,14 @@ process.on('uncaughtException', (error) => {
logger.error(
`Uncaught Exception: ${error instanceof Error ? `${error.message}\n${error.stack ?? ''}` : String(error)}`
)
process.exit(1)
})
process.on('unhandledRejection', (reason) => {
console.error('Unhandled Rejection:', reason)
logger.error(
`Unhandled Rejection: ${reason instanceof Error ? `${reason.message}\n${reason.stack ?? ''}` : String(reason)}`
)
process.exit(1)
})
new MainProcess()
+1
View File
@@ -59,6 +59,7 @@ export {
NodePathProvider,
applyPendingNodeDataDirMigrationIfNeeded,
getDefaultNodeUserDataDir,
getSystemLogsDir,
hasPendingElectronDataWarning,
} from './node-path-provider'
export { DatabaseManager } from './database-manager'
@@ -55,11 +55,11 @@ class AppLogger {
if (LEVEL_ORDER[level] < LEVEL_ORDER[this.threshold]) return
let line = `[${new Date().toISOString()}] [${level}] [${scope}] ${message}`
const tail = formatData(data)
if (tail) line += `\n${tail}`
line += '\n'
try {
const tail = formatData(data)
if (tail) line += `\n${tail}`
line += '\n'
ensureDir(path.dirname(this.logFile))
this.rotateIfNeeded()
fs.appendFileSync(this.logFile, line, 'utf-8')
@@ -150,6 +150,10 @@ export function getDefaultNodeUserDataDir(): string {
return path.join(os.homedir(), '.chatlab', 'data')
}
export function getSystemLogsDir(): string {
return path.join(SYSTEM_DIR, 'logs')
}
function expandHome(filePath: string): string {
if (filePath.startsWith('~/') || filePath === '~') {
return path.join(os.homedir(), filePath.slice(1))
+1 -1
View File
@@ -30,7 +30,7 @@ export function reportError(message: string, stack?: string): void {
const key = `${message}::${stack?.split('\n')[1] ?? ''}`
if (!shouldReport(key)) return
// Fire-and-forget; never let reporting throw or block the UI.
void post('/_web/logs/report', {
void post('/logs/report', {
level: 'error',
message,
stack,