0
# Module Definitions
1
2
The module definition system allows instrumentations to specify which modules and files to instrument, their supported versions, and how to patch/unpatch them.
3
4
## Capabilities
5
6
### InstrumentationNodeModuleDefinition
7
8
Defines instrumentation for an entire Node.js module with optional file-level patching.
9
10
```typescript { .api }
11
/**
12
* Implementation of InstrumentationModuleDefinition for Node.js modules
13
*/
14
class InstrumentationNodeModuleDefinition implements InstrumentationModuleDefinition {
15
files: InstrumentationModuleFile[];
16
17
constructor(
18
/** Module name or path */
19
public name: string,
20
/** Supported version ranges using semver syntax */
21
public supportedVersions: string[],
22
/** Optional module-level patch function */
23
public patch?: (exports: any, moduleVersion?: string) => any,
24
/** Optional module-level unpatch function */
25
public unpatch?: (exports: any, moduleVersion?: string) => void,
26
/** Optional file-level instrumentation definitions */
27
files?: InstrumentationModuleFile[]
28
);
29
}
30
```
31
32
**Usage Example:**
33
34
```typescript
35
import { InstrumentationNodeModuleDefinition } from "@opentelemetry/instrumentation";
36
37
// Simple module-level instrumentation
38
const httpDefinition = new InstrumentationNodeModuleDefinition(
39
"http",
40
["*"], // Support all versions
41
(moduleExports, moduleVersion) => {
42
// Patch http.request and http.get
43
shimmer.wrap(moduleExports, 'request', wrapRequest);
44
shimmer.wrap(moduleExports, 'get', wrapGet);
45
return moduleExports;
46
},
47
(moduleExports, moduleVersion) => {
48
// Unpatch http.request and http.get
49
shimmer.unwrap(moduleExports, 'request');
50
shimmer.unwrap(moduleExports, 'get');
51
}
52
);
53
54
// Module with version constraints
55
const expressDefinition = new InstrumentationNodeModuleDefinition(
56
"express",
57
[">=4.0.0 <6.0.0"], // Support Express 4.x and 5.x
58
(moduleExports, moduleVersion) => {
59
// Patch Express application
60
return moduleExports;
61
}
62
);
63
```
64
65
### InstrumentationNodeModuleFile
66
67
Defines instrumentation for specific files within a module.
68
69
```typescript { .api }
70
/**
71
* Implementation of InstrumentationModuleFile for Node.js module files
72
*/
73
class InstrumentationNodeModuleFile implements InstrumentationModuleFile {
74
public name: string;
75
76
constructor(
77
/** File name with relative path */
78
name: string,
79
/** Supported version ranges using semver syntax */
80
public supportedVersions: string[],
81
/** File-level patch function */
82
public patch: (moduleExports: any, moduleVersion?: string) => any,
83
/** File-level unpatch function */
84
public unpatch: (moduleExports?: any, moduleVersion?: string) => void
85
);
86
}
87
```
88
89
**Usage Example:**
90
91
```typescript
92
import { InstrumentationNodeModuleFile } from "@opentelemetry/instrumentation";
93
94
// File-level instrumentation
95
const routerFile = new InstrumentationNodeModuleFile(
96
"lib/router/index.js",
97
[">=4.0.0 <6.0.0"],
98
(moduleExports, moduleVersion) => {
99
// Patch specific router methods
100
shimmer.wrap(moduleExports.prototype, 'use', wrapUse);
101
return moduleExports;
102
},
103
(moduleExports, moduleVersion) => {
104
// Unpatch router methods
105
shimmer.unwrap(moduleExports.prototype, 'use');
106
}
107
);
108
109
// Combined module with file-level instrumentation
110
const expressWithFiles = new InstrumentationNodeModuleDefinition(
111
"express",
112
[">=4.0.0 <6.0.0"],
113
undefined, // No module-level patch
114
undefined, // No module-level unpatch
115
[routerFile] // File-level instrumentation
116
);
117
```
118
119
### Module Definition Interfaces
120
121
Core interfaces for module and file instrumentation definitions.
122
123
```typescript { .api }
124
/**
125
* Interface for module instrumentation definition
126
*/
127
interface InstrumentationModuleDefinition {
128
/** Module name or path */
129
name: string;
130
/** Module exports (set at runtime) */
131
moduleExports?: any;
132
/** Module version (set at runtime) */
133
moduleVersion?: string;
134
/** Supported version ranges */
135
supportedVersions: string[];
136
/** File-level instrumentation definitions */
137
files: InstrumentationModuleFile[];
138
/** Include prerelease versions in semver check */
139
includePrerelease?: boolean;
140
/** Optional module-level patch function */
141
patch?: (moduleExports: any, moduleVersion?: string) => any;
142
/** Optional module-level unpatch function */
143
unpatch?: (moduleExports: any, moduleVersion?: string) => void;
144
}
145
146
/**
147
* Interface for file instrumentation definition
148
*/
149
interface InstrumentationModuleFile {
150
/** File name with relative path */
151
name: string;
152
/** Module exports for this file (set at runtime) */
153
moduleExports?: unknown;
154
/** Supported version ranges */
155
supportedVersions: string[];
156
/** File-level patch function */
157
patch(moduleExports: unknown, moduleVersion?: string): unknown;
158
/** File-level unpatch function */
159
unpatch(moduleExports?: unknown, moduleVersion?: string): void;
160
}
161
```
162
163
### Version Constraint Patterns
164
165
Common patterns for specifying supported module versions using semver ranges.
166
167
**Usage Examples:**
168
169
```typescript
170
// Support all versions
171
new InstrumentationNodeModuleDefinition("lodash", ["*"]);
172
173
// Support specific major version
174
new InstrumentationNodeModuleDefinition("express", [">=4.0.0 <5.0.0"]);
175
176
// Support multiple major versions
177
new InstrumentationNodeModuleDefinition("mongoose", [">=5.0.0 <6.0.0", ">=6.0.0 <8.0.0"]);
178
179
// Support from specific version onwards
180
new InstrumentationNodeModuleDefinition("redis", [">=2.6.0"]);
181
182
// Support exact version
183
new InstrumentationNodeModuleDefinition("mysql", ["2.18.1"]);
184
185
// Support prerelease versions
186
const definition = new InstrumentationNodeModuleDefinition("beta-package", [">=1.0.0-beta"]);
187
definition.includePrerelease = true;
188
```
189
190
### Complex Module Definition
191
192
Advanced example showing module and file-level instrumentation together.
193
194
**Usage Example:**
195
196
```typescript
197
import {
198
InstrumentationNodeModuleDefinition,
199
InstrumentationNodeModuleFile
200
} from "@opentelemetry/instrumentation";
201
202
class ComplexInstrumentation extends InstrumentationBase {
203
protected init() {
204
// File-level instrumentations
205
const applicationFile = new InstrumentationNodeModuleFile(
206
"lib/application.js",
207
[">=4.0.0 <6.0.0"],
208
(moduleExports, moduleVersion) => {
209
shimmer.wrap(moduleExports, 'listen', this._patchListen.bind(this));
210
return moduleExports;
211
},
212
(moduleExports) => {
213
shimmer.unwrap(moduleExports, 'listen');
214
}
215
);
216
217
const routerFile = new InstrumentationNodeModuleFile(
218
"lib/router/index.js",
219
[">=4.0.0 <6.0.0"],
220
(moduleExports, moduleVersion) => {
221
shimmer.wrap(moduleExports.prototype, 'use', this._patchUse.bind(this));
222
return moduleExports;
223
},
224
(moduleExports) => {
225
shimmer.unwrap(moduleExports.prototype, 'use');
226
}
227
);
228
229
// Module definition with both module and file-level instrumentation
230
return new InstrumentationNodeModuleDefinition(
231
"express",
232
[">=4.0.0 <6.0.0"],
233
(moduleExports, moduleVersion) => {
234
// Module-level patches
235
shimmer.wrap(moduleExports, 'Router', this._patchRouter.bind(this));
236
return moduleExports;
237
},
238
(moduleExports) => {
239
// Module-level unpatches
240
shimmer.unwrap(moduleExports, 'Router');
241
},
242
[applicationFile, routerFile] // File-level instrumentation
243
);
244
}
245
246
private _patchListen(original: Function) {
247
return function(this: any, ...args: any[]) {
248
// Add server startup tracing
249
return original.apply(this, args);
250
};
251
}
252
253
private _patchUse(original: Function) {
254
return function(this: any, ...args: any[]) {
255
// Add middleware tracing
256
return original.apply(this, args);
257
};
258
}
259
260
private _patchRouter(original: Function) {
261
return function(this: any, ...args: any[]) {
262
// Add router creation tracing
263
return original.apply(this, args);
264
};
265
}
266
}
267
```
268
269
### Error Handling
270
271
Module definitions should handle version mismatches and missing modules gracefully.
272
273
**Usage Example:**
274
275
```typescript
276
class RobustInstrumentation extends InstrumentationBase {
277
protected init() {
278
return new InstrumentationNodeModuleDefinition(
279
"optional-module",
280
[">=1.0.0 <3.0.0"],
281
(moduleExports, moduleVersion) => {
282
try {
283
// Check if the expected API exists
284
if (typeof moduleExports.methodToWrap !== 'function') {
285
this._diag.warn('Expected method not found, skipping instrumentation');
286
return moduleExports;
287
}
288
289
shimmer.wrap(moduleExports, 'methodToWrap', this._wrapMethod.bind(this));
290
return moduleExports;
291
} catch (error) {
292
this._diag.error('Failed to patch module', error);
293
return moduleExports;
294
}
295
},
296
(moduleExports) => {
297
try {
298
if (moduleExports && typeof moduleExports.methodToWrap === 'function') {
299
shimmer.unwrap(moduleExports, 'methodToWrap');
300
}
301
} catch (error) {
302
this._diag.error('Failed to unpatch module', error);
303
}
304
}
305
);
306
}
307
}