try fix for windows, change how logging works allows much more flexibility
All checks were successful
Code quality checks / biome (push) Successful in 9s

This commit is contained in:
creations 2025-06-11 18:24:48 -04:00
parent 15d4978ac5
commit f313a8a329
Signed by: creations
GPG key ID: 8F553AA4320FC711
6 changed files with 297 additions and 51 deletions

View file

@ -1,8 +1,8 @@
import { basename } from "node:path";
import { format, inspect } from "node:util";
import { ansiColors, defaultLevelColor, logLevelValues } from "@lib/config";
import { format as formatDate } from "date-fns-tz";
import { ansiColors, defaultLevelColor, logLevelValues } from "@lib/config";
import type {
LogLevel,
LogLevelValue,
@ -59,6 +59,7 @@ function getCallerInfo(config: Required<LoggerConfig>): {
for (let i = 1; i < lines.length; i++) {
const line = lines[i].trim();
// try file:// URLs first (works on all platforms)
const fileURLMatch = line.match(
/at\s+(?:.*\()?file:\/\/(.*):(\d+):(\d+)\)?/,
);
@ -79,16 +80,16 @@ function getCallerInfo(config: Required<LoggerConfig>): {
};
}
const rawMatch = line.match(/at\s+(?:.*\()?(.+):(\d+):(\d+)\)?/);
if (rawMatch) {
const [_, fullPath, lineNumber, columnNumber] = rawMatch;
const pathMatch = parseStackTracePath(line);
if (pathMatch) {
const { fullPath, lineNumber, columnNumber } = pathMatch;
const isInternal =
fullPath.includes("atums.echo") || fullPath.includes("@atums/echo");
if (isInternal) continue;
return {
id: id,
id,
fileName: basename(fullPath),
line: lineNumber,
column: columnNumber,
@ -101,6 +102,59 @@ function getCallerInfo(config: Required<LoggerConfig>): {
return fallback;
}
function parseStackTracePath(line: string): {
fullPath: string;
lineNumber: string;
columnNumber: string;
} | null {
// remove "at " prefix and trim
const cleanLine = line.replace(/^\s*at\s+/, "").trim();
let pathPart: string;
// extract path from parentheses if present
const parenMatch = cleanLine.match(/\(([^)]+)\)$/);
if (parenMatch) {
pathPart = parenMatch[1];
} else {
pathPart = cleanLine;
}
let match: RegExpMatchArray | null = null;
if (process.platform === "win32") {
// windows-specific parsing
// handle drive letters (C:) vs line numbers (:10:5)
match = pathPart.match(
/^((?:[a-zA-Z]:|\\\\[^\\]+\\[^\\]+|[^:]+)):(\d+):(\d+)$/,
);
if (!match) {
// try alternative windows format with forward slashes
match = pathPart.match(/^([a-zA-Z]:[^:]+):(\d+):(\d+)$/);
}
if (!match) {
// try UNC path format
match = pathPart.match(/^(\\\\[^:]+):(\d+):(\d+)$/);
}
} else {
// unix-like systems (Linux, macOS)
match = pathPart.match(/^([^:]+):(\d+):(\d+)$/);
}
if (match) {
const [_, fullPath, lineNumber, columnNumber] = match;
return {
fullPath: fullPath.trim(),
lineNumber,
columnNumber,
};
}
return null;
}
function generateShortId(length = 8): string {
const chars =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
@ -166,13 +220,63 @@ function serializeLogData(data: unknown): unknown {
};
}
if (typeof data === "string" || typeof data === "number") {
if (
typeof data === "string" ||
typeof data === "number" ||
typeof data === "boolean" ||
data === null ||
data === undefined
) {
return data;
}
if (typeof data === "object") {
try {
return JSON.parse(JSON.stringify(data));
} catch (err) {
if (
(err instanceof TypeError && err.message.includes("circular")) ||
(err instanceof Error && err.message.includes("cyclic"))
) {
return createSafeObjectRepresentation(data);
}
return String(data);
}
}
return data;
}
function createSafeObjectRepresentation(
obj: unknown,
seen = new WeakSet(),
): unknown {
if (obj === null || typeof obj !== "object") {
return obj;
}
if (seen.has(obj as object)) {
return "[Circular Reference]";
}
seen.add(obj as object);
if (Array.isArray(obj)) {
return obj.map((item) => createSafeObjectRepresentation(item, seen));
}
const result: Record<string, unknown> = {};
for (const [key, value] of Object.entries(obj)) {
try {
result[key] = createSafeObjectRepresentation(value, seen);
} catch {
result[key] = "[Unserializable]";
}
}
return result;
}
function processPattern(
pattern: string,
tokens: PatternTokens,
@ -231,15 +335,23 @@ function processPattern(
return processed;
}
function formatMultipleData(
dataArray: unknown[],
config: Required<LoggerConfig>,
): string {
return dataArray.map((item) => formatData(item, config)).join(" ");
}
function parsePattern(ctx: PatternContext): string {
const { level, data, config } = ctx;
const { id, fileName, line, column, timestamp, prettyTimestamp } =
getCallerInfo(config);
const resolvedData: string = formatData(data, config);
const numericLevel: LogLevelValue = logLevelValues[level];
const resolvedData: string = Array.isArray(data)
? formatMultipleData(data, config)
: formatData(data, config);
const numericLevel: LogLevelValue = logLevelValues[level];
const tokens: PatternTokens = {
timestamp,
prettyTimestamp,
@ -251,7 +363,6 @@ function parsePattern(ctx: PatternContext): string {
data: resolvedData,
id,
};
return processPattern(config.pattern, tokens, config, level);
}