mirror of
https://github.com/orangecoding/fredy.git
synced 2026-06-16 12:31:07 +00:00
adding ability to record logs for debug purposes
This commit is contained in:
@@ -14,6 +14,20 @@ const COLORS = {
|
||||
const env = process.env.NODE_ENV || 'development';
|
||||
const useColor = process.stdout.isTTY || process.stderr.isTTY;
|
||||
|
||||
/**
|
||||
* Optional sink that forwards formatted log entries to the opt-in "Debug Logging"
|
||||
* DB storage. Wired and unwired by debugLogStorage as the feature is toggled, so
|
||||
* when nobody enabled the feature this stays null and the logger hot path skips
|
||||
* the Date.now + stringifyArgs work entirely.
|
||||
*
|
||||
* We deliberately do NOT import debugLogStorage here, because that would create a
|
||||
* cycle (debugLogStorage → SqliteConnection → utils → logger → debugLogStorage).
|
||||
* Inversion of control via setDebugLogSink() keeps the dependency one-way.
|
||||
*
|
||||
* @type {((entry:{ts:number, level:string, message:string}) => void)|null}
|
||||
*/
|
||||
let debugLogSink = null;
|
||||
|
||||
function ts() {
|
||||
const d = new Date();
|
||||
const yyyy = d.getFullYear();
|
||||
@@ -31,10 +45,50 @@ function lvl(level) {
|
||||
return `${COLORS[level] || ''}${upper}${COLORS.reset}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a colour-free plain text representation of variadic console args. Errors
|
||||
* are unwrapped to their stack/message, objects are JSON-serialized. Used when
|
||||
* forwarding to the DB sink so the stored text is portable across terminals.
|
||||
*
|
||||
* @param {any[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
function stringifyArgs(args) {
|
||||
return args
|
||||
.map((a) => {
|
||||
if (a == null) return String(a);
|
||||
if (a instanceof Error) return a.stack || a.message;
|
||||
if (typeof a === 'object') {
|
||||
try {
|
||||
return JSON.stringify(a);
|
||||
} catch {
|
||||
return String(a);
|
||||
}
|
||||
}
|
||||
return String(a);
|
||||
})
|
||||
.join(' ');
|
||||
}
|
||||
|
||||
/* eslint-disable no-console */
|
||||
function log(level, ...args) {
|
||||
// Forward to the DB sink first (regardless of console suppression rules) so the
|
||||
// recorded debug bundle truly contains every level, including debug entries that
|
||||
// would otherwise be silenced in production.
|
||||
if (debugLogSink) {
|
||||
try {
|
||||
debugLogSink({
|
||||
ts: Date.now(),
|
||||
level,
|
||||
message: `${stringifyArgs(args)}`,
|
||||
});
|
||||
} catch {
|
||||
// never break the caller because of logging
|
||||
}
|
||||
}
|
||||
|
||||
if (level === 'debug' && env !== 'development') {
|
||||
return; // Skip debug logs in non-development environments
|
||||
return; // Skip debug logs in non-development environments (console only)
|
||||
}
|
||||
|
||||
const prefix = `[${ts()}] ${lvl(level)}:`;
|
||||
@@ -56,9 +110,28 @@ function log(level, ...args) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a sink function that receives every log entry the logger sees, regardless
|
||||
* of console suppression rules. debugLogStorage attaches its sink only while the
|
||||
* feature is enabled and detaches it on disable, so the logger's hot path can use
|
||||
* the null check as a cheap on/off gate and skip stringification when off.
|
||||
*
|
||||
* Pass null to remove the sink (used both by the storage module on disable and by
|
||||
* tests to reset state between cases).
|
||||
*
|
||||
* @param {((entry:{ts:number, level:string, message:string}) => void)|null} sink
|
||||
* @returns {void}
|
||||
*/
|
||||
function setDebugLogSink(sink) {
|
||||
debugLogSink = typeof sink === 'function' ? sink : null;
|
||||
}
|
||||
|
||||
export { setDebugLogSink };
|
||||
|
||||
export default {
|
||||
debug: (...a) => log('debug', ...a),
|
||||
info: (...a) => log('info', ...a),
|
||||
warn: (...a) => log('warn', ...a),
|
||||
error: (...a) => log('error', ...a),
|
||||
setDebugLogSink,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user