UNPKG

@bitblit/epsilon

Version:

Tiny adapter to simplify building API gateway Lambda APIS

214 lines 13 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.EpsilonGlobalHandler = void 0; const logger_1 = require("@bitblit/ratchet/common/logger"); const event_util_1 = require("./http/event-util"); const timeout_token_1 = require("@bitblit/ratchet/common/timeout-token"); const promise_ratchet_1 = require("@bitblit/ratchet/common/promise-ratchet"); const response_util_1 = require("./http/response-util"); const request_timeout_error_1 = require("./http/error/request-timeout-error"); const common_1 = require("@bitblit/ratchet/common"); const context_util_1 = require("./util/context-util"); const web_v2_handler_1 = require("./http/web-v2-handler"); const inter_api_epsilon_lambda_event_handler_1 = require("./lambda-event-handler/inter-api-epsilon-lambda-event-handler"); const generic_sns_epsilon_lambda_event_handler_1 = require("./lambda-event-handler/generic-sns-epsilon-lambda-event-handler"); const generic_sqs_epsilon_lambda_event_handler_1 = require("./lambda-event-handler/generic-sqs-epsilon-lambda-event-handler"); const cron_epsilon_lambda_event_handler_1 = require("./lambda-event-handler/cron-epsilon-lambda-event-handler"); const s3_epsilon_lambda_event_handler_1 = require("./lambda-event-handler/s3-epsilon-lambda-event-handler"); const dynamo_epsilon_lambda_event_handler_1 = require("./lambda-event-handler/dynamo-epsilon-lambda-event-handler"); const epsilon_logging_extension_processor_1 = require("./epsilon-logging-extension-processor"); const no_handlers_found_error_1 = require("./config/no-handlers-found-error"); /** * This class functions as the adapter from a default Lambda function to the handlers exposed via Epsilon */ class EpsilonGlobalHandler { static set globalInstanceProvider(input) { EpsilonGlobalHandler.GLOBAL_INSTANCE_PROVIDER = input; } static get globalInstanceProvider() { return EpsilonGlobalHandler.GLOBAL_INSTANCE_PROVIDER; } constructor(_epsilon) { this._epsilon = _epsilon; this.handlers = null; // We only want to do this if it wasn't explicitly configured earlier if (!EpsilonGlobalHandler.LOGGER_CONFIGURED) { EpsilonGlobalHandler.configureDefaultLogger(); logger_1.Logger.info('EpsilonLoggingConfiguration:Default logger configured'); } else { logger_1.Logger.info('EpsilonLoggingConfiguration:Skipping default logger config - already configured'); } this.handlers = [ this._epsilon.webHandler, new web_v2_handler_1.WebV2Handler(this._epsilon.webHandler), this._epsilon.backgroundHandler, new inter_api_epsilon_lambda_event_handler_1.InterApiEpsilonLambdaEventHandler(this._epsilon), new generic_sns_epsilon_lambda_event_handler_1.GenericSnsEpsilonLambdaEventHandler(this._epsilon), new generic_sqs_epsilon_lambda_event_handler_1.GenericSqsEpsilonLambdaEventHandler(this._epsilon), new cron_epsilon_lambda_event_handler_1.CronEpsilonLambdaEventHandler(this._epsilon), new s3_epsilon_lambda_event_handler_1.S3EpsilonLambdaEventHandler(this._epsilon), new dynamo_epsilon_lambda_event_handler_1.DynamoEpsilonLambdaEventHandler(this._epsilon), ]; } static configureDefaultLogger(overrides) { var _a, _b, _c, _d, _e; const output = overrides ? Object.assign({}, overrides) : {}; output.initialLevel = (_a = output.initialLevel) !== null && _a !== void 0 ? _a : common_1.LoggerLevelName.info; output.formatType = (_b = output.formatType) !== null && _b !== void 0 ? _b : common_1.LogMessageFormatType.StructuredJson; //output.trace; output.globalVars = (_c = output.globalVars) !== null && _c !== void 0 ? _c : {}; // No extra defaults for now output.outputFunction = (_d = output.outputFunction) !== null && _d !== void 0 ? _d : common_1.LoggerOutputFunction.StdOut; output.ringBufferSize = (_e = output.ringBufferSize) !== null && _e !== void 0 ? _e : 0; const src = output.preProcessors || []; output.preProcessors = src.concat([new epsilon_logging_extension_processor_1.EpsilonLoggingExtensionProcessor()]); //output.preProcessors.push(); logger_1.Logger.info('EpsilonLoggingConfiguration: configureDefaultLogger: pre'); logger_1.Logger.dumpOptionsIntoLog(); logger_1.Logger.changeDefaultOptions(output, true); logger_1.Logger.info('EpsilonLoggingConfiguration: configureDefaultLogger: post'); logger_1.Logger.dumpOptionsIntoLog(); EpsilonGlobalHandler.LOGGER_CONFIGURED = true; logger_1.Logger.info('EpsilonLoggingConfiguration: Updated'); } get defaultLoggerInstance() { return logger_1.Logger.getLogger(); } get epsilon() { return this._epsilon; } processSingleBackgroundByParts(type, data, overrideTraceId, overrideTraceDepth) { return __awaiter(this, void 0, void 0, function* () { return this.processSingleBackgroundEntry(this._epsilon.backgroundManager.createEntry(type, data), overrideTraceId, overrideTraceDepth); }); } processSingleBackgroundEntry(e, overrideTraceId, overrideTraceDepth) { return __awaiter(this, void 0, void 0, function* () { let rval = false; if (e === null || e === void 0 ? void 0 : e.type) { const internal = yield this._epsilon.backgroundManager.wrapEntryForInternal(e, overrideTraceId, overrideTraceDepth); rval = yield this._epsilon.backgroundHandler.processSingleBackgroundEntry(internal); logger_1.Logger.info('Direct processed request %j to %s', e, rval); } else { logger_1.Logger.error('Cannot process null/unnamed background entry'); } return rval; }); } lambdaHandler(event, context) { return __awaiter(this, void 0, void 0, function* () { let rval = null; try { if (this.epsilon.config.disableLastResortTimeout || !context || !context.getRemainingTimeInMillis()) { rval = yield this.innerLambdaHandler(event, context); } else { // Outer wrap timeout makes sure that we timeout even if the slow part is a filter instead of the controller const tmp = yield promise_ratchet_1.PromiseRatchet.timeout(this.innerLambdaHandler(event, context), 'EpsilonLastResortTimeout', context.getRemainingTimeInMillis() - 1000); // Reserve 1 second for cleanup if (timeout_token_1.TimeoutToken.isTimeoutToken(tmp)) { tmp.writeToLog(); // Using the HTTP version since it can use it, and the background ones dont care about the response format rval = response_util_1.ResponseUtil.errorResponse(common_1.RestfulApiHttpError.wrapError(new request_timeout_error_1.RequestTimeoutError('Timed out'))); } else { rval = tmp; } } } finally { context_util_1.ContextUtil.clearContext(); } return rval; }); } innerLambdaHandler(event, context) { var _a, _b, _c, _d, _e, _f; return __awaiter(this, void 0, void 0, function* () { context_util_1.ContextUtil.initContext(this._epsilon, event, context, 'TBD'); let rval = null; let errorHandler = EpsilonGlobalHandler.defaultProcessUncaughtError; let noMatchingHandler = false; try { if (!this._epsilon) { logger_1.Logger.error('Config not found, abandoning'); return false; } // Setup logging const logLevel = event_util_1.EventUtil.calcLogLevelViaEventOrEnvParam(logger_1.Logger.getLevel(), event, this._epsilon.config.loggerConfig); logger_1.Logger.setLevel(logLevel); if (this._epsilon.config.loggerConfig && this._epsilon.config.loggerConfig.queryParamTracePrefixName && event.queryStringParameters && event.queryStringParameters[this._epsilon.config.loggerConfig.queryParamTracePrefixName]) { logger_1.Logger.info('Setting trace prefix to %s', event.queryStringParameters[this._epsilon.config.loggerConfig.queryParamTracePrefixName]); logger_1.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; // Override it, if the handler supports that const label = handler.extractLabel(event, context); context_util_1.ContextUtil.setProcessLabel(label); logger_1.Logger.logByLevel(((_c = (_b = (_a = this._epsilon) === null || _a === void 0 ? void 0 : _a.config) === null || _b === void 0 ? void 0 : _b.loggerConfig) === null || _c === void 0 ? void 0 : _c.epsilonStartEndMessageLogLevel) || common_1.LoggerLevelName.info, 'EvtStart: %s', label); try { rval = yield handler.processEvent(event, context); } catch (err) { if (err instanceof no_handlers_found_error_1.NoHandlersFoundError) { // We found a generic handler to handle this event, but it didn't have any handlers for // this specific message. // Reset "found" flag to false, but still break the loop. found = false; break; } else { throw err; } } logger_1.Logger.logByLevel(((_f = (_e = (_d = this._epsilon) === null || _d === void 0 ? void 0 : _d.config) === null || _e === void 0 ? void 0 : _e.loggerConfig) === null || _f === void 0 ? void 0 : _f.epsilonStartEndMessageLogLevel) || common_1.LoggerLevelName.info, 'EvtEnd: %s', label); logger_1.Logger.silly('EvtEnd:Value: %s Value: %j', label, rval); } } if (!found) { noMatchingHandler = true; } } catch (err) { // Note: If your errorHandler throws an error its just gonna get thrown up, which is what we want // since some of them actually NEED to rethrow errors to get auto-retries (eg, Dynamo) rval = yield errorHandler(event, context, err); } if (this.epsilon.config.throwErrorIfNoSuitableEventHandlers && noMatchingHandler) { logger_1.Logger.error('No matching handler found for event: %j', event); throw new Error('No matching handler found for event'); } return rval; }); } static defaultProcessUncaughtError(event, context, err) { return __awaiter(this, void 0, void 0, function* () { logger_1.Logger.error('Error slipped out to outer edge (Default). Logging and returning log : %s', err, err); const rval = { statusCode: 500, body: JSON.stringify({ error: common_1.ErrorRatchet.safeStringifyErr(err) }), isBase64Encoded: false, }; return rval; }); } } exports.EpsilonGlobalHandler = EpsilonGlobalHandler; EpsilonGlobalHandler.LOGGER_CONFIGURED = false; //# sourceMappingURL=epsilon-global-handler.js.map