@rivetkit/core
Version:
140 lines (116 loc) • 3.22 kB
text/typescript
import { getEnvUniversal } from "@/utils";
import {
type LevelIndex,
LevelNameMap,
type LogLevel,
LogLevels,
} from "./log-levels";
import {
castToLogValue,
formatTimestamp,
type LogEntry,
stringify,
} from "./logfmt";
interface LogRecord {
args: unknown[];
datetime: Date;
level: number;
levelName: string;
loggerName: string;
msg: string;
}
export class Logger {
name: string;
level: LogLevel;
constructor(name: string, level: LogLevel) {
this.name = name;
this.level = level;
}
log(level: LevelIndex, message: string, ...args: unknown[]): void {
const record: LogRecord = {
msg: message,
args,
level,
loggerName: this.name,
datetime: new Date(),
levelName: LevelNameMap[level],
};
if (this.#shouldLog(level)) {
this.#logRecord(record);
}
}
#shouldLog(level: LevelIndex): boolean {
return level >= LogLevels[this.level];
}
#logRecord(record: LogRecord): void {
console.log(formatter(record));
}
trace(message: string, ...args: unknown[]): void {
this.log(LogLevels.TRACE, message, ...args);
}
debug(message: string, ...args: unknown[]): void {
this.log(LogLevels.DEBUG, message, ...args);
}
info(message: string, ...args: unknown[]): void {
this.log(LogLevels.INFO, message, ...args);
}
warn(message: string, ...args: unknown[]): void {
this.log(LogLevels.WARN, message, ...args);
}
error(message: string, ...args: unknown[]): void {
this.log(LogLevels.ERROR, message, ...args);
}
critical(message: string, ...args: unknown[]): void {
this.log(LogLevels.CRITICAL, message, ...args);
}
}
const loggers: Record<string, Logger> = {};
export function getLogger(name = "default"): Logger {
const defaultLogLevelEnv: LogLevel | undefined = getEnvUniversal(
"_LOG_LEVEL",
) as LogLevel | undefined;
const defaultLogLevel: LogLevel = defaultLogLevelEnv ?? "INFO";
if (!loggers[name]) {
loggers[name] = new Logger(name, defaultLogLevel);
}
return loggers[name];
}
function formatter(log: LogRecord): string {
const args: LogEntry[] = [];
for (let i = 0; i < log.args.length; i++) {
const logArg = log.args[i];
if (logArg && typeof logArg === "object") {
// Spread object
for (const k in logArg) {
// biome-ignore lint/suspicious/noExplicitAny: Unknown type
const v = (logArg as any)[k];
pushArg(k, v, args);
}
} else {
pushArg(`arg${i}`, logArg, args);
}
}
const logTs = getEnvUniversal("_LOG_TIMESTAMP") === "1";
const logTarget = getEnvUniversal("_LOG_TARGET") === "1";
return stringify(
...(logTs ? [["ts", formatTimestamp(new Date())] as LogEntry] : []),
["level", LevelNameMap[log.level]],
...(logTarget ? [["target", log.loggerName] as LogEntry] : []),
["msg", log.msg],
...args,
);
}
function pushArg(k: string, v: unknown, args: LogEntry[]) {
args.push([k, castToLogValue(v)]);
}
// function getEnv(name: string): string | undefined {
// if (typeof window !== "undefined" && window.localStorage) {
// return window.localStorage.getItem(name) || undefined;
// }
// return undefined;
// // TODO(ACTR-9): Add back env config once node compat layer works
// //return crossGetEnv(name);
// }
export function setupLogging() {
// Do nothing for now
}