-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
Copy pathchildProcess.ts
110 lines (98 loc) · 3.16 KB
/
childProcess.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import type { ChildProcess } from 'node:child_process';
import * as diagnosticsChannel from 'node:diagnostics_channel';
import type { Worker } from 'node:worker_threads';
import { addBreadcrumb, defineIntegration } from '@sentry/core';
interface Options {
/**
* Whether to include child process arguments in breadcrumbs data.
*
* @default false
*/
includeChildProcessArgs?: boolean;
}
// TODO(v9): Update this name and mention in migration docs.
const INTEGRATION_NAME = 'ProcessAndThreadBreadcrumbs';
/**
* Capture breadcrumbs for child processes and worker threads.
*/
export const childProcessIntegration = defineIntegration((options: Options = {}) => {
return {
name: INTEGRATION_NAME,
setup(_client) {
// eslint-disable-next-line deprecation/deprecation
diagnosticsChannel.channel('child_process').subscribe((event: unknown) => {
if (event && typeof event === 'object' && 'process' in event) {
captureChildProcessEvents(event.process as ChildProcess, options);
}
});
// eslint-disable-next-line deprecation/deprecation
diagnosticsChannel.channel('worker_threads').subscribe((event: unknown) => {
if (event && typeof event === 'object' && 'worker' in event) {
captureWorkerThreadEvents(event.worker as Worker);
}
});
},
};
});
/**
* Capture breadcrumbs for child processes and worker threads.
*
* @deprecated Use `childProcessIntegration` integration instead. Functionally they are the same. `processThreadBreadcrumbIntegration` will be removed in the next major version.
*/
export const processThreadBreadcrumbIntegration = childProcessIntegration;
function captureChildProcessEvents(child: ChildProcess, options: Options): void {
let hasExited = false;
let data: Record<string, unknown> | undefined;
child
.on('spawn', () => {
// This is Sentry getting macOS OS context
if (child.spawnfile === '/usr/bin/sw_vers') {
hasExited = true;
return;
}
data = { spawnfile: child.spawnfile };
if (options.includeChildProcessArgs) {
data.spawnargs = child.spawnargs;
}
})
.on('exit', code => {
if (!hasExited) {
hasExited = true;
// Only log for non-zero exit codes
if (code !== null && code !== 0) {
addBreadcrumb({
category: 'child_process',
message: `Child process exited with code '${code}'`,
level: 'warning',
data,
});
}
}
})
.on('error', error => {
if (!hasExited) {
hasExited = true;
addBreadcrumb({
category: 'child_process',
message: `Child process errored with '${error.message}'`,
level: 'error',
data,
});
}
});
}
function captureWorkerThreadEvents(worker: Worker): void {
let threadId: number | undefined;
worker
.on('online', () => {
threadId = worker.threadId;
})
.on('error', error => {
addBreadcrumb({
category: 'worker_thread',
message: `Worker thread errored with '${error.message}'`,
level: 'error',
data: { threadId },
});
});
}