Skip to content

Commit

Permalink
feat(node-experimental): Update tracing integrations to functional st…
Browse files Browse the repository at this point in the history
…yle (#10443)

This refactors the node-experimental performance integrations to
functional style.
Importantly, it also slightly updates the options for httpIntegration &
nativeNodeFetchIntegration, with what they can/should be in v8:

* There is no way to disable span creation for them (this is pretty
hacky to do, and prob. not needed - not allowing this simplifies this a
lot)
* You can define filters for incoming/outgoing requests to filter them
fully - that will filter them both for breadcrumbs and spans.
* spans are not created anyhow when tracing is disabled.
  • Loading branch information
mydea authored and onurtemizkan committed Feb 4, 2024
1 parent 6170a76 commit c0bcd8e
Show file tree
Hide file tree
Showing 20 changed files with 531 additions and 141 deletions.
1 change: 1 addition & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ jobs:
node:
- *shared
- 'packages/node/**'
- 'packages/node-experimental/**'
- 'dev-packages/node-integration-tests/**'
deno:
- *shared
Expand Down
13 changes: 13 additions & 0 deletions packages/node-experimental/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
import { Integrations as CoreIntegrations } from '@sentry/core';

import * as NodeExperimentalIntegrations from './integrations';
export { expressIntegration } from './integrations/express';
export { fastifyIntegration } from './integrations/fastify';
export { graphqlIntegration } from './integrations/graphql';
export { httpIntegration } from './integrations/http';
export { mongoIntegration } from './integrations/mongo';
export { mongooseIntegration } from './integrations/mongoose';
export { mysqlIntegration } from './integrations/mysql';
export { mysql2Integration } from './integrations/mysql2';
export { nestIntegration } from './integrations/nest';
export { nativeNodeFetchIntegration } from './integrations/node-fetch';
export { postgresIntegration } from './integrations/postgres';
export { prismaIntegration } from './integrations/prisma';

/** @deprecated Import the integration function directly, e.g. `inboundFiltersIntegration()` instead of `new Integrations.InboundFilter(). */
export const Integrations = {
// eslint-disable-next-line deprecation/deprecation
...CoreIntegrations,
Expand Down
25 changes: 24 additions & 1 deletion packages/node-experimental/src/integrations/express.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,36 @@
import type { Instrumentation } from '@opentelemetry/instrumentation';
import { registerInstrumentations } from '@opentelemetry/instrumentation';
import { ExpressInstrumentation } from '@opentelemetry/instrumentation-express';
import type { Integration } from '@sentry/types';
import { defineIntegration } from '@sentry/core';
import type { Integration, IntegrationFn } from '@sentry/types';

import { addOriginToSpan } from '../utils/addOriginToSpan';
import { NodePerformanceIntegration } from './NodePerformanceIntegration';

const _expressIntegration = (() => {
return {
name: 'Express',
setupOnce() {
registerInstrumentations({
instrumentations: [
new ExpressInstrumentation({
requestHook(span) {
addOriginToSpan(span, 'auto.http.otel.express');
},
}),
],
});
},
};
}) satisfies IntegrationFn;

export const expressIntegration = defineIntegration(_expressIntegration);

/**
* Express integration
*
* Capture tracing data for express.
* @deprecated Use `expressIntegration()` instead.
*/
export class Express extends NodePerformanceIntegration<void> implements Integration {
/**
Expand All @@ -23,6 +45,7 @@ export class Express extends NodePerformanceIntegration<void> implements Integra

public constructor() {
super();
// eslint-disable-next-line deprecation/deprecation
this.name = Express.id;
}

Expand Down
26 changes: 25 additions & 1 deletion packages/node-experimental/src/integrations/fastify.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,37 @@
import type { Instrumentation } from '@opentelemetry/instrumentation';
import { registerInstrumentations } from '@opentelemetry/instrumentation';
import { FastifyInstrumentation } from '@opentelemetry/instrumentation-fastify';
import type { Integration } from '@sentry/types';
import { defineIntegration } from '@sentry/core';
import type { Integration, IntegrationFn } from '@sentry/types';

import { addOriginToSpan } from '../utils/addOriginToSpan';
import { NodePerformanceIntegration } from './NodePerformanceIntegration';

const _fastifyIntegration = (() => {
return {
name: 'Fastify',
setupOnce() {
registerInstrumentations({
instrumentations: [
new FastifyInstrumentation({
requestHook(span) {
addOriginToSpan(span, 'auto.http.otel.fastify');
},
}),
],
});
},
};
}) satisfies IntegrationFn;

export const fastifyIntegration = defineIntegration(_fastifyIntegration);

/**
* Express integration
*
* Capture tracing data for fastify.
*
* @deprecated Use `fastifyIntegration()` instead.
*/
export class Fastify extends NodePerformanceIntegration<void> implements Integration {
/**
Expand All @@ -23,6 +46,7 @@ export class Fastify extends NodePerformanceIntegration<void> implements Integra

public constructor() {
super();
// eslint-disable-next-line deprecation/deprecation
this.name = Fastify.id;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,73 +1,32 @@
import type { Integration } from '@sentry/types';

import type { NodePerformanceIntegration } from './NodePerformanceIntegration';
import { Express } from './express';
import { Fastify } from './fastify';
import { GraphQL } from './graphql';
import { Hapi } from './hapi';
import { Mongo } from './mongo';
import { Mongoose } from './mongoose';
import { Mysql } from './mysql';
import { Mysql2 } from './mysql2';
import { Nest } from './nest';
import { Postgres } from './postgres';
import { Prisma } from './prisma';

const INTEGRATIONS: (() => NodePerformanceIntegration<unknown>)[] = [
() => {
return new Express();
},
() => {
return new Fastify();
},
() => {
return new GraphQL();
},
() => {
return new Mongo();
},
() => {
return new Mongoose();
},
() => {
return new Mysql();
},
() => {
return new Mysql2();
},
() => {
return new Postgres();
},
() => {
return new Prisma();
},
() => {
return new Nest();
},
() => {
return new Hapi();
},
];
import { expressIntegration } from './express';
import { fastifyIntegration } from './fastify';
import { graphqlIntegration } from './graphql';
import { hapiIntegration } from './hapi';
import { mongoIntegration } from './mongo';
import { mongooseIntegration } from './mongoose';
import { mysqlIntegration } from './mysql';
import { mysql2Integration } from './mysql2';
import { nestIntegration } from './nest';
import { postgresIntegration } from './postgres';
import { prismaIntegration } from './prisma';

/**
* Get auto-dsicovered performance integrations.
* Note that due to the way OpenTelemetry instrumentation works, this will generally still return Integrations
* for stuff that may not be installed. This is because Otel only instruments when the module is imported/required,
* so if the package is not required at all it will not be patched, and thus not instrumented.
* But the _Sentry_ Integration will still be added.
* This _may_ be a bit confusing because it shows all integrations as being installed in the debug logs, but this is
* technically not wrong because we install it (it just doesn't do anything).
* With OTEL, all performance integrations will be added, as OTEL only initializes them when the patched package is actually required.
*/
export function getAutoPerformanceIntegrations(): Integration[] {
const loadedIntegrations = INTEGRATIONS.map(tryLoad => {
try {
const integration = tryLoad();
const isLoaded = integration.loadInstrumentations();
return isLoaded ? integration : false;
} catch (_) {
return false;
}
}).filter(integration => !!integration) as Integration[];

return loadedIntegrations;
return [
expressIntegration(),
fastifyIntegration(),
graphqlIntegration(),
mongoIntegration(),
mongooseIntegration(),
mysqlIntegration(),
mysql2Integration(),
postgresIntegration(),
prismaIntegration(),
nestIntegration(),
hapiIntegration(),
];
}
27 changes: 26 additions & 1 deletion packages/node-experimental/src/integrations/graphql.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,38 @@
import type { Instrumentation } from '@opentelemetry/instrumentation';
import { registerInstrumentations } from '@opentelemetry/instrumentation';
import { GraphQLInstrumentation } from '@opentelemetry/instrumentation-graphql';
import type { Integration } from '@sentry/types';
import { defineIntegration } from '@sentry/core';
import type { Integration, IntegrationFn } from '@sentry/types';

import { addOriginToSpan } from '../utils/addOriginToSpan';
import { NodePerformanceIntegration } from './NodePerformanceIntegration';

const _graphqlIntegration = (() => {
return {
name: 'Graphql',
setupOnce() {
registerInstrumentations({
instrumentations: [
new GraphQLInstrumentation({
ignoreTrivialResolveSpans: true,
responseHook(span) {
addOriginToSpan(span, 'auto.graphql.otel.graphql');
},
}),
],
});
},
};
}) satisfies IntegrationFn;

export const graphqlIntegration = defineIntegration(_graphqlIntegration);

/**
* GraphQL integration
*
* Capture tracing data for GraphQL.
*
* @deprecated Use `graphqlIntegration()` instead.
*/
export class GraphQL extends NodePerformanceIntegration<void> implements Integration {
/**
Expand All @@ -23,6 +47,7 @@ export class GraphQL extends NodePerformanceIntegration<void> implements Integra

public constructor() {
super();
// eslint-disable-next-line deprecation/deprecation
this.name = GraphQL.id;
}

Expand Down
20 changes: 19 additions & 1 deletion packages/node-experimental/src/integrations/hapi.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,30 @@
import type { Instrumentation } from '@opentelemetry/instrumentation';
import { registerInstrumentations } from '@opentelemetry/instrumentation';
import { HapiInstrumentation } from '@opentelemetry/instrumentation-hapi';
import type { Integration } from '@sentry/types';
import { defineIntegration } from '@sentry/core';
import type { Integration, IntegrationFn } from '@sentry/types';

import { NodePerformanceIntegration } from './NodePerformanceIntegration';

const _hapiIntegration = (() => {
return {
name: 'Hapi',
setupOnce() {
registerInstrumentations({
instrumentations: [new HapiInstrumentation()],
});
},
};
}) satisfies IntegrationFn;

export const hapiIntegration = defineIntegration(_hapiIntegration);

/**
* Hapi integration
*
* Capture tracing data for Hapi.
*
* @deprecated Use `hapiIntegration()` instead.
*/
export class Hapi extends NodePerformanceIntegration<void> implements Integration {
/**
Expand All @@ -22,6 +39,7 @@ export class Hapi extends NodePerformanceIntegration<void> implements Integratio

public constructor() {
super();
// eslint-disable-next-line deprecation/deprecation
this.name = Hapi.id;
}

Expand Down
Loading

0 comments on commit c0bcd8e

Please sign in to comment.