
























@@ -55,7 +55,8 @@ export const DEFAULT_LOG_FILE = resolveDefaultLogFile(DEFAULT_LOG_DIR); // legac
5555const LOG_PREFIX = "openclaw";
5656const LOG_SUFFIX = ".log";
5757const MAX_LOG_AGE_MS = 24 * 60 * 60 * 1000; // 24h
58-const DEFAULT_MAX_LOG_FILE_BYTES = 500 * 1024 * 1024; // 500 MB
58+const DEFAULT_MAX_LOG_FILE_BYTES = 100 * 1024 * 1024; // 100 MB
59+const MAX_ROTATED_LOG_FILES = 5;
59606061type LogObj = { date?: Date } & Record<string, unknown>;
6162@@ -397,39 +398,45 @@ function buildLogger(settings: ResolvedSettings): TsLogger<LogObj> {
397398return logger;
398399}
399400400-fs.mkdirSync(path.dirname(settings.file), { recursive: true });
401+const rollingFile = isRollingPath(settings.file);
402+let activeFile = resolveActiveLogFile(settings.file);
403+fs.mkdirSync(path.dirname(activeFile), { recursive: true });
401404// Clean up stale rolling logs when using a dated log filename.
402-if (isRollingPath(settings.file)) {
403-pruneOldRollingLogs(path.dirname(settings.file));
405+if (rollingFile) {
406+pruneOldRollingLogs(path.dirname(activeFile));
404407}
405-let currentFileBytes = getCurrentLogFileBytes(settings.file);
406-let warnedAboutSizeCap = false;
408+let currentFileBytes = getCurrentLogFileBytes(activeFile);
409+let warnedAboutRotationFailure = false;
407410408411logger.attachTransport((logObj: LogObj) => {
409412try {
413+const nextActiveFile = resolveActiveLogFile(settings.file);
414+if (nextActiveFile !== activeFile) {
415+activeFile = nextActiveFile;
416+fs.mkdirSync(path.dirname(activeFile), { recursive: true });
417+if (rollingFile) {
418+pruneOldRollingLogs(path.dirname(activeFile));
419+}
420+currentFileBytes = getCurrentLogFileBytes(activeFile);
421+}
410422const time = formatTimestamp(logObj.date ?? new Date(), { style: "long" });
411423const line = redactSensitiveText(JSON.stringify({ ...logObj, time }));
412424const payload = `${line}\n`;
413425const payloadBytes = Buffer.byteLength(payload, "utf8");
414426const nextBytes = currentFileBytes + payloadBytes;
415-if (nextBytes > settings.maxFileBytes) {
416-if (!warnedAboutSizeCap) {
417-warnedAboutSizeCap = true;
418-const warningLine = JSON.stringify({
419-time: formatTimestamp(new Date(), { style: "long" }),
420-level: "warn",
421-subsystem: "logging",
422-message: `log file size cap reached; suppressing writes file=${settings.file} maxFileBytes=${settings.maxFileBytes}`,
423-});
424-appendLogLine(settings.file, `${warningLine}\n`);
427+if (currentFileBytes > 0 && nextBytes > settings.maxFileBytes) {
428+if (rotateLogFile(activeFile)) {
429+currentFileBytes = getCurrentLogFileBytes(activeFile);
430+warnedAboutRotationFailure = false;
431+} else if (!warnedAboutRotationFailure) {
432+warnedAboutRotationFailure = true;
425433process.stderr.write(
426-`[openclaw] log file size cap reached; suppressing writes file=${settings.file} maxFileBytes=${settings.maxFileBytes}\n`,
434+`[openclaw] log file rotation failed; continuing writes file=${activeFile} maxFileBytes=${settings.maxFileBytes}\n`,
427435);
428436}
429-return;
430437}
431-if (appendLogLine(settings.file, payload)) {
432-currentFileBytes = nextBytes;
438+if (appendLogLine(activeFile, payload)) {
439+currentFileBytes += payloadBytes;
433440}
434441} catch {
435442// never block on logging failures
@@ -554,8 +561,19 @@ function formatLocalDate(date: Date): string {
554561}
555562556563function defaultRollingPathForToday(): string {
557-const today = formatLocalDate(new Date());
558-return path.join(DEFAULT_LOG_DIR, `${LOG_PREFIX}-${today}${LOG_SUFFIX}`);
564+return rollingPathForDate(DEFAULT_LOG_DIR, new Date());
565+}
566+567+function rollingPathForDate(dir: string, date: Date): string {
568+const today = formatLocalDate(date);
569+return path.join(dir, `${LOG_PREFIX}-${today}${LOG_SUFFIX}`);
570+}
571+572+function resolveActiveLogFile(file: string): string {
573+if (!isRollingPath(file)) {
574+return file;
575+}
576+return rollingPathForDate(path.dirname(file), new Date());
559577}
560578561579function isRollingPath(file: string): boolean {
@@ -592,3 +610,29 @@ function pruneOldRollingLogs(dir: string): void {
592610// ignore missing dir or read errors
593611}
594612}
613+614+function rotatedLogPath(file: string, index: number): string {
615+const ext = path.extname(file);
616+const base = file.slice(0, file.length - ext.length);
617+return `${base}.${index}${ext}`;
618+}
619+620+function rotateLogFile(file: string): boolean {
621+try {
622+fs.mkdirSync(path.dirname(file), { recursive: true });
623+fs.rmSync(rotatedLogPath(file, MAX_ROTATED_LOG_FILES), { force: true });
624+for (let index = MAX_ROTATED_LOG_FILES - 1; index >= 1; index -= 1) {
625+const from = rotatedLogPath(file, index);
626+if (!fs.existsSync(from)) {
627+continue;
628+}
629+fs.renameSync(from, rotatedLogPath(file, index + 1));
630+}
631+if (fs.existsSync(file)) {
632+fs.renameSync(file, rotatedLogPath(file, 1));
633+}
634+return true;
635+} catch {
636+return false;
637+}
638+}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。