Skip to content

Commit 9a9aa85

Browse files
authored
feat(profiling): add support for enabling Profiling integration (#577)
1 parent bde9750 commit 9a9aa85

File tree

6 files changed

+436
-23
lines changed

6 files changed

+436
-23
lines changed

build.config.ts

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export default defineBuildConfig({
1616
'@sentry/cli',
1717
'@sentry/core',
1818
'@sentry/node',
19+
'@sentry/profiling-node',
1920
'@sentry/types',
2021
'@sentry/webpack-plugin',
2122
'consola',

docs/content/en/guide/profiling.md

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
---
2+
title: Profiling
3+
description: Node profiling enhances tracing by providing profiles for individual transactions
4+
position: 25
5+
category: Guide
6+
---
7+
8+
Node profiling can be enabled through an integration provided by the `@sentry/profiling-node` dependency that does not come with this module by default.
9+
10+
### Setup
11+
12+
Install required dependency:
13+
14+
<code-group>
15+
<code-block label="Yarn" active>
16+
17+
```bash
18+
yarn add @sentry/profiling-node
19+
```
20+
21+
</code-block>
22+
<code-block label="NPM">
23+
24+
```bash
25+
npm install @sentry/profiling-node
26+
```
27+
28+
</code-block>
29+
</code-group>
30+
31+
Include the following options in the module's configuration:
32+
33+
```js [nuxt.config.js]
34+
sentry: {
35+
dsn: '...',
36+
tracing: {
37+
tracesSampleRate: 1.0,
38+
},
39+
serverIntegrations: {
40+
ProfilingIntegration: {},
41+
},
42+
serverConfig: {
43+
// Set sampling rate for profiling - this is relative to tracesSampleRate
44+
profilesSampleRate: 1.0,
45+
},
46+
}
47+
```
48+
49+
<alert type="info">
50+
51+
Note that the `tracesSampleRate` value can be between 0.0 and 1.0 (percentage of requests to capture) and Sentry documentation strongly recommends reducing the value from the default 1.0.
52+
53+
</alert>
54+
55+
### Documentation
56+
57+
See Sentry's [Profiling](https://docs.sentry.io/platforms/node/profiling/) pages for additional information.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
"@nuxtjs/eslint-config-typescript": "12.0.0",
7979
"@nuxtjs/module-test-utils": "1.6.3",
8080
"@release-it/conventional-changelog": "5.1.1",
81+
"@sentry/profiling-node": "^0.3.0",
8182
"@sentry/webpack-plugin": "1.20.1",
8283
"@size-limit/file": "^8.2.4",
8384
"@types/hash-sum": "1.0.0",

src/options.ts

+20-4
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import { relative } from 'pathe'
44
import { Integrations as ServerIntegrations, autoDiscoverNodePerformanceMonitoringIntegrations } from '@sentry/node'
55
import type Sentry from '@sentry/node'
66
import * as PluggableIntegrations from '@sentry/integrations'
7-
import type { Options } from '@sentry/types'
7+
import type { Integration, Options } from '@sentry/types'
88
import type { Replay } from '@sentry/vue'
9-
import type { AllIntegrations, ClientIntegrations, LazyConfiguration, TracingConfiguration } from './types/configuration'
9+
import type { AllIntegrations, ClientIntegrations, LazyConfiguration, ProfilingIntegration, TracingConfiguration } from './types/configuration'
1010
import type { ModuleConfiguration } from './types'
1111
import { Nuxt, resolveAlias } from './kit-shim'
1212
import { canInitialize } from './utils'
@@ -27,6 +27,8 @@ export const BROWSER_VUE_INTEGRATIONS = ['Replay']
2727
const SERVER_INTEGRATIONS = ['Console', 'ContextLines', 'FunctionToString', 'Http', 'InboundFilters', 'LinkedErrors', 'LocalVariables', 'Modules', 'OnUncaughtException', 'OnUnhandledRejection', 'RequestData']
2828
// Optional in Node.js - https://docs.sentry.io/platforms/node/configuration/integrations/pluggable-integrations/
2929
const SERVER_PLUGGABLE_INTEGRATIONS = ['CaptureConsole', 'Debug', 'Dedupe', 'ExtraErrorData', 'RewriteFrames', 'Transaction']
30+
// External and optional Node.js integration - https://docs.sentry.io/platforms/node/profiling/
31+
export const SERVER_PROFILING_INTEGRATION: keyof ProfilingIntegration = 'ProfilingIntegration'
3032

3133
function filterDisabledIntegrations<T extends AllIntegrations> (integrations: T): (keyof T)[] {
3234
return getIntegrationsKeys(integrations).filter(key => integrations[key])
@@ -246,13 +248,13 @@ export async function resolveServerOptions (nuxt: Nuxt, moduleOptions: Readonly<
246248
options.config = defu(getServerRuntimeConfig(nuxt, options), options.serverConfig, options.config)
247249

248250
for (const name of getIntegrationsKeys(options.serverIntegrations)) {
249-
if (!isServerDefaultIntegration(name) && !isServerPlugabbleIntegration(name)) {
251+
if (!isServerDefaultIntegration(name) && !isServerPlugabbleIntegration(name) && name !== SERVER_PROFILING_INTEGRATION) {
250252
logger.warn(`Sentry serverIntegration "${name}" is not recognized and will be ignored.`)
251253
delete options.serverIntegrations[name]
252254
}
253255
}
254256

255-
let customIntegrations = []
257+
let customIntegrations: Integration[] = []
256258
if (options.customServerIntegrations) {
257259
const resolvedPath = resolveAlias(options.customServerIntegrations)
258260
try {
@@ -265,6 +267,20 @@ export async function resolveServerOptions (nuxt: Nuxt, moduleOptions: Readonly<
265267
}
266268
}
267269

270+
if (SERVER_PROFILING_INTEGRATION in options.serverIntegrations) {
271+
const enabled = options.serverIntegrations[SERVER_PROFILING_INTEGRATION]
272+
delete options.serverIntegrations[SERVER_PROFILING_INTEGRATION]
273+
if (enabled) {
274+
try {
275+
const { ProfilingIntegration } = await (import('@sentry/profiling-node').then(m => m.default || m))
276+
customIntegrations.push(new ProfilingIntegration())
277+
} catch (error) {
278+
logger.error(`To use the ${SERVER_PROFILING_INTEGRATION} integration you need to install the "@sentry/profiling-node" dependency.`)
279+
throw new Error((error as Error).message)
280+
}
281+
}
282+
}
283+
268284
options.config.integrations = [
269285
// Automatically instrument Node.js libraries and frameworks
270286
...(options.tracing ? autoDiscoverNodePerformanceMonitoringIntegrations() : []),

src/types/configuration.d.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@ type IntegrationsConfig<T extends Record<keyof T, IntegrationClass<unknown>>> =
1010
[K in keyof T]: ConstructorParameters<T[K]>[0] | Record<string, never> | false
1111
}>
1212

13+
// A replacement type since we don't want to depend on `@sentry/profiling-node`
14+
type ProfilingIntegration = { ProfilingIntegration?: Record<string, never> | false }
15+
1316
type ClientIntegrations = IntegrationsConfig<typeof BrowserIntegrations & typeof PluggableIntegrations & { Replay: typeof Replay }>
14-
type ServerIntegrations = IntegrationsConfig<typeof NodeIntegrations & typeof PluggableIntegrations>
17+
type ServerIntegrations = IntegrationsConfig<typeof NodeIntegrations & typeof PluggableIntegrations> & ProfilingIntegration
1518
type AllIntegrations = ClientIntegrations | ServerIntegrations
1619

1720
export interface LazyConfiguration {

0 commit comments

Comments
 (0)