UNPKG

inngest

Version:

Official SDK for Inngest.com. Inngest is the reliability layer for modern applications. Inngest combines durable execution, events, and queues into a zero-infra platform with built-in observability.

1 lines 7.57 kB
{"version":3,"file":"logger.cjs","names":["isRecord","effectiveLevel: CallableLogLevel","resolveNextTick"],"sources":["../../src/middleware/logger.ts"],"sourcesContent":["import { resolveNextTick } from \"../helpers/promises.ts\";\nimport { isRecord } from \"../helpers/types.ts\";\nimport type { LogLevel } from \"../types.ts\";\n\n/**\n * All kinds of arguments can come through\n *\n * Examples seen are\n * - string\n * - object / hash\n * - values used for string interpolation, basically anything\n *\n * See https://linear.app/inngest/issue/INN-1342/flush-logs-on-function-exitreturns for more details\n *\n * @public\n */\nexport type LogArg = unknown;\n\n/**\n * Based on https://datatracker.ietf.org/doc/html/rfc5424#autoid-11\n * it's pretty reasonable to expect a logger to have the following interfaces\n * available.\n */\nexport interface Logger {\n info(...args: LogArg[]): void;\n warn(...args: LogArg[]): void;\n error(...args: LogArg[]): void;\n debug(...args: LogArg[]): void;\n}\n\n/**\n * Numeric ranking for log levels. Higher = more severe.\n * Used to determine if a message should be logged based on configured level.\n */\nconst LOG_LEVEL_RANK = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n} as const;\n\ntype CallableLogLevel = keyof typeof LOG_LEVEL_RANK;\n\n/**\n * Console-based logger. Not for production use.\n */\nexport class ConsoleLogger implements Logger {\n private readonly level: LogLevel;\n\n constructor(opts: { level?: LogLevel } = {}) {\n this.level = opts.level ?? \"info\";\n }\n\n info(...args: LogArg[]) {\n if (this.shouldLog(\"info\")) {\n this.logFormatted(console.info, args);\n }\n }\n\n warn(...args: LogArg[]) {\n if (this.shouldLog(\"warn\")) {\n this.logFormatted(console.warn, args);\n }\n }\n\n error(...args: LogArg[]) {\n if (this.shouldLog(\"error\")) {\n this.logFormatted(console.error, args);\n }\n }\n\n debug(...args: LogArg[]) {\n if (this.shouldLog(\"debug\")) {\n this.logFormatted(console.debug, args);\n }\n }\n\n /**\n * Detect Pino-style `(object, string, ...rest)` calls and reformat for\n * console readability: message first, then structured fields.\n */\n private logFormatted(fn: (...args: LogArg[]) => void, args: LogArg[]) {\n if (args.length > 1 && isRecord(args[0]) && typeof args[1] === \"string\") {\n const fields = args[0];\n const nonErrFields = Object.fromEntries(\n Object.entries(fields).filter(([key]) => {\n return key !== \"err\";\n }),\n );\n const [, message, ...rest] = args;\n\n fn(message);\n\n if (fields.err) {\n fn(fields.err);\n }\n\n if (Object.keys(nonErrFields).length > 0) {\n fn(nonErrFields);\n }\n\n if (rest.length > 0) {\n fn(...rest);\n }\n\n return;\n }\n\n fn(...args);\n }\n\n private shouldLog(level: CallableLogLevel): boolean {\n if (this.level === \"silent\") {\n return false;\n }\n\n // Map configured level to a callable level (fatal -> error)\n let effectiveLevel: CallableLogLevel = \"info\";\n if (this.level === \"fatal\") {\n effectiveLevel = \"error\";\n } else if (this.level in LOG_LEVEL_RANK) {\n effectiveLevel = this.level as CallableLogLevel;\n }\n\n return LOG_LEVEL_RANK[level] >= LOG_LEVEL_RANK[effectiveLevel];\n }\n}\n\n/**\n * ProxyLogger aims to provide a thin wrapper on user's provided logger.\n * It's expected to be turned on and off based on the function execution\n * context, so it doesn't result in duplicated logging.\n *\n * And also attempt to allow enough time for the logger to flush all logs.\n *\n * @public\n */\nexport class ProxyLogger implements Logger {\n private readonly logger: Logger;\n private enabled = false;\n\n constructor(logger: Logger) {\n this.logger = logger;\n\n // Return a Proxy to forward arbitrary property access to the underlying\n // logger. For example, if the user provides a logger that has a `foo`\n // method, they can call `foo` on the ProxyLogger and it will call the\n // underlying logger's `foo` method.\n return new Proxy(this, {\n get(target, prop, receiver): unknown {\n // Handle ProxyLogger's own methods/properties.\n if (prop in target) {\n return Reflect.get(target, prop, receiver);\n }\n\n // Forward property access to the underlying logger.\n return Reflect.get(target.logger, prop, receiver);\n },\n }) as ProxyLogger;\n }\n\n info(...args: LogArg[]) {\n if (!this.enabled) {\n return;\n }\n this.logger.info(...args);\n }\n\n warn(...args: LogArg[]) {\n if (!this.enabled) {\n return;\n }\n this.logger.warn(...args);\n }\n\n error(...args: LogArg[]) {\n if (!this.enabled) {\n return;\n }\n this.logger.error(...args);\n }\n\n debug(...args: LogArg[]) {\n if (!this.enabled || !(typeof this.logger.debug === \"function\")) {\n return;\n }\n this.logger.debug(...args);\n }\n\n enable() {\n this.enabled = true;\n }\n\n disable() {\n this.enabled = false;\n }\n\n async flush() {\n // If ConsoleLogger, nothing to wait for\n if (this.logger.constructor.name == ConsoleLogger.name) {\n return;\n }\n\n const logger = this.logger as Logger & {\n flush?: () => Promise<void> | void;\n };\n\n // If the logger has its own flush, defer to it\n if (typeof logger.flush === \"function\") {\n await logger.flush();\n return;\n }\n\n // Otherwise yield one event-loop tick (non-blocking hint for buffered loggers)\n await resolveNextTick();\n }\n}\n"],"mappings":";;;;;;;;AAkCA,MAAM,iBAAiB;CACrB,OAAO;CACP,MAAM;CACN,MAAM;CACN,OAAO;CACR;;;;AAOD,IAAa,gBAAb,MAA6C;CAC3C,AAAiB;CAEjB,YAAY,OAA6B,EAAE,EAAE;AAC3C,OAAK,QAAQ,KAAK,SAAS;;CAG7B,KAAK,GAAG,MAAgB;AACtB,MAAI,KAAK,UAAU,OAAO,CACxB,MAAK,aAAa,QAAQ,MAAM,KAAK;;CAIzC,KAAK,GAAG,MAAgB;AACtB,MAAI,KAAK,UAAU,OAAO,CACxB,MAAK,aAAa,QAAQ,MAAM,KAAK;;CAIzC,MAAM,GAAG,MAAgB;AACvB,MAAI,KAAK,UAAU,QAAQ,CACzB,MAAK,aAAa,QAAQ,OAAO,KAAK;;CAI1C,MAAM,GAAG,MAAgB;AACvB,MAAI,KAAK,UAAU,QAAQ,CACzB,MAAK,aAAa,QAAQ,OAAO,KAAK;;;;;;CAQ1C,AAAQ,aAAa,IAAiC,MAAgB;AACpE,MAAI,KAAK,SAAS,KAAKA,uBAAS,KAAK,GAAG,IAAI,OAAO,KAAK,OAAO,UAAU;GACvE,MAAM,SAAS,KAAK;GACpB,MAAM,eAAe,OAAO,YAC1B,OAAO,QAAQ,OAAO,CAAC,QAAQ,CAAC,SAAS;AACvC,WAAO,QAAQ;KACf,CACH;GACD,MAAM,GAAG,SAAS,GAAG,QAAQ;AAE7B,MAAG,QAAQ;AAEX,OAAI,OAAO,IACT,IAAG,OAAO,IAAI;AAGhB,OAAI,OAAO,KAAK,aAAa,CAAC,SAAS,EACrC,IAAG,aAAa;AAGlB,OAAI,KAAK,SAAS,EAChB,IAAG,GAAG,KAAK;AAGb;;AAGF,KAAG,GAAG,KAAK;;CAGb,AAAQ,UAAU,OAAkC;AAClD,MAAI,KAAK,UAAU,SACjB,QAAO;EAIT,IAAIC,iBAAmC;AACvC,MAAI,KAAK,UAAU,QACjB,kBAAiB;WACR,KAAK,SAAS,eACvB,kBAAiB,KAAK;AAGxB,SAAO,eAAe,UAAU,eAAe;;;;;;;;;;;;AAanD,IAAa,cAAb,MAA2C;CACzC,AAAiB;CACjB,AAAQ,UAAU;CAElB,YAAY,QAAgB;AAC1B,OAAK,SAAS;AAMd,SAAO,IAAI,MAAM,MAAM,EACrB,IAAI,QAAQ,MAAM,UAAmB;AAEnC,OAAI,QAAQ,OACV,QAAO,QAAQ,IAAI,QAAQ,MAAM,SAAS;AAI5C,UAAO,QAAQ,IAAI,OAAO,QAAQ,MAAM,SAAS;KAEpD,CAAC;;CAGJ,KAAK,GAAG,MAAgB;AACtB,MAAI,CAAC,KAAK,QACR;AAEF,OAAK,OAAO,KAAK,GAAG,KAAK;;CAG3B,KAAK,GAAG,MAAgB;AACtB,MAAI,CAAC,KAAK,QACR;AAEF,OAAK,OAAO,KAAK,GAAG,KAAK;;CAG3B,MAAM,GAAG,MAAgB;AACvB,MAAI,CAAC,KAAK,QACR;AAEF,OAAK,OAAO,MAAM,GAAG,KAAK;;CAG5B,MAAM,GAAG,MAAgB;AACvB,MAAI,CAAC,KAAK,WAAW,EAAE,OAAO,KAAK,OAAO,UAAU,YAClD;AAEF,OAAK,OAAO,MAAM,GAAG,KAAK;;CAG5B,SAAS;AACP,OAAK,UAAU;;CAGjB,UAAU;AACR,OAAK,UAAU;;CAGjB,MAAM,QAAQ;AAEZ,MAAI,KAAK,OAAO,YAAY,QAAQ,cAAc,KAChD;EAGF,MAAM,SAAS,KAAK;AAKpB,MAAI,OAAO,OAAO,UAAU,YAAY;AACtC,SAAM,OAAO,OAAO;AACpB;;AAIF,QAAMC,kCAAiB"}