openpencil/electron/logger.ts
Kayshen Xu 3b60bdc1fa V0.3.2 (#28)
* feat(electron): update electron-builder.yml to specify artifact naming convention for Windows builds. This change enhances clarity and consistency in the build output.

* feat(electron): implement a file logger for the main process

- Added a new logger module that writes logs to `{userData}/logs/main.log` with daily rotation and retains logs for the last 7 days.
- Integrated logging functionality into the main process, replacing console error messages with log entries for better error tracking and debugging.
- Introduced IPC handlers to retrieve the log directory path for user access.
- Updated the preload and main files to utilize the new logging system, enhancing overall application reliability and maintainability.

* feat(mcp): introduce layered design workflow and selection management

- Added a new layered design workflow with tools: `design_skeleton`, `design_content`, and `design_refine` for improved multi-section design generation.
- Implemented segmented prompt retrieval in `get_design_prompt` to allow focused access to design knowledge.
- Created new API endpoints for managing canvas selection state with `selection.get` and `selection.post`, enabling real-time updates and synchronization.
- Enhanced document management with live selection fetching and improved node operations for better design content handling.
- Updated README and CLAUDE.md to reflect new features and usage guidelines for the layered design process.
2026-03-10 21:55:47 +08:00

96 lines
2.4 KiB
TypeScript

/**
* Simple file logger for the Electron main process.
*
* Writes to `{userData}/logs/main.log` with daily rotation.
* Keeps the last 7 days of logs, auto-cleans on init.
*
* Usage:
* import { initLogger, log } from './logger'
* await initLogger() // call once at startup
* log.info('message')
* log.error('message')
* log.warn('message')
*/
import { appendFile, readdir, unlink, mkdir, stat } from 'node:fs/promises'
import { join } from 'node:path'
let logDir = ''
let logFilePath = ''
let initialized = false
const MAX_LOG_DAYS = 7
function timestamp(): string {
return new Date().toISOString()
}
function todayStamp(): string {
return new Date().toISOString().slice(0, 10) // YYYY-MM-DD
}
async function writeLine(level: string, msg: string): Promise<void> {
if (!initialized) return
const line = `${timestamp()} [${level}] ${msg}\n`
// Also forward to console for dev mode
if (level === 'ERROR') {
process.stderr.write(line)
} else {
process.stdout.write(line)
}
try {
await appendFile(logFilePath, line, 'utf-8')
} catch {
// Disk full or permission error — silently drop
}
}
async function cleanOldLogs(): Promise<void> {
try {
const files = await readdir(logDir)
const cutoff = Date.now() - MAX_LOG_DAYS * 24 * 60 * 60 * 1000
for (const file of files) {
if (!file.endsWith('.log')) continue
const filePath = join(logDir, file)
try {
const s = await stat(filePath)
if (s.mtimeMs < cutoff) {
await unlink(filePath)
}
} catch {
// ignore individual file errors
}
}
} catch {
// ignore
}
}
/**
* Initialize the logger. Must be called after `app.getPath('userData')` is available.
*/
export async function initLogger(userDataPath: string): Promise<void> {
logDir = join(userDataPath, 'logs')
logFilePath = join(logDir, `main-${todayStamp()}.log`)
try {
await mkdir(logDir, { recursive: true })
} catch {
// ignore
}
initialized = true
await writeLine('INFO', '--- OpenPencil started ---')
// Clean old logs in background
cleanOldLogs()
}
/** Get the log directory path (for displaying to users). */
export function getLogDir(): string {
return logDir
}
export const log = {
info: (msg: string) => { writeLine('INFO', msg) },
warn: (msg: string) => { writeLine('WARN', msg) },
error: (msg: string) => { writeLine('ERROR', msg) },
}