diff --git a/.gitignore b/.gitignore index 2cc499e..f256216 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,9 @@ build/ npm-debug.log* bun-debug.log* +# Date-based log files in logs folder +logs/ + .DS_Store Thumbs.db diff --git a/src/cli-shared.ts b/src/cli-shared.ts index b0c7b46..23dec10 100644 --- a/src/cli-shared.ts +++ b/src/cli-shared.ts @@ -3,7 +3,7 @@ import { existsSync } from "fs"; import { CONFIG_FILE, DEFAULT_CONFIG, - LOG_FILE, + LOGS_DIR, type RoutstrdConfig, } from "./utils/config"; @@ -56,17 +56,20 @@ export async function isDaemonRunning(): Promise { } export async function startDaemonProcess(): Promise { - const logFile = Bun.file(LOG_FILE); + // Ensure logs directory exists (logger handles date-based files) + if (!existsSync(LOGS_DIR)) { + await Bun.$`mkdir -p ${LOGS_DIR}`; + } const proc = Bun.spawn([ "bun", "run", `${import.meta.dir}/daemon/index.ts` ], { - stdout: logFile, - stderr: logFile, + stdout: "inherit", + stderr: "inherit", stdin: "ignore", detached: true, }); - + proc.unref(); for (let i = 0; i < 50; i++) { diff --git a/src/cli.ts b/src/cli.ts index a0109e0..192aa9a 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -13,7 +13,7 @@ import { DB_PATH, CONFIG_FILE, DEFAULT_CONFIG, - LOG_FILE, + LOGS_DIR, type RoutstrdConfig, } from "./utils/config"; import { logger } from "./utils/logger"; @@ -932,22 +932,47 @@ program }); // Logs +function getLogFileForDate(date: Date = new Date()): string { + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, "0"); + const day = String(date.getDate()).padStart(2, "0"); + return `${LOGS_DIR}/${year}-${month}-${day}.log`; +} + program .command("logs") .description("View daemon logs") .option("-f, --follow", "Follow log output", false) .option("-n, --lines ", "Number of lines to show", "50") .action(async (options: { follow: boolean; lines: string }) => { - if (!existsSync(LOG_FILE)) { - console.log("No log file found. Daemon may not have started yet."); + const todayFile = getLogFileForDate(); + const yesterday = new Date(); + yesterday.setDate(yesterday.getDate() - 1); + const yesterdayFile = getLogFileForDate(yesterday); + + if (!existsSync(todayFile) && !existsSync(yesterdayFile)) { + console.log("No log files found. Daemon may not have started yet."); + console.log(`Logs directory: ${LOGS_DIR}`); process.exit(1); } const lines = parseInt(options.lines, 10); const readLastLines = async (): Promise => { - const content = await Bun.file(LOG_FILE).text(); - const allLines = content.split("\n").filter(Boolean); + let allLines: string[] = []; + + // Read yesterday's log first if it exists + if (existsSync(yesterdayFile)) { + const yesterdayContent = await Bun.file(yesterdayFile).text(); + allLines = yesterdayContent.split("\n").filter(Boolean); + } + + // Then read today's log + if (existsSync(todayFile)) { + const todayContent = await Bun.file(todayFile).text(); + allLines = allLines.concat(todayContent.split("\n").filter(Boolean)); + } + return allLines.slice(-lines); }; @@ -959,25 +984,40 @@ program }; if (options.follow) { - const logFile = Bun.file(LOG_FILE); - const initialContent = await logFile.text(); - let lastSize = initialContent.length; + let currentLogFile = todayFile; + let lastSize = 0; + + if (existsSync(currentLogFile)) { + lastSize = (await Bun.file(currentLogFile).text()).length; + } await printLines(); const interval = setInterval(async () => { - const content = await Bun.file(LOG_FILE).text(); - const currentSize = content.length; - if (currentSize > lastSize) { - const allLines = content.split("\n").filter(Boolean); - const newLines = allLines.slice( - Math.floor(lastSize === 0 ? 0 : -1), - -1, - ); - for (const line of newLines) { - console.log(line); + // Check if we need to switch to a new date file + const newLogFile = getLogFileForDate(); + if (newLogFile !== currentLogFile) { + console.log(`\n--- Switched to ${newLogFile} ---\n`); + currentLogFile = newLogFile; + lastSize = existsSync(currentLogFile) + ? (await Bun.file(currentLogFile).text()).length + : 0; + } + + if (existsSync(currentLogFile)) { + const content = await Bun.file(currentLogFile).text(); + const currentSize = content.length; + if (currentSize > lastSize) { + const allLines = content.split("\n").filter(Boolean); + const newLines = allLines.slice( + Math.floor(lastSize === 0 ? 0 : -1), + -1, + ); + for (const line of newLines) { + console.log(line); + } + lastSize = currentSize; } - lastSize = currentSize; } }, 1000); diff --git a/src/start-daemon.ts b/src/start-daemon.ts index e3c8296..5704105 100644 --- a/src/start-daemon.ts +++ b/src/start-daemon.ts @@ -1,7 +1,6 @@ -import { LOG_FILE } from "./utils/config"; import { logger } from "./utils/logger"; -import { existsSync, mkdirSync } from "fs"; -import { dirname } from "path"; +import { existsSync } from "fs"; +import { LOGS_DIR } from "./utils/config"; export async function startDaemon( options: { port?: string; provider?: string } = {}, @@ -33,16 +32,13 @@ export async function startDaemon( args.push("--provider", options.provider); } - // Ensure log directory exists - const logDir = dirname(LOG_FILE); - if (!existsSync(logDir)) { - mkdirSync(logDir, { recursive: true }); + // Ensure logs directory exists (logger handles date-based files) + if (!existsSync(LOGS_DIR)) { + await Bun.$`mkdir -p ${LOGS_DIR}`; } - // Use shell redirection to append stdout/stderr to log file - // Bun.file() overwrites, so we need shell >> for appending const daemonScript = new URL("./daemon/index.js", import.meta.url).pathname; - const shellCmd = `bun run "${daemonScript}" ${args.map(a => `'${a}'`).join(" ")} >> "${LOG_FILE}" 2>&1`; + const shellCmd = `bun run "${daemonScript}" ${args.map(a => `'${a}'`).join(" ")}`; const proc = Bun.spawn(["sh", "-c", shellCmd], { stdout: "inherit", @@ -64,7 +60,7 @@ export async function startDaemon( if (exitCode !== null) { throw new Error( - `Daemon process exited early with code ${exitCode}. Check logs at ${LOG_FILE}`, + `Daemon process exited early with code ${exitCode}. Check logs in ${LOGS_DIR}`, ); } @@ -85,6 +81,6 @@ export async function startDaemon( } throw new Error( - `Daemon failed to start within ${Math.round(startupTimeoutMs / 1000)} seconds. Check logs at ${LOG_FILE}`, + `Daemon failed to start within ${Math.round(startupTimeoutMs / 1000)} seconds. Check logs in ${LOGS_DIR}`, ); } diff --git a/src/utils/config.ts b/src/utils/config.ts index d05865a..2a3be1e 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -5,7 +5,7 @@ export const SOCKET_PATH = process.env.ROUTSTRD_SOCKET || `${CONFIG_DIR}/routstr export const PID_FILE = process.env.ROUTSTRD_PID || `${CONFIG_DIR}/routstrd.pid`; export const DB_PATH = `${CONFIG_DIR}/routstr.db`; export const CONFIG_FILE = `${CONFIG_DIR}/config.json`; -export const LOG_FILE = `${CONFIG_DIR}/routstrd.log`; +export const LOGS_DIR = `${CONFIG_DIR}/logs`; export interface RoutstrdConfig { port: number; diff --git a/src/utils/logger.ts b/src/utils/logger.ts index 19f639d..7de5da1 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -4,11 +4,18 @@ import { join } from "path"; const HOME = process.env.HOME || process.env.USERPROFILE || ""; const LOG_DIR = process.env.ROUTSTRD_DIR || `${HOME}/.routstrd`; -const LOG_FILE = join(LOG_DIR, "routstrd.log"); +const LOGS_DIR = join(LOG_DIR, "logs"); + +function getLogFileForDate(date: Date = new Date()): string { + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, "0"); + const day = String(date.getDate()).padStart(2, "0"); + return join(LOGS_DIR, `${year}-${month}-${day}.log`); +} async function ensureLogDir() { - if (!existsSync(LOG_DIR)) { - await mkdir(LOG_DIR, { recursive: true }); + if (!existsSync(LOGS_DIR)) { + await mkdir(LOGS_DIR, { recursive: true }); } } @@ -31,8 +38,9 @@ async function writeLog(level: string, ...args: unknown[]) { }) .join(" "); const line = `[${timestamp}] [${level}] ${message}\n`; + const logFile = getLogFileForDate(new Date(timestamp)); try { - await appendFile(LOG_FILE, line); + await appendFile(logFile, line); } catch (error) { console.error("Failed to write log:", error); }