Skip to content

Commit a5fdaee

Browse files
authored
fix(node-experimental): Update auto integration lookup & readme (#8690)
This updates the way we auto-lookup integrations. Due to how OTEL instrumentation works, we actually do not need any dynamic require. Otel instrumentation will generally always work, it only actually instruments when something is required/imported. So all integration _will_ be added, they will simply do nothing if the package is not used. This also updates the readme to clarify this & restrictions.
1 parent e1e0a3c commit a5fdaee

File tree

13 files changed

+83
-68
lines changed

13 files changed

+83
-68
lines changed

packages/node-experimental/README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,26 @@ Currently, this SDK:
5050
* Will capture errors (same as @sentry/node)
5151
* Auto-instrument for performance - see below for which performance integrations are available.
5252

53+
### Manual Instrumentation
54+
5355
**Manual instrumentation is not supported!**
5456
This is because the current Sentry-Performance-APIs like `Sentry.startTransaction()` are not compatible with the OpenTelemetry tracing model.
5557
We may add manual tracing capabilities in a later version.
5658

59+
### ESM Support
60+
61+
Due to the way OpenTelemetry handles instrumentation, this only works out of the box for CommonJS (`require`) applications.
62+
63+
64+
There is experimental support for running OpenTelemetry with ESM (`"type": "module"`):
65+
66+
```bash
67+
node --experimental-loader=@opentelemetry/instrumentation/hook.mjs ./app.js
68+
```
69+
70+
See [OpenTelemetry Instrumentation Docs](https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-instrumentation#instrumentation-for-es-modules-in-nodejs-experimental) for details on this -
71+
but note that this is a) experimental, and b) does not work with all integrations.
72+
5773
## Available (Performance) Integrations
5874

5975
* Http

packages/node-experimental/src/integrations/lazy.ts renamed to packages/node-experimental/src/integrations/NodePerformanceIntegration.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,39 @@
11
import type { Instrumentation } from '@opentelemetry/instrumentation';
22
import { registerInstrumentations } from '@opentelemetry/instrumentation';
33

4-
/** TODO */
4+
/**
5+
* The base node performance integration.
6+
*/
57
export abstract class NodePerformanceIntegration<IntegrationOptions> {
68
protected _options: IntegrationOptions;
79
protected _unload?: () => void;
10+
protected _instrumentations?: Instrumentation[] | undefined;
11+
12+
public abstract name: string;
813

914
public constructor(options: IntegrationOptions) {
1015
this._options = options;
1116
}
1217

18+
/**
19+
* Load the instrumentation(s) for this integration.
20+
* Returns `true` if the instrumentations were loaded, else false.
21+
*/
22+
public loadInstrumentations(): boolean {
23+
try {
24+
this._instrumentations = this.setupInstrumentation(this._options) || undefined;
25+
} catch (error) {
26+
return false;
27+
}
28+
29+
return true;
30+
}
31+
1332
/**
1433
* @inheritDoc
1534
*/
1635
public setupOnce(): void {
17-
const instrumentations = this.setupInstrumentation(this._options);
36+
const instrumentations = this._instrumentations || this.setupInstrumentation(this._options);
1837

1938
if (!instrumentations) {
2039
return;

packages/node-experimental/src/integrations/express.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { Instrumentation } from '@opentelemetry/instrumentation';
22
import { ExpressInstrumentation } from '@opentelemetry/instrumentation-express';
33
import type { Integration } from '@sentry/types';
44

5-
import { NodePerformanceIntegration } from './lazy';
5+
import { NodePerformanceIntegration } from './NodePerformanceIntegration';
66

77
/**
88
* Express integration

packages/node-experimental/src/integrations/fastify.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { Instrumentation } from '@opentelemetry/instrumentation';
22
import { FastifyInstrumentation } from '@opentelemetry/instrumentation-fastify';
33
import type { Integration } from '@sentry/types';
44

5-
import { NodePerformanceIntegration } from './lazy';
5+
import { NodePerformanceIntegration } from './NodePerformanceIntegration';
66

77
/**
88
* Express integration

packages/node-experimental/src/integrations/getAutoPerformanceIntegrations.ts

Lines changed: 36 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,67 @@
1-
import type { Integration, IntegrationClass } from '@sentry/types';
2-
import { dynamicRequire } from '@sentry/utils';
1+
import type { Integration } from '@sentry/types';
32

4-
import type { Express } from './express';
5-
import type { Fastify } from './fastify';
6-
import type { GraphQL } from './graphql';
7-
import type { Mongo } from './mongo';
8-
import type { Mongoose } from './mongoose';
9-
import type { Mysql } from './mysql';
10-
import type { Mysql2 } from './mysql2';
11-
import type { Nest } from './nest';
12-
import type { Postgres } from './postgres';
13-
import type { Prisma } from './prisma';
3+
import { Express } from './express';
4+
import { Fastify } from './fastify';
5+
import { GraphQL } from './graphql';
6+
import { Mongo } from './mongo';
7+
import { Mongoose } from './mongoose';
8+
import { Mysql } from './mysql';
9+
import { Mysql2 } from './mysql2';
10+
import { Nest } from './nest';
11+
import type { NodePerformanceIntegration } from './NodePerformanceIntegration';
12+
import { Postgres } from './postgres';
13+
import { Prisma } from './prisma';
1414

15-
const INTEGRATIONS = [
15+
const INTEGRATIONS: (() => NodePerformanceIntegration<unknown>)[] = [
1616
() => {
17-
const integration = dynamicRequire(module, './express') as {
18-
Express: IntegrationClass<Express>;
19-
};
20-
return new integration.Express();
17+
return new Express();
2118
},
2219
() => {
23-
const integration = dynamicRequire(module, './fastify') as {
24-
Fastify: IntegrationClass<Fastify>;
25-
};
26-
return new integration.Fastify();
20+
return new Fastify();
2721
},
2822
() => {
29-
const integration = dynamicRequire(module, './graphql') as {
30-
GraphQL: IntegrationClass<GraphQL>;
31-
};
32-
return new integration.GraphQL();
23+
return new GraphQL();
3324
},
3425
() => {
35-
const integration = dynamicRequire(module, './mongo') as {
36-
Mongo: IntegrationClass<Mongo>;
37-
};
38-
return new integration.Mongo();
26+
return new Mongo();
3927
},
4028
() => {
41-
const integration = dynamicRequire(module, './mongoose') as {
42-
Mongoose: IntegrationClass<Mongoose>;
43-
};
44-
return new integration.Mongoose();
29+
return new Mongoose();
4530
},
4631
() => {
47-
const integration = dynamicRequire(module, './mysql') as {
48-
Mysql: IntegrationClass<Mysql>;
49-
};
50-
return new integration.Mysql();
32+
return new Mysql();
5133
},
5234
() => {
53-
const integration = dynamicRequire(module, './mysql2') as {
54-
Mysql2: IntegrationClass<Mysql2>;
55-
};
56-
return new integration.Mysql2();
35+
return new Mysql2();
5736
},
5837
() => {
59-
const integration = dynamicRequire(module, './postgres') as {
60-
Postgres: IntegrationClass<Postgres>;
61-
};
62-
return new integration.Postgres();
38+
return new Postgres();
6339
},
6440
() => {
65-
const integration = dynamicRequire(module, './prisma') as {
66-
Prisma: IntegrationClass<Prisma>;
67-
};
68-
return new integration.Prisma();
41+
return new Prisma();
6942
},
7043
() => {
71-
const integration = dynamicRequire(module, './nest') as {
72-
Nest: IntegrationClass<Nest>;
73-
};
74-
return new integration.Nest();
44+
return new Nest();
7545
},
7646
];
7747

78-
/** TODO */
48+
/**
49+
* Get auto-dsicovered performance integrations.
50+
* Note that due to the way OpenTelemetry instrumentation works, this will generally still return Integrations
51+
* for stuff that may not be installed. This is because Otel only instruments when the module is imported/required,
52+
* so if the package is not required at all it will not be patched, and thus not instrumented.
53+
* But the _Sentry_ Integration will still be added.
54+
* This _may_ be a bit confusing because it shows all integrations as being installed in the debug logs, but this is
55+
* technically not wrong because we install it (it just doesn't do anything).
56+
*/
7957
export function getAutoPerformanceIntegrations(): Integration[] {
8058
const loadedIntegrations = INTEGRATIONS.map(tryLoad => {
8159
try {
82-
return tryLoad();
60+
const integration = tryLoad();
61+
const isLoaded = integration.loadInstrumentations();
62+
return isLoaded ? integration : false;
8363
} catch (_) {
84-
return undefined;
64+
return false;
8565
}
8666
}).filter(integration => !!integration) as Integration[];
8767

packages/node-experimental/src/integrations/graphql.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { Instrumentation } from '@opentelemetry/instrumentation';
22
import { GraphQLInstrumentation } from '@opentelemetry/instrumentation-graphql';
33
import type { Integration } from '@sentry/types';
44

5-
import { NodePerformanceIntegration } from './lazy';
5+
import { NodePerformanceIntegration } from './NodePerformanceIntegration';
66

77
/**
88
* GraphQL integration

packages/node-experimental/src/integrations/mongo.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { Instrumentation } from '@opentelemetry/instrumentation';
22
import { MongoDBInstrumentation } from '@opentelemetry/instrumentation-mongodb';
33
import type { Integration } from '@sentry/types';
44

5-
import { NodePerformanceIntegration } from './lazy';
5+
import { NodePerformanceIntegration } from './NodePerformanceIntegration';
66

77
/**
88
* MongoDB integration

packages/node-experimental/src/integrations/mongoose.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { Instrumentation } from '@opentelemetry/instrumentation';
22
import { MongooseInstrumentation } from '@opentelemetry/instrumentation-mongoose';
33
import type { Integration } from '@sentry/types';
44

5-
import { NodePerformanceIntegration } from './lazy';
5+
import { NodePerformanceIntegration } from './NodePerformanceIntegration';
66

77
/**
88
* Mongoose integration

packages/node-experimental/src/integrations/mysql.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { Instrumentation } from '@opentelemetry/instrumentation';
22
import { MySQLInstrumentation } from '@opentelemetry/instrumentation-mysql';
33
import type { Integration } from '@sentry/types';
44

5-
import { NodePerformanceIntegration } from './lazy';
5+
import { NodePerformanceIntegration } from './NodePerformanceIntegration';
66

77
/**
88
* MySQL integration

packages/node-experimental/src/integrations/mysql2.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { Instrumentation } from '@opentelemetry/instrumentation';
22
import { MySQL2Instrumentation } from '@opentelemetry/instrumentation-mysql2';
33
import type { Integration } from '@sentry/types';
44

5-
import { NodePerformanceIntegration } from './lazy';
5+
import { NodePerformanceIntegration } from './NodePerformanceIntegration';
66

77
/**
88
* MySQL2 integration

packages/node-experimental/src/integrations/nest.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { Instrumentation } from '@opentelemetry/instrumentation';
22
import { NestInstrumentation } from '@opentelemetry/instrumentation-nestjs-core';
33
import type { Integration } from '@sentry/types';
44

5-
import { NodePerformanceIntegration } from './lazy';
5+
import { NodePerformanceIntegration } from './NodePerformanceIntegration';
66

77
/**
88
* Nest framework integration

packages/node-experimental/src/integrations/postgres.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { Instrumentation } from '@opentelemetry/instrumentation';
22
import { PgInstrumentation } from '@opentelemetry/instrumentation-pg';
33
import type { Integration } from '@sentry/types';
44

5-
import { NodePerformanceIntegration } from './lazy';
5+
import { NodePerformanceIntegration } from './NodePerformanceIntegration';
66

77
/**
88
* Postgres integration

packages/node-experimental/src/integrations/prisma.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { Instrumentation } from '@opentelemetry/instrumentation';
22
import { PrismaInstrumentation } from '@prisma/instrumentation';
33
import type { Integration } from '@sentry/types';
44

5-
import { NodePerformanceIntegration } from './lazy';
5+
import { NodePerformanceIntegration } from './NodePerformanceIntegration';
66

77
/**
88
* Prisma integration

0 commit comments

Comments
 (0)