import * as IO from "fp-ts/lib/IO"; import { pino, Logger as PinoLogger } from "pino"; import type { Config } from "../../config"; import { pinoMixin as telemetryMixin } from "../telemetry/instrumentations/pino"; export interface Logger { readonly fatal: (message: string, payload?: unknown) => IO.IO; readonly error: (message: string, payload?: unknown) => IO.IO; readonly warn: (message: string, payload?: unknown) => IO.IO; readonly info: (message: string, payload?: unknown) => IO.IO; readonly debug: (message: string, payload?: unknown) => IO.IO; readonly trace: (message: string, payload?: unknown) => IO.IO; readonly silent: (message: string, payload?: unknown) => IO.IO; readonly flush: () => IO.IO; } export function createLogger( serviceName: string, { config }: { readonly config: Config } ): Logger { const logger = pino({ name: "app", level: config.logLevel, formatters: { // format level as string instead of number level(label) { return { level: label }; }, }, timestamp: pino.stdTimeFunctions.isoTime, mixin: telemetryMixin, }).child({ serviceName, }); return makePinoFunctionalWrapper(logger); } function makePinoFunctionalWrapper(logger: PinoLogger) { return { fatal(message: string, payload?: unknown) { return () => logger.fatal(payload, message); }, error(message: string, payload?: unknown) { return () => logger.error(payload ?? {}, message); }, warn(message: string, payload?: unknown) { return () => logger.warn(payload ?? {}, message); }, info(message: string, payload?: unknown) { return () => logger.info(payload ?? {}, message); }, debug(message: string, payload?: unknown) { return () => logger.debug(payload ?? {}, message); }, trace(message: string, payload?: unknown) { return () => logger.trace(payload ?? {}, message); }, silent(message: string, payload?: unknown) { return () => logger.silent(payload ?? {}, message); }, flush() { return () => logger.flush(); }, }; }