diff --git a/CHANGELOG.md b/CHANGELOG.md index f85fd69b3..1b87ad8b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,10 +9,10 @@ }); ``` - The logger can also override default behavior of `console.*` methods through a special require: +- Adds a special require that mimics Node.js 8 runtime logging in Node.js 10 and later runtimes: ```js require('firebase-functions/logger/compat'); ``` - In older runtimes, logger prints to the console, and no structured data is saved. + In newer runtimes, requiring this will emit text logs with multi-line support and appropriate severity. In the Node.js 8 runtime, the `compat` module has no effect. diff --git a/src/logger.ts b/src/logger.ts index 7d4c91cbf..258dbbdff 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -1,32 +1,10 @@ import { format } from 'util'; -// safely preserve unpatched console.* methods in case of compat require -const unpatchedConsole = { - debug: console.debug, - info: console.info, - log: console.log, - warn: console.warn, - error: console.error, -}; - -// Determine if structured logs are supported (node >= 10). If something goes wrong, -// assume no since unstructured is safer. -const SUPPORTS_STRUCTURED_LOGS = - parseInt(process.versions?.node?.split('.')?.[0] || '8', 10) >= 10; - -// Map LogSeverity types to their equivalent `console.*` method. -const CONSOLE_SEVERITY: { - [severity: string]: 'debug' | 'info' | 'warn' | 'error'; -} = { - DEBUG: 'debug', - INFO: 'info', - NOTICE: 'info', - WARNING: 'warn', - ERROR: 'error', - CRITICAL: 'error', - ALERT: 'error', - EMERGENCY: 'error', -}; +import { + SUPPORTS_STRUCTURED_LOGS, + CONSOLE_SEVERITY, + UNPATCHED_CONSOLE, +} from './logger/common'; /** * `LogSeverity` indicates the detailed severity of the log entry. See [LogSeverity](https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#logseverity) for more. @@ -57,7 +35,7 @@ export interface LogEntry { */ export function write(entry: LogEntry) { if (SUPPORTS_STRUCTURED_LOGS) { - unpatchedConsole[CONSOLE_SEVERITY[entry.severity]](JSON.stringify(entry)); + UNPATCHED_CONSOLE[CONSOLE_SEVERITY[entry.severity]](JSON.stringify(entry)); return; } @@ -73,7 +51,7 @@ export function write(entry: LogEntry) { if (jsonKeyCount > 0) { message = `${message} ${JSON.stringify(jsonPayload, null, 2)}`; } - unpatchedConsole[CONSOLE_SEVERITY[entry.severity]](message); + UNPATCHED_CONSOLE[CONSOLE_SEVERITY[entry.severity]](message); } /** diff --git a/src/logger/common.ts b/src/logger/common.ts new file mode 100644 index 000000000..f8b1f0ed9 --- /dev/null +++ b/src/logger/common.ts @@ -0,0 +1,27 @@ +// Determine if structured logs are supported (node >= 10). If something goes wrong, +// assume no since unstructured is safer. +export const SUPPORTS_STRUCTURED_LOGS = + parseInt(process.versions?.node?.split('.')?.[0] || '8', 10) >= 10; + +// Map LogSeverity types to their equivalent `console.*` method. +export const CONSOLE_SEVERITY: { + [severity: string]: 'debug' | 'info' | 'warn' | 'error'; +} = { + DEBUG: 'debug', + INFO: 'info', + NOTICE: 'info', + WARNING: 'warn', + ERROR: 'error', + CRITICAL: 'error', + ALERT: 'error', + EMERGENCY: 'error', +}; + +// safely preserve unpatched console.* methods in case of compat require +export const UNPATCHED_CONSOLE = { + debug: console.debug, + info: console.info, + log: console.log, + warn: console.warn, + error: console.error, +}; diff --git a/src/logger/compat.ts b/src/logger/compat.ts index 6f6eda03f..48647f5e3 100644 --- a/src/logger/compat.ts +++ b/src/logger/compat.ts @@ -1,8 +1,26 @@ -import { debug, info, warn, error } from '../logger'; +import { + SUPPORTS_STRUCTURED_LOGS, + UNPATCHED_CONSOLE, + CONSOLE_SEVERITY, +} from './common'; +import { format } from 'util'; + +function patchedConsole(severity: string): (data: any, ...args: any[]) => void { + return function(data: any, ...args: any[]): void { + if (SUPPORTS_STRUCTURED_LOGS) { + UNPATCHED_CONSOLE[CONSOLE_SEVERITY[severity]]( + JSON.stringify({ severity, message: format(data, ...args) }) + ); + return; + } + + UNPATCHED_CONSOLE[CONSOLE_SEVERITY[severity]](data, ...args); + }; +} // IMPORTANT -- "../logger" must be imported before monkeypatching! -console.debug = debug; -console.info = info; -console.log = info; -console.warn = warn; -console.error = error; +console.debug = patchedConsole('DEBUG'); +console.info = patchedConsole('INFO'); +console.log = patchedConsole('INFO'); +console.warn = patchedConsole('WARNING'); +console.error = patchedConsole('ERROR');