@catbee/utils
Version:
A modular, production-grade utility toolkit for Node.js and TypeScript, designed for robust, scalable applications (including Express-based services). All utilities are tree-shakable and can be imported independently.
141 lines • 5.47 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports._globalThis = void 0;
exports.getLogger = getLogger;
exports.createChildLogger = createChildLogger;
exports.createRequestLogger = createRequestLogger;
exports.logError = logError;
const pino_1 = __importStar(require("pino"));
const config_1 = require("../config");
const context_store_utils_1 = require("./context-store.utils");
/**
* Symbol used to store the root logger in the Node.js global object.
*/
const GLOBAL_LOGGER_KEY = Symbol.for("logger");
/**
* Use an object compatible with either modern or legacy global scopes.
*/
exports._globalThis = typeof globalThis === "object" ? globalThis : global;
const _global = exports._globalThis;
/**
* Initializes the global root logger according to app configuration.
*
* - Sets log name, level, timestamp, and redaction for sensitive fields.
* - Uses singleton in global symbol registry.
*/
function setupLogger() {
const logParams = {
name: config_1.Config.Logger.name,
level: config_1.Config.Logger.level,
redact: {
paths: ["req.authorization", "url"],
censor(value, path) {
if (path[0] === "url") {
return value.replace(/access_token=[a-zA-Z0-9_-]*/, "access_token=***");
}
else if (path[1] === "authorization") {
return value.replace(/\s+(\S+)$/, " ***");
}
return "***";
},
},
};
if (config_1.Config.Logger.isoTimestamp) {
logParams.timestamp = pino_1.stdTimeFunctions.isoTime;
}
_global[GLOBAL_LOGGER_KEY] = (0, pino_1.default)(logParams);
_global[GLOBAL_LOGGER_KEY].debug("Logger initialized");
}
/**
* Retrieves the current logger instance:
* - Returns a request-scoped logger from AsyncLocalStorage if available
* - Falls back to the global (singleton) logger
* - Initializes the global logger if not created yet
*
* @returns {Logger} The logger instance (request-bound or global root logger)
*/
function getLogger() {
const logger = context_store_utils_1.ContextStore.get(context_store_utils_1.StoreKeys.LOGGER);
if (logger)
return logger;
if (!_global[GLOBAL_LOGGER_KEY]) {
setupLogger();
}
return _global[GLOBAL_LOGGER_KEY];
}
/**
* Creates a child logger with additional context.
*
* @param {Record<string, any>} bindings - Properties to attach to all log records
* @param {Logger} [parentLogger] - Parent logger (defaults to current context logger or global)
* @returns {Logger} Child logger with merged context
*/
function createChildLogger(bindings, parentLogger) {
const logger = parentLogger || getLogger();
return logger.child(bindings);
}
/**
* Creates a request-scoped logger with request ID and stores it in context
*
* @param {string} requestId - Unique request identifier
* @param {object} [additionalContext] - Additional context to include in logs
* @returns {Logger} Request-scoped logger instance
*/
function createRequestLogger(requestId, additionalContext = {}) {
const logger = createChildLogger(Object.assign({ requestId }, additionalContext));
try {
context_store_utils_1.ContextStore.set(context_store_utils_1.StoreKeys.LOGGER, logger);
}
catch (_a) {
// Context not initialized, can't store logger
logger.debug("Failed to store logger in context - AsyncLocalStorage not initialized");
}
return logger;
}
/**
* Utility to safely log errors with proper stack trace extraction
*
* @param {Error|unknown} error - Error object to log
* @param {string} [message] - Optional message to include
* @param {Record<string, any>} [context] - Additional context properties
*/
function logError(error, message, context) {
const logger = getLogger();
const errObj = error instanceof Error ? error : new Error(String(error));
const logContext = Object.assign(Object.assign({}, context), { err: errObj });
logger.error(logContext, message || errObj.message);
}
//# sourceMappingURL=logger.utils.js.map