From 0a2bfdbbffbbe8d451ace0b22f1001989803db50 Mon Sep 17 00:00:00 2001 From: Vladimir Kochnev Date: Thu, 12 Nov 2020 11:28:41 +0000 Subject: [PATCH] Add `optional` parameter to AWSServices integration (#3030) Initially, I thought there's no need to catch the error of `require('aws-sdk/global')` because this package is always available on AWS Lambda and even in the `sam local` emulator. However, in some environments it could be missing. Examples of such environments is netlify dev or it could be simply a unit-test environment without any packages. Fixes #3000. --- packages/serverless/src/awslambda.ts | 2 +- packages/serverless/src/awsservices.ts | 82 +++++++++++++++----------- 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/packages/serverless/src/awslambda.ts b/packages/serverless/src/awslambda.ts index 633bc1774a69..61b47209da9c 100644 --- a/packages/serverless/src/awslambda.ts +++ b/packages/serverless/src/awslambda.ts @@ -44,7 +44,7 @@ export interface WrapperOptions { timeoutWarningLimit: number; } -export const defaultIntegrations: Integration[] = [...Sentry.defaultIntegrations, new AWSServices()]; +export const defaultIntegrations: Integration[] = [...Sentry.defaultIntegrations, new AWSServices({ optional: true })]; /** * @see {@link Sentry.init} diff --git a/packages/serverless/src/awsservices.ts b/packages/serverless/src/awsservices.ts index 3c0500755178..2869c8a29b65 100644 --- a/packages/serverless/src/awsservices.ts +++ b/packages/serverless/src/awsservices.ts @@ -27,48 +27,60 @@ export class AWSServices implements Integration { */ public name: string = AWSServices.id; + private readonly _optional: boolean; + + public constructor(options: { optional?: boolean } = {}) { + this._optional = options.optional || false; + } + /** * @inheritDoc */ public setupOnce(): void { - const awsModule = require('aws-sdk/global') as typeof AWS; - fill( - awsModule.Service.prototype, - 'makeRequest', - ( - orig: MakeRequestFunction, - ): MakeRequestFunction => - function(this: TService, operation: string, params?: GenericParams, callback?: MakeRequestCallback) { - let transaction: Transaction | undefined; - let span: Span | undefined; - const scope = getCurrentHub().getScope(); - if (scope) { - transaction = scope.getTransaction(); - } - const req = orig.call(this, operation, params); - req.on('afterBuild', () => { - if (transaction) { - span = transaction.startChild({ - description: describe(this, operation, params), - op: 'aws.request', - }); - } - }); - req.on('complete', () => { - if (span) { - span.finish(); - } - }); - - if (callback) { - req.send(callback); - } - return req; - }, - ); + try { + const awsModule = require('aws-sdk/global') as typeof AWS; + fill(awsModule.Service.prototype, 'makeRequest', wrapMakeRequest); + } catch (e) { + if (!this._optional) { + throw e; + } + } } } +/** */ +function wrapMakeRequest( + orig: MakeRequestFunction, +): MakeRequestFunction { + return function(this: TService, operation: string, params?: GenericParams, callback?: MakeRequestCallback) { + let transaction: Transaction | undefined; + let span: Span | undefined; + const scope = getCurrentHub().getScope(); + if (scope) { + transaction = scope.getTransaction(); + } + const req = orig.call(this, operation, params); + req.on('afterBuild', () => { + if (transaction) { + span = transaction.startChild({ + description: describe(this, operation, params), + op: 'aws.request', + }); + } + }); + req.on('complete', () => { + if (span) { + span.finish(); + } + }); + + if (callback) { + req.send(callback); + } + return req; + }; +} + /** Describes an operation on generic AWS service */ function describe(service: TService, operation: string, params?: GenericParams): string { let ret = `aws.${service.serviceIdentifier}.${operation}`;