Skip to content

Commit

Permalink
Add optional parameter to AWSServices integration (#3030)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
marshall-lee authored Nov 12, 2020
1 parent 4b20bfb commit 0a2bfdb
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 36 deletions.
2 changes: 1 addition & 1 deletion packages/serverless/src/awslambda.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
82 changes: 47 additions & 35 deletions packages/serverless/src/awsservices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
<TService extends AWSService, TResult>(
orig: MakeRequestFunction<GenericParams, TResult>,
): MakeRequestFunction<GenericParams, TResult> =>
function(this: TService, operation: string, params?: GenericParams, callback?: MakeRequestCallback<TResult>) {
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<TService extends AWSService, TResult>(
orig: MakeRequestFunction<GenericParams, TResult>,
): MakeRequestFunction<GenericParams, TResult> {
return function(this: TService, operation: string, params?: GenericParams, callback?: MakeRequestCallback<TResult>) {
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<TService extends AWSService>(service: TService, operation: string, params?: GenericParams): string {
let ret = `aws.${service.serviceIdentifier}.${operation}`;
Expand Down

0 comments on commit 0a2bfdb

Please sign in to comment.