openpencil/server/utils/server-logger.ts
Kayshen Xu e25feb56fc V0.4.3 (#50)
* chore(ai): update dependencies and enhance logging functionality

- Bump version of `@github/copilot-sdk` and related packages to `0.1.32` and `1.0.7` for improved features and bug fixes.
- Update Discord invite links across multiple README files to the new server.
- Introduce a new logging utility in `server/utils/server-logger.ts` for better server process logging, including automatic log cleanup and directory management.
- Enhance the `connect-agent.ts` and `install-agent.ts` files to improve OpenCode binary resolution and installation commands.
- Refactor `resolve-claude-cli.ts` and `resolve-copilot-cli.ts` to include detailed logging for CLI binary resolution processes.

This update improves dependency management, enhances user experience with updated links, and provides better insights into server operations through logging.

* chore: bump version from 0.4.0 to 0.4.3 in package.json
2026-03-18 21:34:58 +08:00

89 lines
2.1 KiB
TypeScript

/**
* Simple file logger for the Nitro server process.
*
* Writes to `~/.openpencil/logs/server-{YYYY-MM-DD}.log`.
* Also forwards to console for dev mode visibility.
* Keeps the last 7 days of logs, auto-cleans on first write.
*/
import { appendFileSync, existsSync, mkdirSync, readdirSync, statSync, unlinkSync } from 'node:fs'
import { homedir } from 'node:os'
import { join } from 'node:path'
const MAX_LOG_DAYS = 7
const logDir = join(homedir(), '.openpencil', 'logs')
let dirEnsured = false
let cleanedUp = false
function ensureDir(): void {
if (dirEnsured) return
try {
if (!existsSync(logDir)) {
mkdirSync(logDir, { recursive: true })
}
dirEnsured = true
} catch {
// Silently fail — logging is best-effort
}
}
function todayStamp(): string {
return new Date().toISOString().slice(0, 10)
}
function timestamp(): string {
return new Date().toISOString()
}
function getLogFilePath(): string {
return join(logDir, `server-${todayStamp()}.log`)
}
function cleanOldLogs(): void {
if (cleanedUp) return
cleanedUp = true
try {
const files = readdirSync(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 = statSync(filePath)
if (s.mtimeMs < cutoff) {
unlinkSync(filePath)
}
} catch {
// ignore individual file errors
}
}
} catch {
// ignore
}
}
function writeLine(level: string, msg: string): void {
const line = `${timestamp()} [${level}] ${msg}\n`
// Forward to console
if (level === 'ERROR') {
process.stderr.write(line)
} else {
process.stdout.write(line)
}
// Write to file
try {
ensureDir()
cleanOldLogs()
appendFileSync(getLogFilePath(), line, 'utf-8')
} catch {
// Disk full or permission error — silently drop
}
}
export const serverLog = {
info: (msg: string) => writeLine('INFO', msg),
warn: (msg: string) => writeLine('WARN', msg),
error: (msg: string) => writeLine('ERROR', msg),
}