Skip to content

Commit 27f8b43

Browse files
committed
[v7] Make all serverless tracing wrappers use provided client directly
1 parent 9a44ac4 commit 27f8b43

File tree

3 files changed

+100
-75
lines changed

3 files changed

+100
-75
lines changed

packages/serverless/src/awsservices.ts

Lines changed: 39 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { getTransaction } from '@sentry/minimal';
21
import { ClientLike, Integration, Span } from '@sentry/types';
32
import { fill } from '@sentry/utils';
43
// 'aws-sdk/global' import is expected to be type-only so it's erased in the final .js file.
@@ -19,6 +18,8 @@ interface AWSService {
1918
export class AWSServices implements Integration {
2019
public name = this.constructor.name;
2120

21+
private _client!: ClientLike;
22+
2223
private readonly _optional: boolean;
2324

2425
public constructor(options: { optional?: boolean } = {}) {
@@ -28,47 +29,54 @@ export class AWSServices implements Integration {
2829
/**
2930
* @inheritDoc
3031
*/
31-
public install(_client: ClientLike): void {
32+
public install(client: ClientLike): void {
33+
this._client = client;
34+
3235
try {
3336
// eslint-disable-next-line @typescript-eslint/no-var-requires
3437
const awsModule = require('aws-sdk/global') as typeof AWS;
35-
fill(awsModule.Service.prototype, 'makeRequest', wrapMakeRequest);
38+
fill(awsModule.Service.prototype, 'makeRequest', this._wrapMakeRequest.bind(this));
3639
} catch (e) {
3740
if (!this._optional) {
3841
throw e;
3942
}
4043
}
4144
}
42-
}
4345

44-
/** */
45-
function wrapMakeRequest<TService extends AWSService, TResult>(
46-
orig: MakeRequestFunction<GenericParams, TResult>,
47-
): MakeRequestFunction<GenericParams, TResult> {
48-
return function(this: TService, operation: string, params?: GenericParams, callback?: MakeRequestCallback<TResult>) {
49-
// TODO: Use clients scope instead of global call
50-
const transaction = getTransaction();
51-
let span: Span | undefined;
52-
const req = orig.call(this, operation, params);
53-
req.on('afterBuild', () => {
54-
if (transaction) {
55-
span = transaction.startChild({
56-
description: describe(this, operation, params),
57-
op: 'aws.request',
58-
});
59-
}
60-
});
61-
req.on('complete', () => {
62-
if (span) {
63-
span.finish();
64-
}
65-
});
46+
private _wrapMakeRequest<TService extends AWSService, TResult>(
47+
orig: MakeRequestFunction<GenericParams, TResult>,
48+
): MakeRequestFunction<GenericParams, TResult> {
49+
const client = this._client;
6650

67-
if (callback) {
68-
req.send(callback);
69-
}
70-
return req;
71-
};
51+
return function(
52+
this: TService,
53+
operation: string,
54+
params?: GenericParams,
55+
callback?: MakeRequestCallback<TResult>,
56+
) {
57+
const transaction = client.getScope().getTransaction();
58+
let span: Span | undefined;
59+
const req = orig.call(this, operation, params);
60+
req.on('afterBuild', () => {
61+
if (transaction) {
62+
span = transaction.startChild({
63+
description: describe(this, operation, params),
64+
op: 'aws.request',
65+
});
66+
}
67+
});
68+
req.on('complete', () => {
69+
if (span) {
70+
span.finish();
71+
}
72+
});
73+
74+
if (callback) {
75+
req.send(callback);
76+
}
77+
return req;
78+
};
79+
}
7280
}
7381

7482
/** Describes an operation on generic AWS service */

packages/serverless/src/google-cloud-grpc.ts

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { EventEmitter } from 'events';
22

33
import { ClientLike, Integration, Span } from '@sentry/types';
44
import { fill } from '@sentry/utils';
5-
import { getTransaction } from '@sentry/minimal';
65

76
interface GrpcFunction extends CallableFunction {
87
(...args: unknown[]): EventEmitter;
@@ -30,6 +29,8 @@ interface Stub {
3029
export class GoogleCloudGrpc implements Integration {
3130
public name = this.constructor.name;
3231

32+
private _client!: ClientLike;
33+
3334
private readonly _optional: boolean;
3435

3536
public constructor(options: { optional?: boolean } = {}) {
@@ -39,41 +40,54 @@ export class GoogleCloudGrpc implements Integration {
3940
/**
4041
* @inheritDoc
4142
*/
42-
public install(_client: ClientLike): void {
43+
public install(client: ClientLike): void {
44+
this._client = client;
4345
try {
4446
// eslint-disable-next-line @typescript-eslint/no-var-requires
4547
const gaxModule = require('google-gax');
4648
fill(
4749
gaxModule.GrpcClient.prototype, // eslint-disable-line @typescript-eslint/no-unsafe-member-access
4850
'createStub',
49-
wrapCreateStub,
51+
this._wrapCreateStub.bind(this),
5052
);
5153
} catch (e) {
5254
if (!this._optional) {
5355
throw e;
5456
}
5557
}
5658
}
57-
}
5859

59-
/** Returns a wrapped function that returns a stub with tracing enabled */
60-
function wrapCreateStub(origCreate: CreateStubFunc): CreateStubFunc {
61-
return async function(this: unknown, ...args: Parameters<CreateStubFunc>) {
62-
const servicePath = args[1]?.servicePath;
63-
if (servicePath == null || servicePath == undefined) {
64-
return origCreate.apply(this, args);
65-
}
66-
const serviceIdentifier = identifyService(servicePath);
67-
const stub = await origCreate.apply(this, args);
68-
for (const methodName of Object.keys(Object.getPrototypeOf(stub))) {
69-
fillGrpcFunction(stub, serviceIdentifier, methodName);
70-
}
71-
return stub;
72-
};
60+
/** Returns a wrapped function that returns a stub with tracing enabled */
61+
private _wrapCreateStub(origCreate: CreateStubFunc): CreateStubFunc {
62+
const client = this._client;
63+
64+
return async function(this: unknown, ...args: Parameters<CreateStubFunc>) {
65+
const servicePath = args[1]?.servicePath;
66+
if (servicePath == null || servicePath == undefined) {
67+
return origCreate.apply(this, args);
68+
}
69+
const serviceIdentifier = identifyService(servicePath);
70+
const stub = await origCreate.apply(this, args);
71+
for (const methodName of Object.keys(Object.getPrototypeOf(stub))) {
72+
fillGrpcFunction({ client, stub, serviceIdentifier, methodName });
73+
}
74+
return stub;
75+
};
76+
}
7377
}
7478

7579
/** Patches the function in grpc stub to enable tracing */
76-
function fillGrpcFunction(stub: Stub, serviceIdentifier: string, methodName: string): void {
80+
function fillGrpcFunction({
81+
client,
82+
stub,
83+
serviceIdentifier,
84+
methodName,
85+
}: {
86+
client: ClientLike;
87+
stub: Stub;
88+
serviceIdentifier: string;
89+
methodName: string;
90+
}): void {
7791
const funcObj = stub[methodName];
7892
if (typeof funcObj !== 'function') {
7993
return;
@@ -97,8 +111,7 @@ function fillGrpcFunction(stub: Stub, serviceIdentifier: string, methodName: str
97111
if (typeof ret?.on !== 'function') {
98112
return ret;
99113
}
100-
// TODO: Use clients scope instead of global call
101-
const transaction = getTransaction();
114+
const transaction = client.getScope().getTransaction();
102115
let span: Span | undefined;
103116
if (transaction) {
104117
span = transaction.startChild({

packages/serverless/src/google-cloud-http.ts

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// '@google-cloud/common' import is expected to be type-only so it's erased in the final .js file.
22
// When TypeScript compiler is upgraded, use `import type` syntax to explicitly assert that we don't want to load a module here.
33
import * as common from '@google-cloud/common';
4-
import { getTransaction } from '@sentry/minimal';
54
import { ClientLike, Integration, Span } from '@sentry/types';
65
import { fill } from '@sentry/utils';
76

@@ -16,6 +15,8 @@ interface RequestFunction extends CallableFunction {
1615
export class GoogleCloudHttp implements Integration {
1716
public name = this.constructor.name;
1817

18+
private _client!: ClientLike;
19+
1920
private readonly _optional: boolean;
2021

2122
public constructor(options: { optional?: boolean } = {}) {
@@ -25,39 +26,42 @@ export class GoogleCloudHttp implements Integration {
2526
/**
2627
* @inheritDoc
2728
*/
28-
public install(_client: ClientLike): void {
29+
public install(client: ClientLike): void {
30+
this._client = client;
31+
2932
try {
3033
// eslint-disable-next-line @typescript-eslint/no-var-requires
3134
const commonModule = require('@google-cloud/common') as typeof common;
32-
fill(commonModule.Service.prototype, 'request', wrapRequestFunction);
35+
fill(commonModule.Service.prototype, 'request', this._wrapRequestFunction.bind(this));
3336
} catch (e) {
3437
if (!this._optional) {
3538
throw e;
3639
}
3740
}
3841
}
39-
}
4042

41-
/** Returns a wrapped function that makes a request with tracing enabled */
42-
function wrapRequestFunction(orig: RequestFunction): RequestFunction {
43-
return function(this: common.Service, reqOpts: RequestOptions, callback: ResponseCallback): void {
44-
// TODO: Use clients scope instead of global call
45-
const transaction = getTransaction();
46-
let span: Span | undefined;
47-
if (transaction) {
48-
const httpMethod = reqOpts.method || 'GET';
49-
span = transaction.startChild({
50-
description: `${httpMethod} ${reqOpts.uri}`,
51-
op: `gcloud.http.${identifyService(this.apiEndpoint)}`,
52-
});
53-
}
54-
orig.call(this, reqOpts, (...args: Parameters<ResponseCallback>) => {
55-
if (span) {
56-
span.finish();
43+
/** Returns a wrapped function that makes a request with tracing enabled */
44+
private _wrapRequestFunction(orig: RequestFunction): RequestFunction {
45+
const client = this._client;
46+
47+
return function(this: common.Service, reqOpts: RequestOptions, callback: ResponseCallback): void {
48+
const transaction = client.getScope().getTransaction();
49+
let span: Span | undefined;
50+
if (transaction) {
51+
const httpMethod = reqOpts.method || 'GET';
52+
span = transaction.startChild({
53+
description: `${httpMethod} ${reqOpts.uri}`,
54+
op: `gcloud.http.${identifyService(this.apiEndpoint)}`,
55+
});
5756
}
58-
callback(...args);
59-
});
60-
};
57+
orig.call(this, reqOpts, (...args: Parameters<ResponseCallback>) => {
58+
if (span) {
59+
span.finish();
60+
}
61+
callback(...args);
62+
});
63+
};
64+
}
6165
}
6266

6367
/** Identifies service by its base url */

0 commit comments

Comments
 (0)