Skip to content

Commit 3004c38

Browse files
authored
ref(node-experimental): Refactor usage of startChild() (#11047)
This refactors the old node integrations to the new syntax, so we can get rid of the public APIs. This also allows us to get rid of some of the last `getCurrentHub` usage etc.
1 parent d09d184 commit 3004c38

File tree

6 files changed

+102
-145
lines changed

6 files changed

+102
-145
lines changed

packages/tracing-internal/src/node/integrations/apollo.ts

Lines changed: 21 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import type { Hub, SentrySpan } from '@sentry/core';
2-
import type { EventProcessor } from '@sentry/types';
3-
import { arrayify, fill, isThenable, loadModule, logger } from '@sentry/utils';
1+
import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startSpan } from '@sentry/core';
2+
import { arrayify, fill, loadModule, logger } from '@sentry/utils';
43

54
import { DEBUG_BUILD } from '../../common/debug-build';
65
import type { LazyLoadedIntegration } from './lazy';
@@ -75,7 +74,7 @@ export class Apollo implements LazyLoadedIntegration<GraphQLModule & ApolloModul
7574
/**
7675
* @inheritDoc
7776
*/
78-
public setupOnce(_: (callback: EventProcessor) => void, getCurrentHub: () => Hub): void {
77+
public setupOnce(): void {
7978
if (this._useNest) {
8079
const pkg = this.loadDependency();
8180

@@ -99,7 +98,7 @@ export class Apollo implements LazyLoadedIntegration<GraphQLModule & ApolloModul
9998
return function (this: unknown) {
10099
const resolvers = arrayify(orig.call(this));
101100

102-
const instrumentedResolvers = instrumentResolvers(resolvers, getCurrentHub);
101+
const instrumentedResolvers = instrumentResolvers(resolvers);
103102

104103
return instrumentedResolvers;
105104
};
@@ -146,7 +145,7 @@ export class Apollo implements LazyLoadedIntegration<GraphQLModule & ApolloModul
146145

147146
const resolvers = arrayify(this.config.resolvers);
148147

149-
this.config.resolvers = instrumentResolvers(resolvers, getCurrentHub);
148+
this.config.resolvers = instrumentResolvers(resolvers);
150149

151150
return orig.call(this);
152151
};
@@ -155,15 +154,15 @@ export class Apollo implements LazyLoadedIntegration<GraphQLModule & ApolloModul
155154
}
156155
}
157156

158-
function instrumentResolvers(resolvers: ApolloModelResolvers[], getCurrentHub: () => Hub): ApolloModelResolvers[] {
157+
function instrumentResolvers(resolvers: ApolloModelResolvers[]): ApolloModelResolvers[] {
159158
return resolvers.map(model => {
160159
Object.keys(model).forEach(resolverGroupName => {
161160
Object.keys(model[resolverGroupName]).forEach(resolverName => {
162161
if (typeof model[resolverGroupName][resolverName] !== 'function') {
163162
return;
164163
}
165164

166-
wrapResolver(model, resolverGroupName, resolverName, getCurrentHub);
165+
wrapResolver(model, resolverGroupName, resolverName);
167166
});
168167
});
169168

@@ -174,37 +173,22 @@ function instrumentResolvers(resolvers: ApolloModelResolvers[], getCurrentHub: (
174173
/**
175174
* Wrap a single resolver which can be a parent of other resolvers and/or db operations.
176175
*/
177-
function wrapResolver(
178-
model: ApolloModelResolvers,
179-
resolverGroupName: string,
180-
resolverName: string,
181-
getCurrentHub: () => Hub,
182-
): void {
176+
function wrapResolver(model: ApolloModelResolvers, resolverGroupName: string, resolverName: string): void {
183177
fill(model[resolverGroupName], resolverName, function (orig: () => unknown | Promise<unknown>) {
184178
return function (this: unknown, ...args: unknown[]) {
185-
// eslint-disable-next-line deprecation/deprecation
186-
const scope = getCurrentHub().getScope();
187-
// eslint-disable-next-line deprecation/deprecation
188-
const parentSpan = scope.getSpan() as SentrySpan | undefined;
189-
// eslint-disable-next-line deprecation/deprecation
190-
const span = parentSpan?.startChild({
191-
name: `${resolverGroupName}.${resolverName}`,
192-
op: 'graphql.resolve',
193-
origin: 'auto.graphql.apollo',
194-
});
195-
196-
const rv = orig.call(this, ...args);
197-
198-
if (isThenable(rv)) {
199-
return rv.then((res: unknown) => {
200-
span?.end();
201-
return res;
202-
});
203-
}
204-
205-
span?.end();
206-
207-
return rv;
179+
return startSpan(
180+
{
181+
onlyIfParent: true,
182+
name: `${resolverGroupName}.${resolverName}`,
183+
op: 'graphql.resolve',
184+
attributes: {
185+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.graphql.apollo',
186+
},
187+
},
188+
() => {
189+
return orig.call(this, ...args);
190+
},
191+
);
208192
};
209193
});
210194
}

packages/tracing-internal/src/node/integrations/express.ts

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* eslint-disable max-lines */
22
import type { Transaction } from '@sentry/core';
3+
import { startInactiveSpan, withActiveSpan } from '@sentry/core';
34
import { SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, spanToJSON } from '@sentry/core';
45
import type { Integration, PolymorphicRequest } from '@sentry/types';
56
import {
@@ -153,11 +154,12 @@ function wrap(fn: Function, method: Method): (...args: any[]) => void {
153154
return function (this: NodeJS.Global, req: unknown, res: ExpressResponse & SentryTracingResponse): void {
154155
const transaction = res.__sentry_transaction;
155156
if (transaction) {
156-
// eslint-disable-next-line deprecation/deprecation
157-
const span = transaction.startChild({
158-
name: fn.name,
159-
op: `middleware.express.${method}`,
160-
origin: 'auto.middleware.express',
157+
const span = withActiveSpan(transaction, () => {
158+
return startInactiveSpan({
159+
name: fn.name,
160+
op: `middleware.express.${method}`,
161+
origin: 'auto.middleware.express',
162+
});
161163
});
162164
res.once('finish', () => {
163165
span.end();
@@ -174,12 +176,15 @@ function wrap(fn: Function, method: Method): (...args: any[]) => void {
174176
next: () => void,
175177
): void {
176178
const transaction = res.__sentry_transaction;
177-
// eslint-disable-next-line deprecation/deprecation
178-
const span = transaction?.startChild({
179-
name: fn.name,
180-
op: `middleware.express.${method}`,
181-
origin: 'auto.middleware.express',
182-
});
179+
const span = transaction
180+
? withActiveSpan(transaction, () => {
181+
return startInactiveSpan({
182+
name: fn.name,
183+
op: `middleware.express.${method}`,
184+
origin: 'auto.middleware.express',
185+
});
186+
})
187+
: undefined;
183188
fn.call(this, req, res, function (this: NodeJS.Global, ...args: unknown[]): void {
184189
span?.end();
185190
next.call(this, ...args);
@@ -195,12 +200,15 @@ function wrap(fn: Function, method: Method): (...args: any[]) => void {
195200
next: () => void,
196201
): void {
197202
const transaction = res.__sentry_transaction;
198-
// eslint-disable-next-line deprecation/deprecation
199-
const span = transaction?.startChild({
200-
name: fn.name,
201-
op: `middleware.express.${method}`,
202-
origin: 'auto.middleware.express',
203-
});
203+
const span = transaction
204+
? withActiveSpan(transaction, () => {
205+
return startInactiveSpan({
206+
name: fn.name,
207+
op: `middleware.express.${method}`,
208+
origin: 'auto.middleware.express',
209+
});
210+
})
211+
: undefined;
204212
fn.call(this, err, req, res, function (this: NodeJS.Global, ...args: unknown[]): void {
205213
span?.end();
206214
next.call(this, ...args);

packages/tracing-internal/src/node/integrations/graphql.ts

Lines changed: 16 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import type { Hub, SentrySpan } from '@sentry/core';
2-
import type { EventProcessor } from '@sentry/types';
3-
import { fill, isThenable, loadModule, logger } from '@sentry/utils';
1+
import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startSpan } from '@sentry/core';
2+
import { fill, loadModule, logger } from '@sentry/utils';
43

54
import { DEBUG_BUILD } from '../../common/debug-build';
65
import type { LazyLoadedIntegration } from './lazy';
@@ -35,7 +34,7 @@ export class GraphQL implements LazyLoadedIntegration<GraphQLModule> {
3534
/**
3635
* @inheritDoc
3736
*/
38-
public setupOnce(_: (callback: EventProcessor) => void, getCurrentHub: () => Hub): void {
37+
public setupOnce(): void {
3938
const pkg = this.loadDependency();
4039

4140
if (!pkg) {
@@ -45,37 +44,19 @@ export class GraphQL implements LazyLoadedIntegration<GraphQLModule> {
4544

4645
fill(pkg, 'execute', function (orig: () => void | Promise<unknown>) {
4746
return function (this: unknown, ...args: unknown[]) {
48-
// eslint-disable-next-line deprecation/deprecation
49-
const scope = getCurrentHub().getScope();
50-
// eslint-disable-next-line deprecation/deprecation
51-
const parentSpan = scope.getSpan() as SentrySpan | undefined;
52-
53-
// eslint-disable-next-line deprecation/deprecation
54-
const span = parentSpan?.startChild({
55-
name: 'execute',
56-
op: 'graphql.execute',
57-
origin: 'auto.graphql.graphql',
58-
});
59-
60-
// eslint-disable-next-line deprecation/deprecation
61-
scope?.setSpan(span);
62-
63-
const rv = orig.call(this, ...args);
64-
65-
if (isThenable(rv)) {
66-
return rv.then((res: unknown) => {
67-
span?.end();
68-
// eslint-disable-next-line deprecation/deprecation
69-
scope?.setSpan(parentSpan);
70-
71-
return res;
72-
});
73-
}
74-
75-
span?.end();
76-
// eslint-disable-next-line deprecation/deprecation
77-
scope?.setSpan(parentSpan);
78-
return rv;
47+
return startSpan(
48+
{
49+
onlyIfParent: true,
50+
name: 'execute',
51+
op: 'graphql.execute',
52+
attributes: {
53+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.graphql.graphql',
54+
},
55+
},
56+
() => {
57+
return orig.call(this, ...args);
58+
},
59+
);
7960
};
8061
});
8162
}

packages/tracing-internal/src/node/integrations/mongo.ts

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import type { Hub, SentrySpan } from '@sentry/core';
2-
import type { EventProcessor, SpanContext } from '@sentry/types';
1+
import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startInactiveSpan } from '@sentry/core';
2+
import { getClient } from '@sentry/core';
3+
import type { EventProcessor, SpanAttributes, StartSpanOptions } from '@sentry/types';
34
import { fill, isThenable, loadModule, logger } from '@sentry/utils';
45

56
import { DEBUG_BUILD } from '../../common/debug-build';
@@ -138,7 +139,7 @@ export class Mongo implements LazyLoadedIntegration<MongoModule> {
138139
/**
139140
* @inheritDoc
140141
*/
141-
public setupOnce(_: (callback: EventProcessor) => void, getCurrentHub: () => Hub): void {
142+
public setupOnce(_: (callback: EventProcessor) => void): void {
142143
const pkg = this.loadDependency();
143144

144145
if (!pkg) {
@@ -147,42 +148,36 @@ export class Mongo implements LazyLoadedIntegration<MongoModule> {
147148
return;
148149
}
149150

150-
this._instrumentOperations(pkg.Collection, this._operations, getCurrentHub);
151+
this._instrumentOperations(pkg.Collection, this._operations);
151152
}
152153

153154
/**
154155
* Patches original collection methods
155156
*/
156-
private _instrumentOperations(collection: MongoCollection, operations: Operation[], getCurrentHub: () => Hub): void {
157-
operations.forEach((operation: Operation) => this._patchOperation(collection, operation, getCurrentHub));
157+
private _instrumentOperations(collection: MongoCollection, operations: Operation[]): void {
158+
operations.forEach((operation: Operation) => this._patchOperation(collection, operation));
158159
}
159160

160161
/**
161162
* Patches original collection to utilize our tracing functionality
162163
*/
163-
private _patchOperation(collection: MongoCollection, operation: Operation, getCurrentHub: () => Hub): void {
164+
private _patchOperation(collection: MongoCollection, operation: Operation): void {
164165
if (!(operation in collection.prototype)) return;
165166

166167
const getSpanContext = this._getSpanContextFromOperationArguments.bind(this);
167168

168169
fill(collection.prototype, operation, function (orig: () => void | Promise<unknown>) {
169170
return function (this: unknown, ...args: unknown[]) {
170171
const lastArg = args[args.length - 1];
171-
const hub = getCurrentHub();
172-
// eslint-disable-next-line deprecation/deprecation
173-
const scope = hub.getScope();
174-
// eslint-disable-next-line deprecation/deprecation
175-
const client = hub.getClient();
176-
// eslint-disable-next-line deprecation/deprecation
177-
const parentSpan = scope.getSpan() as SentrySpan | undefined;
172+
173+
const client = getClient();
178174

179175
const sendDefaultPii = client?.getOptions().sendDefaultPii;
180176

181177
// Check if the operation was passed a callback. (mapReduce requires a different check, as
182178
// its (non-callback) arguments can also be functions.)
183179
if (typeof lastArg !== 'function' || (operation === 'mapReduce' && args.length === 2)) {
184-
// eslint-disable-next-line deprecation/deprecation
185-
const span = parentSpan?.startChild(getSpanContext(this, operation, args, sendDefaultPii));
180+
const span = startInactiveSpan(getSpanContext(this, operation, args, sendDefaultPii));
186181
const maybePromiseOrCursor = orig.call(this, ...args);
187182

188183
if (isThenable(maybePromiseOrCursor)) {
@@ -213,8 +208,7 @@ export class Mongo implements LazyLoadedIntegration<MongoModule> {
213208
}
214209
}
215210

216-
// eslint-disable-next-line deprecation/deprecation
217-
const span = parentSpan?.startChild(getSpanContext(this, operation, args.slice(0, -1)));
211+
const span = startInactiveSpan(getSpanContext(this, operation, args.slice(0, -1)));
218212

219213
return orig.call(this, ...args.slice(0, -1), function (err: Error, result: unknown) {
220214
span?.end();
@@ -232,19 +226,19 @@ export class Mongo implements LazyLoadedIntegration<MongoModule> {
232226
operation: Operation,
233227
args: unknown[],
234228
sendDefaultPii: boolean | undefined = false,
235-
): SpanContext {
236-
const data: { [key: string]: string } = {
229+
): StartSpanOptions {
230+
const attributes: SpanAttributes = {
237231
'db.system': 'mongodb',
238232
'db.name': collection.dbName,
239233
'db.operation': operation,
240234
'db.mongodb.collection': collection.collectionName,
235+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: `${collection.collectionName}.${operation}`,
241236
};
242-
const spanContext: SpanContext = {
237+
const spanContext: StartSpanOptions = {
243238
op: 'db',
244-
// TODO v8: Use `${collection.collectionName}.${operation}`
245-
origin: 'auto.db.mongo',
246239
name: operation,
247-
data,
240+
attributes,
241+
onlyIfParent: true,
248242
};
249243

250244
// If the operation takes no arguments besides `options` and `callback`, or if argument
@@ -262,11 +256,11 @@ export class Mongo implements LazyLoadedIntegration<MongoModule> {
262256
// Special case for `mapReduce`, as the only one accepting functions as arguments.
263257
if (operation === 'mapReduce') {
264258
const [map, reduce] = args as { name?: string }[];
265-
data[signature[0]] = typeof map === 'string' ? map : map.name || '<anonymous>';
266-
data[signature[1]] = typeof reduce === 'string' ? reduce : reduce.name || '<anonymous>';
259+
attributes[signature[0]] = typeof map === 'string' ? map : map.name || '<anonymous>';
260+
attributes[signature[1]] = typeof reduce === 'string' ? reduce : reduce.name || '<anonymous>';
267261
} else {
268262
for (let i = 0; i < signature.length; i++) {
269-
data[`db.mongodb.${signature[i]}`] = JSON.stringify(args[i]);
263+
attributes[`db.mongodb.${signature[i]}`] = JSON.stringify(args[i]);
270264
}
271265
}
272266
} catch (_oO) {

0 commit comments

Comments
 (0)