openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
632 lines (631 loc) • 24.4 kB
JavaScript
import { c as normalizeOptionalString } from "./string-coerce-mnp54Vah.js";
import { c as redactSensitiveText, i as redactSecrets, m as shouldSkipMutatingLoggingConfigRead, p as readLoggingConfig } from "./redact-DduLliKq.js";
import { t as expandHomePrefix } from "./home-dir-BjcCg_IW.js";
import "./fs-safe-defaults-B7hUN42l.js";
import { n as appendRegularFileSync } from "./regular-file-BD2zl6_l.js";
import { t as loggingState } from "./state-CHRYWIGY.js";
import { C as isValidDiagnosticSpanId, S as getActiveDiagnosticTraceContext, T as isValidDiagnosticTraceId, n as emitDiagnosticEvent, w as isValidDiagnosticTraceFlags } from "./diagnostic-events-Chmz2PSy.js";
import { t as isBlockedObjectKey } from "./prototype-keys-D2nJOZIy.js";
import { n as resolvePreferredOpenClawTmpDir, t as POSIX_OPENCLAW_TMP_DIR } from "./tmp-openclaw-dir-DOKojISm.js";
import fs from "node:fs";
import path from "node:path";
import os from "node:os";
import { Logger } from "tslog";
//#region src/logging/levels.ts
const ALLOWED_LOG_LEVELS = [
"silent",
"fatal",
"error",
"warn",
"info",
"debug",
"trace"
];
function tryParseLogLevel(level) {
if (typeof level !== "string") return;
const candidate = level.trim();
return ALLOWED_LOG_LEVELS.includes(candidate) ? candidate : void 0;
}
function normalizeLogLevel(level, fallback = "info") {
return tryParseLogLevel(level) ?? fallback;
}
function levelToMinLevel(level) {
return {
trace: 1,
debug: 2,
info: 3,
warn: 4,
error: 5,
fatal: 6,
silent: Number.POSITIVE_INFINITY
}[level];
}
//#endregion
//#region src/logging/env-log-level.ts
/** Resolves OPENCLAW_LOG_LEVEL once per value, warning only when the invalid value changes. */
function resolveEnvLogLevelOverride() {
const trimmed = normalizeOptionalString(process.env.OPENCLAW_LOG_LEVEL) ?? "";
if (!trimmed) {
loggingState.invalidEnvLogLevelValue = null;
return;
}
const parsed = tryParseLogLevel(trimmed);
if (parsed) {
loggingState.invalidEnvLogLevelValue = null;
return parsed;
}
if (loggingState.invalidEnvLogLevelValue !== trimmed) {
loggingState.invalidEnvLogLevelValue = trimmed;
process.stderr.write(`[openclaw] Ignoring invalid OPENCLAW_LOG_LEVEL="${trimmed}" (allowed: ${ALLOWED_LOG_LEVELS.join("|")}).\n`);
}
}
//#endregion
//#region src/logging/timestamps.ts
const validTimeZoneCache = /* @__PURE__ */ new Map();
const timestampFormatterCache = /* @__PURE__ */ new Map();
let hostTimeZone;
function isValidTimeZone(tz) {
const cached = validTimeZoneCache.get(tz);
if (cached !== void 0) return cached;
let valid;
try {
new Intl.DateTimeFormat("en", { timeZone: tz }).format();
valid = true;
} catch {
valid = false;
}
validTimeZoneCache.set(tz, valid);
return valid;
}
function resolveEffectiveTimeZone(timeZone) {
const explicit = timeZone ?? process.env.TZ;
return explicit && isValidTimeZone(explicit) ? explicit : hostTimeZone ??= Intl.DateTimeFormat().resolvedOptions().timeZone;
}
function formatOffset(offsetRaw) {
return offsetRaw === "GMT" ? "+00:00" : offsetRaw.slice(3);
}
function getTimestampParts(date, timeZone) {
const effectiveTimeZone = resolveEffectiveTimeZone(timeZone);
let fmt = timestampFormatterCache.get(effectiveTimeZone);
if (!fmt) {
fmt = new Intl.DateTimeFormat("en", {
timeZone: effectiveTimeZone,
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
hour12: false,
fractionalSecondDigits: 3,
timeZoneName: "longOffset"
});
timestampFormatterCache.set(effectiveTimeZone, fmt);
}
const parts = Object.fromEntries(fmt.formatToParts(date).map((part) => [part.type, part.value]));
return {
year: parts.year,
month: parts.month,
day: parts.day,
hour: parts.hour,
minute: parts.minute,
second: parts.second,
fractionalSecond: parts.fractionalSecond,
offset: formatOffset(parts.timeZoneName ?? "GMT")
};
}
function formatTimestamp(date, options) {
const style = options?.style ?? "medium";
const parts = getTimestampParts(date, options?.timeZone);
switch (style) {
case "short": return `${parts.hour}:${parts.minute}:${parts.second}${parts.offset}`;
case "medium": return `${parts.hour}:${parts.minute}:${parts.second}.${parts.fractionalSecond}${parts.offset}`;
case "long": return `${parts.year}-${parts.month}-${parts.day}T${parts.hour}:${parts.minute}:${parts.second}.${parts.fractionalSecond}${parts.offset}`;
}
throw new Error("Unsupported timestamp style");
}
/**
* @deprecated Use formatTimestamp from "./timestamps.js" instead.
* This function will be removed in a future version.
*/
function formatLocalIsoWithOffset(now, timeZone) {
return formatTimestamp(now, {
style: "long",
timeZone
});
}
//#endregion
//#region src/logging/logger.ts
function canUseNodeFs() {
const getBuiltinModule = process.getBuiltinModule;
if (typeof getBuiltinModule !== "function") return false;
try {
return getBuiltinModule("fs") !== void 0;
} catch {
return false;
}
}
function resolveDefaultLogDir() {
return canUseNodeFs() ? resolvePreferredOpenClawTmpDir() : POSIX_OPENCLAW_TMP_DIR;
}
function resolveDefaultLogFile(defaultLogDir) {
return canUseNodeFs() ? path.join(defaultLogDir, "openclaw.log") : `${POSIX_OPENCLAW_TMP_DIR}/openclaw.log`;
}
const DEFAULT_LOG_DIR = resolveDefaultLogDir();
const DEFAULT_LOG_FILE = resolveDefaultLogFile(DEFAULT_LOG_DIR);
const LOG_PREFIX = "openclaw";
const LOG_SUFFIX = ".log";
const MAX_LOG_AGE_MS = 1440 * 60 * 1e3;
const DEFAULT_MAX_LOG_FILE_BYTES = 100 * 1024 * 1024;
const MAX_ROTATED_LOG_FILES = 5;
const MAX_DIAGNOSTIC_LOG_BINDINGS_JSON_CHARS = 8 * 1024;
const MAX_DIAGNOSTIC_LOG_MESSAGE_CHARS = 4 * 1024;
const loadLoggerConfigDefault = () => readLoggingConfig();
let loadLoggerConfig = loadLoggerConfigDefault;
function setLoggerConfigLoaderForTests(loader) {
loadLoggerConfig = loader ?? loadLoggerConfigDefault;
loggingState.cachedLogger = null;
loggingState.cachedSettings = null;
}
const MAX_DIAGNOSTIC_LOG_ATTRIBUTE_COUNT = 32;
const MAX_DIAGNOSTIC_LOG_ATTRIBUTE_VALUE_CHARS = 2 * 1024;
const MAX_DIAGNOSTIC_LOG_NAME_CHARS = 120;
const MAX_FILE_LOG_MESSAGE_CHARS = 4 * 1024;
const MAX_FILE_LOG_CONTEXT_VALUE_CHARS = 512;
const DIAGNOSTIC_LOG_ATTRIBUTE_KEY_RE = /^[A-Za-z0-9_.:-]{1,64}$/u;
const defaultHostnameResolver = () => os.hostname();
let hostnameResolver = defaultHostnameResolver;
let cachedHostname = null;
function clampDiagnosticLogText(value, maxChars) {
return value.length > maxChars ? `${value.slice(0, maxChars)}...(truncated)` : value;
}
function sanitizeDiagnosticLogText(value, maxChars) {
return clampDiagnosticLogText(redactSensitiveText(clampDiagnosticLogText(value, maxChars)), maxChars);
}
function normalizeDiagnosticLogName(value) {
if (!value || value.trim().startsWith("{")) return;
const sanitized = sanitizeDiagnosticLogText(value.trim(), MAX_DIAGNOSTIC_LOG_NAME_CHARS);
return DIAGNOSTIC_LOG_ATTRIBUTE_KEY_RE.test(sanitized) ? sanitized : void 0;
}
function assignDiagnosticLogAttribute(attributes, state, key, value) {
if (state.count >= MAX_DIAGNOSTIC_LOG_ATTRIBUTE_COUNT) return;
const normalizedKey = key.trim();
if (isBlockedObjectKey(normalizedKey)) return;
if (redactSensitiveText(normalizedKey) !== normalizedKey) return;
if (!DIAGNOSTIC_LOG_ATTRIBUTE_KEY_RE.test(normalizedKey)) return;
if (typeof value === "string") {
attributes[normalizedKey] = sanitizeDiagnosticLogText(value, MAX_DIAGNOSTIC_LOG_ATTRIBUTE_VALUE_CHARS);
state.count += 1;
return;
}
if (typeof value === "number" && Number.isFinite(value)) {
attributes[normalizedKey] = value;
state.count += 1;
return;
}
if (typeof value === "boolean") {
attributes[normalizedKey] = value;
state.count += 1;
}
}
function addDiagnosticLogAttributesFrom(attributes, state, source) {
if (!source) return;
for (const key in source) {
if (state.count >= MAX_DIAGNOSTIC_LOG_ATTRIBUTE_COUNT) break;
if (!Object.hasOwn(source, key) || key === "trace") continue;
assignDiagnosticLogAttribute(attributes, state, key, source[key]);
}
}
function isPlainLogRecordObject(value) {
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
const prototype = Object.getPrototypeOf(value);
return prototype === Object.prototype || prototype === null;
}
function normalizeTraceContext(value) {
if (!value || typeof value !== "object" || Array.isArray(value)) return;
const candidate = value;
if (!isValidDiagnosticTraceId(candidate.traceId)) return;
if (candidate.spanId !== void 0 && !isValidDiagnosticSpanId(candidate.spanId)) return;
if (candidate.parentSpanId !== void 0 && !isValidDiagnosticSpanId(candidate.parentSpanId)) return;
if (candidate.traceFlags !== void 0 && !isValidDiagnosticTraceFlags(candidate.traceFlags)) return;
return {
traceId: candidate.traceId,
...candidate.spanId ? { spanId: candidate.spanId } : {},
...candidate.parentSpanId ? { parentSpanId: candidate.parentSpanId } : {},
...candidate.traceFlags ? { traceFlags: candidate.traceFlags } : {}
};
}
function extractTraceContext(value) {
const direct = normalizeTraceContext(value);
if (direct) return direct;
if (!value || typeof value !== "object" || Array.isArray(value)) return;
return normalizeTraceContext(value.trace);
}
function getSortedNumericLogArgs(logObj) {
return Object.entries(logObj).filter(([key]) => /^\d+$/.test(key)).toSorted((a, b) => Number(a[0]) - Number(b[0])).map(([, value]) => value);
}
function clampFileLogText(value, maxChars) {
return value.length > maxChars ? `${value.slice(0, maxChars)}...(truncated)` : value;
}
function normalizeFileLogContextValue(value) {
if (typeof value === "string") {
const normalized = value.trim();
return normalized ? clampFileLogText(normalized, MAX_FILE_LOG_CONTEXT_VALUE_CHARS) : void 0;
}
if (typeof value === "number" && Number.isFinite(value)) return String(value);
if (typeof value === "boolean") return String(value);
}
function readFirstContextString(sources, keys) {
for (const source of sources) {
if (!source) continue;
for (const key of keys) {
const value = normalizeFileLogContextValue(source[key]);
if (value) return value;
}
}
}
function stringifyFileLogMessagePart(value) {
if (typeof value === "string") return value;
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return String(value);
if (value instanceof Error) return value.message || value.name;
if (isPlainLogRecordObject(value) && typeof value.message === "string") return value.message;
if (value === null || value === void 0) return;
try {
return JSON.stringify(value);
} catch {
return;
}
}
function buildFileLogMessage(numericArgs) {
const parts = numericArgs.map(stringifyFileLogMessagePart).filter((part) => Boolean(part && part.trim()));
if (parts.length === 0) return;
return clampFileLogText(parts.join(" "), MAX_FILE_LOG_MESSAGE_CHARS);
}
function resolveLogHostname() {
if (cachedHostname) return cachedHostname;
const hostname = hostnameResolver().trim();
if (!hostname) return "unknown";
cachedHostname = hostname;
return hostname;
}
function withResolvedLogMetaHostname(meta, hostname) {
if (!meta || typeof meta !== "object" || Array.isArray(meta)) return meta;
return {
...meta,
hostname
};
}
function extractLogBindingPrefix(numericArgs) {
if (typeof numericArgs[0] === "string" && numericArgs[0].length <= MAX_DIAGNOSTIC_LOG_BINDINGS_JSON_CHARS && numericArgs[0].trim().startsWith("{")) try {
const parsed = JSON.parse(numericArgs[0]);
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return {
bindings: parsed,
args: numericArgs.slice(1)
};
} catch {}
return { args: numericArgs };
}
function findLogTraceContext(bindings, numericArgs) {
const fromBindings = extractTraceContext(bindings);
if (fromBindings) return fromBindings;
for (const arg of numericArgs) {
const fromArg = extractTraceContext(arg);
if (fromArg) return fromArg;
}
}
function buildTraceFileLogFields(logObj) {
const { bindings, args } = extractLogBindingPrefix(getSortedNumericLogArgs(logObj));
const trace = findLogTraceContext(bindings, args) ?? getActiveDiagnosticTraceContext();
if (!trace) return;
return {
traceId: trace.traceId,
...trace.spanId ? { spanId: trace.spanId } : {},
...trace.parentSpanId ? { parentSpanId: trace.parentSpanId } : {},
...trace.traceFlags ? { traceFlags: trace.traceFlags } : {}
};
}
function buildStructuredFileLogFields(logObj) {
const { bindings, args } = extractLogBindingPrefix(getSortedNumericLogArgs(logObj));
const structuredArg = isPlainLogRecordObject(args[0]) ? args[0] : void 0;
const sources = [
structuredArg,
bindings,
logObj
];
const message = buildFileLogMessage(structuredArg && typeof structuredArg.message !== "string" ? args.slice(1) : args);
const agentId = readFirstContextString(sources, ["agent_id", "agentId"]);
const sessionId = readFirstContextString(sources, [
"session_id",
"sessionId",
"sessionKey"
]);
const channel = readFirstContextString(sources, ["channel", "messageProvider"]);
return {
hostname: resolveLogHostname(),
...message ? { message } : {},
...agentId ? { agent_id: agentId } : {},
...sessionId ? { session_id: sessionId } : {},
...channel ? { channel } : {}
};
}
function buildDiagnosticLogRecord(logObj) {
const meta = logObj["_meta"];
const { bindings, args: numericArgs } = extractLogBindingPrefix(getSortedNumericLogArgs(logObj));
const trace = findLogTraceContext(bindings, numericArgs) ?? getActiveDiagnosticTraceContext();
const structuredArg = numericArgs[0];
const structuredBindings = isPlainLogRecordObject(structuredArg) ? structuredArg : void 0;
if (structuredBindings) numericArgs.shift();
let message = "";
if (numericArgs.length > 0 && typeof numericArgs[numericArgs.length - 1] === "string") message = sanitizeDiagnosticLogText(String(numericArgs.pop()), MAX_DIAGNOSTIC_LOG_MESSAGE_CHARS);
else if (numericArgs.length === 1 && (typeof numericArgs[0] === "number" || typeof numericArgs[0] === "boolean")) {
message = String(numericArgs[0]);
numericArgs.length = 0;
}
if (!message) message = "log";
const attributes = Object.create(null);
const attributeState = { count: 0 };
addDiagnosticLogAttributesFrom(attributes, attributeState, bindings);
addDiagnosticLogAttributesFrom(attributes, attributeState, structuredBindings);
const code = {};
if (meta?.path?.fileLine) {
const line = Number(meta.path.fileLine);
if (Number.isFinite(line)) code.line = line;
}
if (meta?.path?.method) code.functionName = sanitizeDiagnosticLogText(meta.path.method, MAX_DIAGNOSTIC_LOG_NAME_CHARS);
const loggerName = normalizeDiagnosticLogName(meta?.name);
const loggerParents = meta?.parentNames?.map(normalizeDiagnosticLogName).filter((name) => Boolean(name));
return {
type: "log.record",
level: meta?.logLevelName ?? "INFO",
message,
...loggerName ? { loggerName } : {},
...loggerParents?.length ? { loggerParents } : {},
...Object.keys(attributes).length > 0 ? { attributes } : {},
...Object.keys(code).length > 0 ? { code } : {},
...trace ? { trace } : {}
};
}
function isLogRedactionDisabled() {
return readLoggingConfig()?.redactSensitive === "off";
}
function redactLogRecordForTransport(record) {
return isLogRedactionDisabled() ? record : redactSecrets(record);
}
function attachDiagnosticEventTransport(logger) {
logger.attachTransport((logObj) => {
try {
emitDiagnosticEvent(buildDiagnosticLogRecord(redactLogRecordForTransport(logObj)));
} catch {}
});
}
function canUseSilentVitestFileLogFastPath(envLevel) {
return process.env.VITEST === "true" && process.env.OPENCLAW_TEST_FILE_LOG !== "1" && !envLevel && !loggingState.overrideSettings;
}
function resolveDefaultActiveLogFile() {
if (process.env.VITEST === "true" && process.env.OPENCLAW_TEST_FILE_LOG === "1") return path.join(process.cwd(), ".artifacts", "test-logs", `${LOG_PREFIX}-vitest-${process.pid}-${formatLocalDate(/* @__PURE__ */ new Date())}${LOG_SUFFIX}`);
return defaultRollingPathForToday();
}
function resolveSettings() {
if (!canUseNodeFs()) return {
level: "silent",
file: DEFAULT_LOG_FILE,
maxFileBytes: DEFAULT_MAX_LOG_FILE_BYTES
};
const envLevel = resolveEnvLogLevelOverride();
if (canUseSilentVitestFileLogFastPath(envLevel)) return {
level: "silent",
file: defaultRollingPathForToday(),
maxFileBytes: DEFAULT_MAX_LOG_FILE_BYTES
};
const cfg = loggingState.overrideSettings ?? loadLoggerConfig();
const defaultLevel = process.env.VITEST === "true" && process.env.OPENCLAW_TEST_FILE_LOG !== "1" ? "silent" : "info";
const fromConfig = normalizeLogLevel(cfg?.level, defaultLevel);
return {
level: envLevel ?? fromConfig,
file: cfg?.file ?? resolveDefaultActiveLogFile(),
maxFileBytes: resolveMaxLogFileBytes(cfg?.maxFileBytes)
};
}
function settingsChanged(a, b) {
if (!a) return true;
return a.level !== b.level || a.file !== b.file || a.maxFileBytes !== b.maxFileBytes;
}
function isFileLogLevelEnabled(level) {
const settings = loggingState.cachedSettings ?? resolveSettings();
if (!loggingState.cachedSettings) loggingState.cachedSettings = settings;
if (level === "silent") return false;
if (settings.level === "silent") return false;
return levelToMinLevel(level) >= levelToMinLevel(settings.level);
}
function buildLogger(settings) {
const logger = new Logger({
name: "openclaw",
maskValuesOfKeys: [],
minLevel: levelToMinLevel(settings.level),
type: "hidden"
});
if (settings.level === "silent") {
attachDiagnosticEventTransport(logger);
return logger;
}
const rollingFile = isRollingPath(settings.file);
let activeFile = resolveActiveLogFile(settings.file);
fs.mkdirSync(path.dirname(activeFile), { recursive: true });
if (rollingFile) pruneOldRollingLogs(path.dirname(activeFile));
let currentFileBytes = getCurrentLogFileBytes(activeFile);
let warnedAboutRotationFailure = false;
logger.attachTransport((logObj) => {
try {
const nextActiveFile = resolveActiveLogFile(settings.file);
if (nextActiveFile !== activeFile) {
activeFile = nextActiveFile;
fs.mkdirSync(path.dirname(activeFile), { recursive: true });
if (rollingFile) pruneOldRollingLogs(path.dirname(activeFile));
currentFileBytes = getCurrentLogFileBytes(activeFile);
}
const time = formatTimestamp(logObj.date ?? /* @__PURE__ */ new Date(), { style: "long" });
const traceFields = buildTraceFileLogFields(logObj);
const structuredFields = buildStructuredFileLogFields(logObj);
const record = {
...logObj,
_meta: withResolvedLogMetaHostname(logObj["_meta"], structuredFields.hostname),
time,
...structuredFields,
...traceFields
};
const payload = `${redactSensitiveText(JSON.stringify(redactLogRecordForTransport(record)))}\n`;
const payloadBytes = Buffer.byteLength(payload, "utf8");
const nextBytes = currentFileBytes + payloadBytes;
if (currentFileBytes > 0 && nextBytes > settings.maxFileBytes) {
if (rotateLogFile(activeFile)) {
currentFileBytes = getCurrentLogFileBytes(activeFile);
warnedAboutRotationFailure = false;
} else if (!warnedAboutRotationFailure) {
warnedAboutRotationFailure = true;
process.stderr.write(`[openclaw] log file rotation failed; continuing writes file=${activeFile} maxFileBytes=${settings.maxFileBytes}\n`);
}
}
if (appendLogLine(activeFile, payload)) currentFileBytes += payloadBytes;
} catch {}
});
attachDiagnosticEventTransport(logger);
return logger;
}
function resolveMaxLogFileBytes(raw) {
if (typeof raw === "number" && Number.isFinite(raw) && raw > 0) return Math.floor(raw);
return DEFAULT_MAX_LOG_FILE_BYTES;
}
function getCurrentLogFileBytes(file) {
try {
return fs.statSync(file).size;
} catch {
return 0;
}
}
function appendLogLine(file, line) {
try {
appendRegularFileSync({
filePath: file,
content: line
});
return true;
} catch {
return false;
}
}
function getLogger() {
const settings = resolveSettings();
const cachedLogger = loggingState.cachedLogger;
const cachedSettings = loggingState.cachedSettings;
if (!cachedLogger || settingsChanged(cachedSettings, settings)) {
loggingState.cachedLogger = buildLogger(settings);
loggingState.cachedSettings = settings;
}
return loggingState.cachedLogger;
}
function getChildLogger(bindings, opts) {
const base = getLogger();
const minLevel = opts?.level ? levelToMinLevel(opts.level) : base.settings.minLevel;
const name = bindings ? JSON.stringify(bindings) : void 0;
return base.getSubLogger({
name,
minLevel,
prefix: bindings ? [name ?? ""] : []
});
}
function toPinoLikeLogger(logger, level) {
const buildChild = (bindings) => toPinoLikeLogger(logger.getSubLogger({
name: bindings ? JSON.stringify(bindings) : void 0,
minLevel: logger.settings.minLevel
}), level);
return {
level,
child: buildChild,
trace: (...args) => logger.trace(...args),
debug: (...args) => logger.debug(...args),
info: (...args) => logger.info(...args),
warn: (...args) => logger.warn(...args),
error: (...args) => logger.error(...args),
fatal: (...args) => logger.fatal(...args)
};
}
function getResolvedLoggerSettings() {
return resolveSettings();
}
function setLoggerOverride(settings) {
loggingState.overrideSettings = settings;
loggingState.cachedLogger = null;
loggingState.cachedSettings = null;
loggingState.cachedConsoleSettings = null;
}
function resetLogger() {
loggingState.cachedLogger = null;
loggingState.cachedSettings = null;
loggingState.cachedConsoleSettings = null;
loggingState.overrideSettings = null;
loadLoggerConfig = loadLoggerConfigDefault;
hostnameResolver = defaultHostnameResolver;
cachedHostname = null;
}
const testApi = {
resolveActiveLogFile,
setHostnameResolverForTests: (resolver) => {
hostnameResolver = resolver ?? defaultHostnameResolver;
cachedHostname = null;
},
shouldSkipMutatingLoggingConfigRead
};
function formatLocalDate(date) {
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
}
function defaultRollingPathForToday() {
return rollingPathForDate(DEFAULT_LOG_DIR, /* @__PURE__ */ new Date());
}
function rollingPathForDate(dir, date) {
const today = formatLocalDate(date);
return path.join(dir, `${LOG_PREFIX}-${today}${LOG_SUFFIX}`);
}
function resolveActiveLogFile(file) {
const expandedFile = expandHomePrefix(file);
if (!isRollingPath(expandedFile)) return expandedFile;
return rollingPathForDate(path.dirname(expandedFile), /* @__PURE__ */ new Date());
}
function isRollingPath(file) {
const base = path.basename(file);
return base.startsWith(`${LOG_PREFIX}-`) && base.endsWith(LOG_SUFFIX) && base.length === `${LOG_PREFIX}-YYYY-MM-DD${LOG_SUFFIX}`.length;
}
function pruneOldRollingLogs(dir) {
try {
const entries = fs.readdirSync(dir, { withFileTypes: true });
const cutoff = Date.now() - MAX_LOG_AGE_MS;
for (const entry of entries) {
if (!entry.isFile()) continue;
if (!entry.name.startsWith(`${LOG_PREFIX}-`) || !entry.name.endsWith(LOG_SUFFIX)) continue;
const fullPath = path.join(dir, entry.name);
try {
if (fs.statSync(fullPath).mtimeMs < cutoff) fs.rmSync(fullPath, { force: true });
} catch {}
}
} catch {}
}
function rotatedLogPath(file, index) {
const ext = path.extname(file);
return `${file.slice(0, file.length - ext.length)}.${index}${ext}`;
}
function rotateLogFile(file) {
try {
fs.mkdirSync(path.dirname(file), { recursive: true });
fs.rmSync(rotatedLogPath(file, MAX_ROTATED_LOG_FILES), { force: true });
for (let index = MAX_ROTATED_LOG_FILES - 1; index >= 1; index -= 1) {
const from = rotatedLogPath(file, index);
if (!fs.existsSync(from)) continue;
fs.renameSync(from, rotatedLogPath(file, index + 1));
}
if (fs.existsSync(file)) fs.renameSync(file, rotatedLogPath(file, 1));
return true;
} catch {
return false;
}
}
//#endregion
export { normalizeLogLevel as _, getResolvedLoggerSettings as a, setLoggerConfigLoaderForTests as c, toPinoLikeLogger as d, formatLocalIsoWithOffset as f, levelToMinLevel as g, ALLOWED_LOG_LEVELS as h, getLogger as i, setLoggerOverride as l, resolveEnvLogLevelOverride as m, DEFAULT_LOG_FILE as n, isFileLogLevelEnabled as o, formatTimestamp as p, getChildLogger as r, resetLogger as s, DEFAULT_LOG_DIR as t, testApi as u, tryParseLogLevel as v };