import * as Sentry from "@sentry/nextjs" import { flatten } from "flat" import { minimumLogLevel } from "./minimumLogLevel" import { shouldLog } from "./shouldLog" import type { logLevels } from "./logLevels" function getLogValue(args: unknown[]): Record | undefined { if (!args || args.length === 0) { return undefined } if (args.length === 1 && typeof args[0] === "object") { return (args[0] as Record) ?? undefined } if (args.length === 1) { if (args[0] instanceof Error) { return { error: { message: args[0].message, stack: args[0].stack, name: args[0].name, cause: String(args[0].cause), digest: "digest" in args[0] && args[0].digest ? String(args[0].digest) : undefined, }, } } return { value: args[0] } } return flatten(args) } export function createLogger(loggerPrefix: string | (() => Promise)) { const asyncWrapper: () => Promise = typeof loggerPrefix === "string" ? async () => loggerPrefix : loggerPrefix const getLoggerPrefix = async () => { const prefix = await asyncWrapper() if (!prefix) { return "" } return `[${prefix}]` } async function log( level: (typeof logLevels)[number], message: string, ...args: unknown[] ) { if (!shouldLog(level, minimumLogLevel)) { return } const logValue = getLogValue(args) Sentry.logger[level]( `${await getLoggerPrefix()} ${message}`.trim(), logValue ) // eslint-disable-next-line no-console console[level](`${await getLoggerPrefix()} ${message}`.trim(), ...args) } return { async debug(message: string, ...args: unknown[]): Promise { await log("debug", message, ...args) }, async info(message: string, ...args: unknown[]): Promise { await log("info", message, ...args) }, async warn(message: string, ...args: unknown[]): Promise { await log("warn", message, ...args) }, async error(message: string, ...args: unknown[]): Promise { await log("error", message, ...args) }, } }