UNPKG

@bitblit/ratchet-epsilon-common

Version:

Tiny adapter to simplify building API gateway Lambda APIS

177 lines 9.19 kB
import { Logger } from '@bitblit/ratchet-common/logger/logger'; import { ErrorRatchet } from '@bitblit/ratchet-common/lang/error-ratchet'; import { PromiseRatchet } from '@bitblit/ratchet-common/lang/promise-ratchet'; import { LoggerLevelName } from '@bitblit/ratchet-common/logger/logger-level-name'; import { LogMessageFormatType } from '@bitblit/ratchet-common/logger/log-message-format-type'; import { LoggerOutputFunction } from '@bitblit/ratchet-common/logger/logger-output-function'; import { TimeoutToken } from '@bitblit/ratchet-common/lang/timeout-token'; import { RestfulApiHttpError } from '@bitblit/ratchet-common/network/restful-api-http-error'; import { EventUtil } from './http/event-util.js'; import { ResponseUtil } from './http/response-util.js'; import { RequestTimeoutError } from './http/error/request-timeout-error.js'; import { ContextUtil } from './util/context-util.js'; import { WebV2Handler } from './http/web-v2-handler.js'; import { InterApiEpsilonLambdaEventHandler } from './lambda-event-handler/inter-api-epsilon-lambda-event-handler.js'; import { GenericSnsEpsilonLambdaEventHandler } from './lambda-event-handler/generic-sns-epsilon-lambda-event-handler.js'; import { CronEpsilonLambdaEventHandler } from './lambda-event-handler/cron-epsilon-lambda-event-handler.js'; import { S3EpsilonLambdaEventHandler } from './lambda-event-handler/s3-epsilon-lambda-event-handler.js'; import { DynamoEpsilonLambdaEventHandler } from './lambda-event-handler/dynamo-epsilon-lambda-event-handler.js'; import { EpsilonLoggingExtensionProcessor } from './epsilon-logging-extension-processor.js'; import { GenericSqsEpsilonLambdaEventHandler } from './lambda-event-handler/generic-sqs-epsilon-lambda-event-handler.js'; import { NoHandlersFoundError } from './config/no-handlers-found-error.js'; export class EpsilonGlobalHandler { _epsilon; static LOGGER_CONFIGURED = false; static GLOBAL_INSTANCE_PROVIDER; static set globalInstanceProvider(input) { EpsilonGlobalHandler.GLOBAL_INSTANCE_PROVIDER = input; } static get globalInstanceProvider() { return EpsilonGlobalHandler.GLOBAL_INSTANCE_PROVIDER; } handlers = null; constructor(_epsilon) { this._epsilon = _epsilon; if (!EpsilonGlobalHandler.LOGGER_CONFIGURED) { EpsilonGlobalHandler.configureDefaultLogger(); Logger.info('EpsilonLoggingConfiguration:Default logger configured'); } else { Logger.info('EpsilonLoggingConfiguration:Skipping default logger config - already configured'); } this.handlers = [ this._epsilon.webHandler, new WebV2Handler(this._epsilon.webHandler), this._epsilon.backgroundHandler, new InterApiEpsilonLambdaEventHandler(this._epsilon), new GenericSnsEpsilonLambdaEventHandler(this._epsilon), new GenericSqsEpsilonLambdaEventHandler(this._epsilon), new CronEpsilonLambdaEventHandler(this._epsilon), new S3EpsilonLambdaEventHandler(this._epsilon), new DynamoEpsilonLambdaEventHandler(this._epsilon), ]; } static configureDefaultLogger(overrides) { const output = overrides ? Object.assign({}, overrides) : {}; output.initialLevel = output.initialLevel ?? LoggerLevelName.info; output.formatType = output.formatType ?? LogMessageFormatType.StructuredJson; output.globalVars = output.globalVars ?? {}; output.outputFunction = output.outputFunction ?? LoggerOutputFunction.StdOut; output.ringBufferSize = output.ringBufferSize ?? 0; const src = output.preProcessors || []; output.preProcessors = src.concat([new EpsilonLoggingExtensionProcessor()]); const _pre = Logger.getOptions(); Logger.changeDefaultOptions(output, true); const _post = Logger.getOptions(); EpsilonGlobalHandler.LOGGER_CONFIGURED = true; Logger.info('EpsilonLoggingConfiguration: Updated'); Logger.dumpOptionsIntoLog(); } get epsilon() { return this._epsilon; } async processSingleBackgroundByParts(type, data, overrideTraceId, overrideTraceDepth) { return this.processSingleBackgroundEntry(this._epsilon.backgroundManager.createEntry(type, data), overrideTraceId, overrideTraceDepth); } async processSingleBackgroundEntry(e, overrideTraceId, overrideTraceDepth) { let rval = false; if (e?.type) { const internal = await this._epsilon.backgroundManager.wrapEntryForInternal(e, overrideTraceId, overrideTraceDepth); rval = await this._epsilon.backgroundHandler.processSingleBackgroundEntry(internal); Logger.info('Direct processed request %j to %s', e, rval); } else { Logger.error('Cannot process null/unnamed background entry'); } return rval; } async lambdaHandler(event, context) { let rval = null; try { if (this.epsilon.config.disableLastResortTimeout || !context || !context.getRemainingTimeInMillis()) { rval = await this.innerLambdaHandler(event, context); } else { const tmp = await PromiseRatchet.timeout(this.innerLambdaHandler(event, context), 'EpsilonLastResortTimeout', context.getRemainingTimeInMillis() - 1000); if (TimeoutToken.isTimeoutToken(tmp)) { tmp.writeToLog(); rval = ResponseUtil.errorResponse(RestfulApiHttpError.wrapError(new RequestTimeoutError('Timed out'))); } else { rval = tmp; } } } finally { ContextUtil.clearContext(); } return rval; } async innerLambdaHandler(event, context) { ContextUtil.initContext(this._epsilon, event, context, 'TBD'); let rval = null; let errorHandler = EpsilonGlobalHandler.defaultProcessUncaughtError; let noMatchingHandler = false; try { if (!this._epsilon) { Logger.error('Config not found, abandoning'); return false; } const logLevel = EventUtil.calcLogLevelViaEventOrEnvParam(Logger.getLevel(), event, this._epsilon.config.loggerConfig); Logger.setLevel(logLevel); if (this._epsilon.config.loggerConfig && this._epsilon.config.loggerConfig.queryParamTracePrefixName && event.queryStringParameters && event.queryStringParameters[this._epsilon.config.loggerConfig.queryParamTracePrefixName]) { Logger.info('Setting trace prefix to %s', event.queryStringParameters[this._epsilon.config.loggerConfig.queryParamTracePrefixName]); Logger.updateTracePrefix(event.queryStringParameters[this._epsilon.config.loggerConfig.queryParamTracePrefixName]); } let found = false; for (let i = 0; i < this.handlers.length && !found; i++) { const handler = this.handlers[i]; if (handler.handlesEvent(event)) { found = true; errorHandler = handler.processUncaughtError || errorHandler; const label = handler.extractLabel(event, context); ContextUtil.setProcessLabel(label); Logger.logByLevel(this._epsilon?.config?.loggerConfig?.epsilonStartEndMessageLogLevel || LoggerLevelName.info, 'EvtStart: %s', label); try { rval = await handler.processEvent(event, context); } catch (err) { if (err instanceof NoHandlersFoundError) { found = false; break; } else { throw err; } } Logger.logByLevel(this._epsilon?.config?.loggerConfig?.epsilonStartEndMessageLogLevel || LoggerLevelName.info, 'EvtEnd: %s', label); Logger.silly('EvtEnd:Value: %s Value: %j', label, rval); } } if (!found) { noMatchingHandler = true; } } catch (err) { rval = await errorHandler(event, context, err); } if (this.epsilon.config.throwErrorIfNoSuitableEventHandlers && noMatchingHandler) { Logger.error('No matching handler found for event: %j', event); throw new Error('No matching handler found for event'); } return rval; } static async defaultProcessUncaughtError(event, context, err) { Logger.error('Error slipped out to outer edge (Default). Logging and returning log : %s', err, err); const rval = { statusCode: 500, body: JSON.stringify({ error: ErrorRatchet.safeStringifyErr(err) }), isBase64Encoded: false, }; return rval; } } //# sourceMappingURL=epsilon-global-handler.js.map