@bitblit/ratchet-epsilon-common
Version:
Tiny adapter to simplify building API gateway Lambda APIS
177 lines • 9.19 kB
JavaScript
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