@lorefnon/tslog
Version:
Extensible TypeScript Logger for Node.js and Browser.
130 lines (129 loc) • 5 kB
JavaScript
import { hostname } from "os";
import { normalize as fileNormalize } from "path";
import { types, formatWithOptions } from "util";
import { formatTemplate } from "../../formatTemplate.js";
export default {
getCallerStackFrame,
getErrorTrace,
getMeta,
transportJSON,
transportFormatted,
isBuffer,
isError,
prettyFormatLogObj,
prettyFormatErrorObj,
};
const meta = {
runtime: "Nodejs",
runtimeVersion: process?.version,
hostname: hostname ? hostname() : undefined,
};
export function getMeta(logLevelId, logLevelName, stackDepthLevel, hideLogPositionForPerformance, name, parentNames) {
return Object.assign({}, meta, {
name,
parentNames,
date: new Date(),
logLevelId,
logLevelName,
path: !hideLogPositionForPerformance ? getCallerStackFrame(stackDepthLevel) : undefined,
});
}
export function getCallerStackFrame(stackDepthLevel, error = Error()) {
return stackLineToStackFrame(error?.stack?.split("\n")?.filter((thisLine) => thisLine.includes(" at "))?.[stackDepthLevel]);
}
export function getErrorTrace(error) {
return error?.stack?.split("\n")?.reduce((result, line) => {
if (line.includes(" at ")) {
result.push(stackLineToStackFrame(line));
}
return result;
}, []);
}
function stackLineToStackFrame(line) {
const pathResult = {
fullFilePath: undefined,
fileName: undefined,
fileNameWithLine: undefined,
fileColumn: undefined,
fileLine: undefined,
filePath: undefined,
filePathWithLine: undefined,
method: undefined,
};
if (line != null && line.includes(" at ")) {
line = line.replace(/^\s+at\s+/gm, "");
const errorStackLine = line.split(" (");
const fullFilePath = line?.slice(-1) === ")" ? line?.match(/\(([^)]+)\)/)?.[1] : line;
const pathArray = fullFilePath?.includes(":") ? fullFilePath?.replace("file://", "")?.replace(process.cwd(), "")?.split(":") : undefined;
const fileColumn = pathArray?.pop();
const fileLine = pathArray?.pop();
const filePath = pathArray?.pop();
const filePathWithLine = fileNormalize(`${filePath}:${fileLine}`);
const fileName = filePath?.split("/")?.pop();
const fileNameWithLine = `${fileName}:${fileLine}`;
if (filePath != null && filePath.length > 0) {
pathResult.fullFilePath = fullFilePath;
pathResult.fileName = fileName;
pathResult.fileNameWithLine = fileNameWithLine;
pathResult.fileColumn = fileColumn;
pathResult.fileLine = fileLine;
pathResult.filePath = filePath;
pathResult.filePathWithLine = filePathWithLine;
pathResult.method = errorStackLine?.[1] != null ? errorStackLine?.[0] : undefined;
}
}
return pathResult;
}
export function isError(e) {
return types?.isNativeError != null ? types.isNativeError(e) : e instanceof Error;
}
export function prettyFormatLogObj(maskedArgs, settings) {
return maskedArgs.reduce((result, arg) => {
isError(arg) ? result.errors.push(prettyFormatErrorObj(arg, settings)) : result.args.push(arg);
return result;
}, { args: [], errors: [] });
}
export function prettyFormatErrorObj(error, settings) {
const errorStackStr = getErrorTrace(error).map((stackFrame) => {
return formatTemplate(settings, settings.prettyErrorStackTemplate, { ...stackFrame }, true);
});
const placeholderValuesError = {
errorName: ` ${error.name} `,
errorMessage: Object.getOwnPropertyNames(error)
.reduce((result, key) => {
if (key !== "stack") {
result.push(error[key]);
}
return result;
}, [])
.join(", "),
errorStack: errorStackStr.join("\n"),
};
return formatTemplate(settings, settings.prettyErrorTemplate, placeholderValuesError);
}
export function transportFormatted(logMetaMarkup, logArgs, logErrors, settings) {
const logErrorsStr = (logErrors.length > 0 && logArgs.length > 0 ? "\n" : "") + logErrors.join("\n");
settings.prettyInspectOptions.colors = settings.stylePrettyLogs;
console.log(logMetaMarkup + formatWithOptions(settings.prettyInspectOptions, ...logArgs) + logErrorsStr);
}
export function transportJSON(json) {
console.log(jsonStringifyRecursive(json));
function jsonStringifyRecursive(obj) {
const cache = new Set();
return JSON.stringify(obj, (key, value) => {
if (typeof value === "object" && value !== null) {
if (cache.has(value)) {
return "[Circular]";
}
cache.add(value);
}
if (typeof value === "bigint") {
return `${value}`;
}
return value;
});
}
}
export function isBuffer(arg) {
return Buffer.isBuffer(arg);
}