From 7bebf6f370c7fbfab3f1431741a48a8cdaaf552c Mon Sep 17 00:00:00 2001 From: Dominik Kundel Date: Tue, 26 Mar 2024 00:52:08 -0700 Subject: [PATCH] fix(@twilio/runtime-handler): add cross-fork logger instance for local dev (#459) Co-authored-by: Victor A <33580233+victoray@users.noreply.github.com> --- .changeset/forty-snails-rescue.md | 5 +++ .../dev-runtime/internal/crossForkLogger.ts | 35 +++++++++++++++++++ .../dev-runtime/internal/functionRunner.ts | 8 +++++ .../runtime-handler/src/dev-runtime/route.ts | 23 +++++++++++- 4 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 .changeset/forty-snails-rescue.md create mode 100644 packages/runtime-handler/src/dev-runtime/internal/crossForkLogger.ts diff --git a/.changeset/forty-snails-rescue.md b/.changeset/forty-snails-rescue.md new file mode 100644 index 00000000..def1040e --- /dev/null +++ b/.changeset/forty-snails-rescue.md @@ -0,0 +1,5 @@ +--- +'@twilio/runtime-handler': patch +--- + +Fix error messages in local development diff --git a/packages/runtime-handler/src/dev-runtime/internal/crossForkLogger.ts b/packages/runtime-handler/src/dev-runtime/internal/crossForkLogger.ts new file mode 100644 index 00000000..f6f18325 --- /dev/null +++ b/packages/runtime-handler/src/dev-runtime/internal/crossForkLogger.ts @@ -0,0 +1,35 @@ +import { LoggerInstance } from '../types'; + +export class CrossForkLogger implements LoggerInstance { + constructor() {} + + debug(msg: string) { + this.sendLog('debug', msg); + } + + info(msg: string) { + this.sendLog('info', msg); + } + + warn(msg: string, title: string = '') { + this.sendLog('warn', msg, title); + } + + error(msg: string, title: string = '') { + this.sendLog('error', msg, title); + } + + log(msg: string, level: number) { + this.sendLog('log', msg, level); + } + + private sendLog(level: keyof LoggerInstance, ...args: (string | number)[]) { + process.send && + process.send({ + crossForkLogMessage: { + level, + args: args, + }, + }); + } +} diff --git a/packages/runtime-handler/src/dev-runtime/internal/functionRunner.ts b/packages/runtime-handler/src/dev-runtime/internal/functionRunner.ts index 10a7d944..d54a0f86 100644 --- a/packages/runtime-handler/src/dev-runtime/internal/functionRunner.ts +++ b/packages/runtime-handler/src/dev-runtime/internal/functionRunner.ts @@ -7,6 +7,7 @@ import { isTwiml, } from '../route'; import { ServerConfig, Headers } from '../types'; +import { CrossForkLogger } from './crossForkLogger'; import { Response } from './response'; import { setRoutes } from './route-cache'; @@ -61,12 +62,19 @@ const handleSuccess = (responseObject?: string | number | boolean | object) => { } }; +process.on('uncaughtException', (err, origin) => { + if (process.send) { + process.send({ err: serializeError(err) }); + } +}); + process.on( 'message', ({ functionPath, event, config, path }: FunctionRunnerOptions) => { try { setRoutes(config.routes); constructGlobalScope(config); + config.logger = new CrossForkLogger(); let context = constructContext(config, path); sendDebugMessage('Context for %s: %p', path, context); context = augmentContextWithOptionals(config, context); diff --git a/packages/runtime-handler/src/dev-runtime/route.ts b/packages/runtime-handler/src/dev-runtime/route.ts index 008329b8..4dfdad31 100644 --- a/packages/runtime-handler/src/dev-runtime/route.ts +++ b/packages/runtime-handler/src/dev-runtime/route.ts @@ -26,7 +26,7 @@ import { import { Reply } from './internal/functionRunner'; import { Response } from './internal/response'; import * as Runtime from './internal/runtime'; -import { ServerConfig } from './types'; +import { LoggerInstance, ServerConfig } from './types'; import debug from './utils/debug'; import { wrapErrorInHtml } from './utils/error-html'; import { getCodeLocation } from './utils/getCodeLocation'; @@ -303,25 +303,46 @@ export function functionPathToRoute( reply, debugMessage, debugArgs = [], + crossForkLogMessage, }: { err?: Error | number | string; reply?: Reply; debugMessage?: string; debugArgs?: any[]; + crossForkLogMessage?: { + level: keyof LoggerInstance; + args: [string] | [string, number] | [string, string]; + }; }) => { if (debugMessage) { log(debugMessage, ...debugArgs); return; } + + if (crossForkLogMessage) { + if ( + config.logger && + typeof config.logger[crossForkLogMessage.level] === 'function' + ) { + config.logger[crossForkLogMessage.level]( + // @ts-ignore + ...crossForkLogMessage.args + ); + } + return; + } + if (err) { const error = deserializeError(err); handleError(error, req, res, functionPath); } + if (reply) { res.status(reply.statusCode); res.set(reply.headers); res.send(reply.body); } + forked.kill(); } );