/* oxlint-disable no-console */
import { LogContext, } from '@rocicorp/logger';
import chalk from 'chalk';
import { pid } from 'node:process';
import { stringify } from "./bigint-json.js";
const colors = {
    debug: chalk.grey,
    warn: chalk.yellow,
    error: chalk.red,
};
/**
 * Returns an object for writing colorized output to a provided console.
 * Note this should only be used when console is a TTY (i.e., Node).
 */
export const colorConsole = {
    log: (...args) => {
        console.log(...args);
    },
    debug: (...args) => {
        console.debug(colors.debug(...args));
    },
    info: (...args) => {
        console.info(...args);
    },
    warn: (...args) => {
        console.warn(colors.warn(...args));
    },
    error: (...args) => {
        console.error(colors.error(...args));
    },
};
export const consoleSink = {
    log(level, context, ...args) {
        colorConsole[level](stringifyContext(context), ...args.map(stringifyValue));
    },
};
export function getLogSink(config) {
    return config.format === 'json' ? consoleJsonLogSink : consoleSink;
}
export function createLogContext({ log }, context = {}, sink = getLogSink(log)) {
    const ctx = { pid, ...context };
    const lc = new LogContext(log.level, ctx, sink);
    // Emit a blank line to absorb random ANSI control code garbage that
    // for some reason gets prepended to the first log line in CloudWatch.
    lc.info?.('');
    return lc;
}
const consoleJsonLogSink = {
    log(level, context, ...args) {
        // If the last arg is an object or an Error, combine those fields into the message.
        const lastObj = errorOrObject(args.at(-1));
        if (lastObj) {
            args.pop();
        }
        const message = args.length
            ? {
                message: args.map(stringifyValue).join(' '),
            }
            : undefined;
        console[level](stringify({
            level: level.toUpperCase(),
            ...context,
            ...lastObj,
            ...message,
        }));
    },
};
export function errorOrObject(v) {
    if (v instanceof Error) {
        return {
            ...v, // some properties of Error subclasses may be enumerable
            name: v.name,
            errorMsg: v.message,
            stack: v.stack,
            ...('cause' in v ? { cause: errorOrObject(v.cause) } : null),
        };
    }
    if (v && typeof v === 'object') {
        return v;
    }
    return undefined;
}
function stringifyContext(context) {
    const args = [];
    for (const [k, v] of Object.entries(context ?? {})) {
        const arg = v === undefined ? k : `${k}=${v}`;
        args.push(arg);
    }
    return args;
}
function stringifyValue(v) {
    if (typeof v === 'string') {
        return v;
    }
    return stringify(v);
}
//# sourceMappingURL=logging.js.map