node-oom-heapdump 2.1.0-progress.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js CHANGED
@@ -1,228 +1,194 @@
1
- let cp = require("child_process");
2
- let fs = require("fs");
3
- let path = require("path");
4
-
5
- class NodeOomHeapDumpImpl {
6
- constructor(options) {
7
- this._opts = options;
8
- this._files = [];
9
- this._busy = false;
10
- this._count = 0;
11
- this._limitReached = false;
12
-
13
- if (this._opts.heapdumpOnOOM) {
14
- if (options.OOMImplementation === "NATIVE_HOOK") {
15
- require('bindings')('node_oom_heapdump_native.node').call(this._getHeapSnapshotPath(this._opts.path), this._opts.addTimestamp);
16
- } else if (options.OOMImplementation === "GC_MONITORING") {
17
- this._monitorHeap();
18
- }
19
- }
20
- }
21
-
22
- _monitorHeap() {
23
- // see https://www.npmjs.com/package/gc-stats
24
- let gcStats = new require('gc-stats')();
25
- gcStats.on('stats', (stats) => {
26
- // gctype 2 is a Full GC (Mark/Sweep/Compact)
27
- if (stats.gctype === 2 && !this._busy) {
28
- let memoryUsagePercentage = Math.round((stats.after.usedHeapSize / stats.after.heapSizeLimit) * 100);
29
- if (memoryUsagePercentage > this._opts.threshold) {
30
- if (this._count < this._opts.limit) {
31
- // this is a full GC and the used heap size is using more than x% of the assigned heap space limit
32
- console.warn('OoM is imminent: Full GC (Mark/Sweep/Compact) complete and still more than %s% (%s%) of the heap is used. Creating heapdump now. GC stats: ', this._opts.threshold, Math.round(memoryUsagePercentage), JSON.stringify(stats));
33
-
34
- this.createHeapSnapshot(this._opts.path, "OoM");
35
-
36
- // block execution of other code for a while (5 second) to enable snapshot to be created
37
- const time = Date.now();
38
- let diff = 0;
39
- do {
40
- diff = Date.now() - time;
41
- }
42
- while (diff < 5000);
43
- } else if (!this._limitReached) {
44
- this._limitReached = true;
45
- console.warn("OoM heapdump limit reached (%s); no more heapdumps will be created.", this._opts.limit);
46
- return;
47
- }
48
- }
49
- }
50
- });
51
- }
52
-
53
-
54
- /**
55
- * Calls the designated worker and returns a promise
56
- * @param {String} workerPath - path of the worker
57
- * @param {String[]} workerArgs - arguments to worker
58
- * @return {Promise} resolve on success, reject on error
59
- */
60
- _callWorker(workerPath, workerArgs) {
61
- if (this._busy) {
62
- return new Promise((resolve, reject) => {
63
- reject(new Error("A CPU profile or heapdump is already being created, please retry later."));
64
- });
65
- }
66
-
67
- var args = [path.resolve(__dirname, workerPath)].concat(workerArgs);
68
-
69
- // use 'require-main-filename' module instead of require.main.filename, see https://github.com/blueconic/node-oom-heapdump/issues/3
70
- let mainFilename = require('require-main-filename')();
71
-
72
- // start worker
73
- let child = cp.spawn('node', args, {
74
- cmd: path.dirname(mainFilename),
75
- stdio: 'inherit'
76
- });
77
-
78
- return new Promise((resolve, reject) => {
79
- this._busy = true;
80
- var error = null;
81
-
82
- child.on('error', (err) => {
83
- error = err;
84
- reject(err);
85
- });
86
- child.on('exit', (code) => {
87
- if (!error) {
88
- if (code === 0) {
89
- resolve();
90
- } else {
91
- reject(new Error("Worker exited with statusCode: " + code));
92
- }
93
- }
94
- this._busy = false;
95
- });
96
- });
97
- }
98
-
99
- /**
100
- * Returns the path to the created heap snapshot in a promise, or rejects on error
101
- * @param {String} snapshotPath - path of the snapshot
102
- * @param {String} logPrefix - optional log prefix message when heapdump is created
103
- * @return {Promise} the heap snapshot path on success or error on rejection
104
- */
105
- createHeapSnapshot(snapshotPath, logPrefix) {
106
- snapshotPath = this._getHeapSnapshotPath(snapshotPath, logPrefix);
107
-
108
- // start OoMworker to create heapdump
109
- return this._callWorker('./heapdumpWorker.js', [this._opts.port, snapshotPath, logPrefix || ""]).then(() => {
110
- if (logPrefix === "OoM") {
111
- this._count++;
112
- }
113
- if (!this._files.includes(snapshotPath)) {
114
- this._files.push(snapshotPath);
115
- }
116
- return snapshotPath;
117
- });
118
- }
119
-
120
- /**
121
- * Returns the path to the created CPU profile in a promise, or rejects on error
122
- * @param {String} cpuProfilePath - path of the CPU profile
123
- * @param {number} duration - the duration of the cpu profile (in ms)
124
- * @return {Promise} the CPU profile path on success or error on rejection
125
- */
126
- createCpuProfile(cpuProfilePath, duration) {
127
- if (!cpuProfilePath) {
128
- cpuProfilePath = path.resolve(__dirname, "../cpuprofile-" + Date.now());
129
- }
130
- if (!cpuProfilePath.endsWith(".cpuprofile")) {
131
- cpuProfilePath += ".cpuprofile";
132
- }
133
-
134
- // start OoMworker to create heapdump
135
- return this._callWorker('./cpuProfileWorker.js', [this._opts.port, cpuProfilePath, duration]).then(() => {
136
- if (!this._files.includes(cpuProfilePath)) {
137
- this._files.push(cpuProfilePath);
138
- }
139
- return cpuProfilePath;
140
- });
141
- }
142
-
143
- /**
144
- * Delete all created heap snapshots
145
- */
146
- deleteAllHeapSnapshots() {
147
- this._files.forEach((snapshotPath) => {
148
- if (snapshotPath.endsWith(".heapsnapshot")) {
149
- this.deleteHeapSnapshot(snapshotPath);
150
- }
151
- });
152
- }
153
-
154
- /**
155
- * Deletes a particular snapshot from disk
156
- * @param {String} snapshotPath - path of the heap snapshot to delete
157
- * @return {Promise}
158
- */
159
- deleteHeapSnapshot(snapshotPath) {
160
- return this._deleteFile(snapshotPath);
161
- }
162
-
163
- /**
164
- * Delete all created CPU profiles
165
- */
166
- deleteAllCpuProfiles() {
167
- this._files.forEach((path) => {
168
- if (path.endsWith(".cpuprofile")) {
169
- this.deleteCpuProfile(path);
170
- }
171
- });
172
- }
173
-
174
- /**
175
- * Deletes a particular CPU profile from disk
176
- * @param {String} cpuProfilePath - path of the CPU profile to delete
177
- * @return {Promise}
178
- */
179
- deleteCpuProfile(cpuProfilePath) {
180
- return this._deleteFile(cpuProfilePath);
181
- }
182
-
183
- /**
184
- * Deletes a given CPU profile or heapsnapshot from disk
185
- * @param {String} path - path to the file to delete
186
- * @return {Promise}
187
- */
188
- _deleteFile(path) {
189
- return new Promise((resolve, reject) => {
190
- if (this._files.includes(path)) {
191
- fs.unlink(path, (err) => {
192
- if (err) {
193
- reject(err);
194
- } else {
195
- resolve(path);
196
- }
197
- });
198
- } else {
199
- reject(new Error("File not found:" + path));
200
- }
201
- });
202
- }
203
-
204
- /**
205
- * Returns a proper snapshot path, based on the given parameter
206
- * @param {String} snapshotPath
207
- * @param {String} logPrefix
208
- * @return {String} path
209
- */
210
- _getHeapSnapshotPath(snapshotPath, logPrefix) {
211
- if (!snapshotPath) {
212
- snapshotPath = path.resolve(__dirname, "../heapsnapshot-" + Date.now());
213
- }
214
- if (logPrefix === "OoM" && this._opts.addTimestamp) {
215
- if (snapshotPath.endsWith(".heapsnapshot")) {
216
- snapshotPath = snapshotPath.replace(".heapsnapshot", "");
217
- }
218
- // in case of OoM error, add timestamp if needed
219
- snapshotPath += "-" + Date.now();
220
- }
221
- if (!snapshotPath.endsWith(".heapsnapshot")) {
222
- snapshotPath += ".heapsnapshot";
223
- }
224
- return snapshotPath;
225
- }
226
- }
227
-
1
+ let cp = require("child_process");
2
+ let fs = require("fs");
3
+ let path = require("path");
4
+
5
+ class NodeOomHeapDumpImpl {
6
+ constructor(options) {
7
+ this._opts = options;
8
+ this._files = [];
9
+ this._busy = false;
10
+ this._count = 0;
11
+
12
+ if (this._opts.heapdumpOnOOM) {
13
+ if (options.OOMImplementation === "NATIVE_HOOK") {
14
+ require('bindings')('node_oom_heapdump_native.node').call(this._getHeapSnapshotPath(this._opts.path), this._opts.addTimestamp);
15
+ }
16
+ }
17
+ }
18
+
19
+
20
+ /**
21
+ * Calls the designated worker and returns a promise
22
+ * @param {String} workerPath - path of the worker
23
+ * @param {String[]} workerArgs - arguments to worker
24
+ * @return {Promise} resolve on success, reject on error
25
+ */
26
+ _callWorker(workerPath, workerArgs) {
27
+ if (this._busy) {
28
+ return new Promise((resolve, reject) => {
29
+ reject(new Error("A CPU profile or heapdump is already being created, please retry later."));
30
+ });
31
+ }
32
+
33
+ var args = [path.resolve(__dirname, workerPath)].concat(workerArgs);
34
+
35
+ // use 'require-main-filename' module instead of require.main.filename, see https://github.com/blueconic/node-oom-heapdump/issues/3
36
+ let mainFilename = require('require-main-filename')();
37
+
38
+ // start worker
39
+ let child = cp.spawn('node', args, {
40
+ cmd: path.dirname(mainFilename),
41
+ stdio: 'inherit'
42
+ });
43
+
44
+ return new Promise((resolve, reject) => {
45
+ this._busy = true;
46
+ var error = null;
47
+
48
+ child.on('error', (err) => {
49
+ error = err;
50
+ reject(err);
51
+ });
52
+ child.on('exit', (code) => {
53
+ if (!error) {
54
+ if (code === 0) {
55
+ resolve();
56
+ } else {
57
+ reject(new Error("Worker exited with statusCode: " + code));
58
+ }
59
+ }
60
+ this._busy = false;
61
+ });
62
+ });
63
+ }
64
+
65
+ /**
66
+ * Returns the path to the created heap snapshot in a promise, or rejects on error
67
+ * @param {String} snapshotPath - path of the snapshot
68
+ * @param {String} logPrefix - optional log prefix message when heapdump is created
69
+ * @return {Promise} the heap snapshot path on success or error on rejection
70
+ */
71
+ createHeapSnapshot(snapshotPath, logPrefix) {
72
+ snapshotPath = this._getHeapSnapshotPath(snapshotPath, logPrefix);
73
+
74
+ // start OoMworker to create heapdump
75
+ return this._callWorker('./heapdumpWorker.js', [this._opts.port, snapshotPath, logPrefix || ""]).then(() => {
76
+ if (logPrefix === "OoM") {
77
+ this._count++;
78
+ }
79
+ if (!this._files.includes(snapshotPath)) {
80
+ this._files.push(snapshotPath);
81
+ }
82
+ return snapshotPath;
83
+ });
84
+ }
85
+
86
+ /**
87
+ * Returns the path to the created CPU profile in a promise, or rejects on error
88
+ * @param {String} cpuProfilePath - path of the CPU profile
89
+ * @param {number} duration - the duration of the cpu profile (in ms)
90
+ * @return {Promise} the CPU profile path on success or error on rejection
91
+ */
92
+ createCpuProfile(cpuProfilePath, duration) {
93
+ if (!cpuProfilePath) {
94
+ cpuProfilePath = path.resolve(__dirname, "../cpuprofile-" + Date.now());
95
+ }
96
+ if (!cpuProfilePath.endsWith(".cpuprofile")) {
97
+ cpuProfilePath += ".cpuprofile";
98
+ }
99
+
100
+ // start OoMworker to create heapdump
101
+ return this._callWorker('./cpuProfileWorker.js', [this._opts.port, cpuProfilePath, duration]).then(() => {
102
+ if (!this._files.includes(cpuProfilePath)) {
103
+ this._files.push(cpuProfilePath);
104
+ }
105
+ return cpuProfilePath;
106
+ });
107
+ }
108
+
109
+ /**
110
+ * Delete all created heap snapshots
111
+ */
112
+ deleteAllHeapSnapshots() {
113
+ this._files.forEach((snapshotPath) => {
114
+ if (snapshotPath.endsWith(".heapsnapshot")) {
115
+ this.deleteHeapSnapshot(snapshotPath);
116
+ }
117
+ });
118
+ }
119
+
120
+ /**
121
+ * Deletes a particular snapshot from disk
122
+ * @param {String} snapshotPath - path of the heap snapshot to delete
123
+ * @return {Promise}
124
+ */
125
+ deleteHeapSnapshot(snapshotPath) {
126
+ return this._deleteFile(snapshotPath);
127
+ }
128
+
129
+ /**
130
+ * Delete all created CPU profiles
131
+ */
132
+ deleteAllCpuProfiles() {
133
+ this._files.forEach((path) => {
134
+ if (path.endsWith(".cpuprofile")) {
135
+ this.deleteCpuProfile(path);
136
+ }
137
+ });
138
+ }
139
+
140
+ /**
141
+ * Deletes a particular CPU profile from disk
142
+ * @param {String} cpuProfilePath - path of the CPU profile to delete
143
+ * @return {Promise}
144
+ */
145
+ deleteCpuProfile(cpuProfilePath) {
146
+ return this._deleteFile(cpuProfilePath);
147
+ }
148
+
149
+ /**
150
+ * Deletes a given CPU profile or heapsnapshot from disk
151
+ * @param {String} path - path to the file to delete
152
+ * @return {Promise}
153
+ */
154
+ _deleteFile(path) {
155
+ return new Promise((resolve, reject) => {
156
+ if (this._files.includes(path)) {
157
+ fs.unlink(path, (err) => {
158
+ if (err) {
159
+ reject(err);
160
+ } else {
161
+ resolve(path);
162
+ }
163
+ });
164
+ } else {
165
+ reject(new Error("File not found:" + path));
166
+ }
167
+ });
168
+ }
169
+
170
+ /**
171
+ * Returns a proper snapshot path, based on the given parameter
172
+ * @param {String} snapshotPath
173
+ * @param {String} logPrefix
174
+ * @return {String} path
175
+ */
176
+ _getHeapSnapshotPath(snapshotPath, logPrefix) {
177
+ if (!snapshotPath) {
178
+ snapshotPath = path.resolve(__dirname, "../heapsnapshot-" + Date.now());
179
+ }
180
+ if (logPrefix === "OoM" && this._opts.addTimestamp) {
181
+ if (snapshotPath.endsWith(".heapsnapshot")) {
182
+ snapshotPath = snapshotPath.replace(".heapsnapshot", "");
183
+ }
184
+ // in case of OoM error, add timestamp if needed
185
+ snapshotPath += "-" + Date.now();
186
+ }
187
+ if (!snapshotPath.endsWith(".heapsnapshot")) {
188
+ snapshotPath += ".heapsnapshot";
189
+ }
190
+ return snapshotPath;
191
+ }
192
+ }
193
+
228
194
  module.exports = NodeOomHeapDumpImpl;
@@ -1,110 +1,119 @@
1
- #include <nan.h>
2
- #include <v8-profiler.h>
3
- #include <stdlib.h>
4
- #if defined(_WIN32)
5
- #include <time.h>
6
- #define snprintf _snprintf
7
- #else
8
- #include <sys/time.h>
9
- #endif
10
-
11
- using namespace v8;
12
-
13
- char filename[256];
14
- bool addTimestamp;
15
-
16
- class FileOutputStream: public OutputStream {
17
- public:
18
- FileOutputStream(FILE* stream): stream_(stream) { }
19
- virtual int GetChunkSize() {
20
- return 65536;
21
- }
22
- virtual void EndOfStream() { }
23
- virtual WriteResult WriteAsciiChunk(char* data, int size) {
24
- const size_t len = static_cast<size_t>(size);
25
- size_t off = 0;
26
- while (off < len && !feof(stream_) && !ferror(stream_))
27
- off += fwrite(data + off, 1, len - off, stream_);
28
- return off == len ? kContinue : kAbort;
29
- }
30
-
31
- private:
32
- FILE* stream_;
33
- };
34
-
35
- class ActivityControlAdapter : public ActivityControl {
36
- public:
37
- ActivityControlAdapter()
38
- {}
39
-
40
- ControlOption ReportProgressValue(int done, int total) {
41
- printf("\nProgress of heapdump: %d, %d", done, total);
42
- return kContinue;
43
- }
44
- };
45
-
46
- void OnOOMError(const char *location, bool is_heap_oom) {
47
- if (addTimestamp) {
48
- // Add timestamp to filename
49
- time_t rawtime;
50
- struct tm* timeinfo;
51
- time(&rawtime);
52
- timeinfo = localtime(&rawtime);
53
-
54
- char * pch;
55
- pch = strstr (filename,".heapsnapshot");
56
- strncpy (pch,"",1);
57
- strcat (filename, "-%Y%m%dT%H%M%S.heapsnapshot");
58
-
59
- char newFilename[256];
60
- strftime(newFilename, sizeof(filename), filename, timeinfo);
61
- strcpy(filename, newFilename);
62
- }
63
-
64
- fprintf(stderr, "Generating Heapdump to '%s' now...\n", filename);
65
- FILE* fp = fopen(filename, "w");
66
- if (fp == NULL) abort();
67
-
68
- // Create heapdump, depending on which Node.js version this can differ
69
- // for now, just support Node.js 7 and higher
70
-
71
- ActivityControlAdapter* control = new ActivityControlAdapter();
72
- const HeapSnapshot* snap = v8::Isolate::GetCurrent()->GetHeapProfiler()->TakeHeapSnapshot(control);
73
-
74
- FileOutputStream stream(fp);
75
- snap->Serialize(&stream, HeapSnapshot::kJSON);
76
- fclose(fp);
77
-
78
- fprintf(stderr, "Done! Exiting process now.\n");
79
- exit(1);
80
-
81
- }
82
-
83
- void ParseArgumentsAndSetErrorHandler(const FunctionCallbackInfo<Value>& args) {
84
- Isolate* isolate = args.GetIsolate();
85
- isolate->SetOOMErrorHandler(OnOOMError);
86
-
87
- // parse JS arguments
88
- // 1: filename
89
- // 2: addTimestamp boolean
90
- #if NODE_VERSION_AT_LEAST(12, 0, 0)
91
- String::Utf8Value fArg(isolate, args[0]->ToString(isolate));
92
- #elif NODE_VERSION_AT_LEAST(9, 0, 0)
93
- String::Utf8Value fArg(isolate, args[0]->ToString());
94
- #else
95
- String::Utf8Value fArg(args[0]->ToString());
96
- #endif
97
- strncpy(filename, (const char*)(*fArg), sizeof(filename) - 1);
98
-
99
- #if NODE_VERSION_AT_LEAST(12, 0, 0)
100
- addTimestamp = args[1]->BooleanValue(isolate);
101
- #else
102
- addTimestamp = args[1]->BooleanValue();
103
- #endif
104
- }
105
-
106
- void init(Local<Object> exports) {
107
- NODE_SET_METHOD(exports, "call", ParseArgumentsAndSetErrorHandler);
108
- }
109
-
110
- NODE_MODULE(NODE_OOM_HEAPDUMP_NATIVE, init)
1
+ #include <nan.h>
2
+ #include <v8-profiler.h>
3
+ #include <stdlib.h>
4
+ #if defined(_WIN32)
5
+ #include <time.h>
6
+ #define snprintf _snprintf
7
+ #else
8
+ #include <sys/time.h>
9
+ #endif
10
+
11
+ using namespace v8;
12
+
13
+ char filename[256];
14
+ bool addTimestamp;
15
+ bool processingOOM = false;
16
+
17
+ class FileOutputStream: public OutputStream {
18
+ public:
19
+ FileOutputStream(FILE* stream): stream_(stream) { }
20
+ virtual int GetChunkSize() {
21
+ return 65536;
22
+ }
23
+ virtual void EndOfStream() { }
24
+ virtual WriteResult WriteAsciiChunk(char* data, int size) {
25
+ const size_t len = static_cast<size_t>(size);
26
+ size_t off = 0;
27
+ while (off < len && !feof(stream_) && !ferror(stream_))
28
+ off += fwrite(data + off, 1, len - off, stream_);
29
+ return off == len ? kContinue : kAbort;
30
+ }
31
+
32
+ private:
33
+ FILE* stream_;
34
+ };
35
+
36
+ size_t RaiseLimit(void* data, size_t current_heap_limit, size_t initial_heap_limit) {
37
+ return current_heap_limit + 10u * 1024 * 1024; // 10MiB
38
+ }
39
+
40
+ void OnOOMError(const char *location, bool is_heap_oom) {
41
+ if (processingOOM) {
42
+ fprintf(stderr, "FATAL: OnOOMError called more than once.\n");
43
+ exit(2);
44
+ }
45
+ processingOOM = true;
46
+
47
+ if (addTimestamp) {
48
+ // Add timestamp to filename
49
+ time_t rawtime;
50
+ struct tm* timeinfo;
51
+ time(&rawtime);
52
+ timeinfo = localtime(&rawtime);
53
+
54
+ char * pch;
55
+ pch = strstr (filename,".heapsnapshot");
56
+ strncpy (pch,"",1);
57
+ strcat (filename, "-%Y%m%dT%H%M%S.heapsnapshot");
58
+
59
+ char newFilename[256];
60
+ strftime(newFilename, sizeof(filename), filename, timeinfo);
61
+ strcpy(filename, newFilename);
62
+ }
63
+
64
+ fprintf(stderr, "Generating Heapdump to '%s' now...\n", filename);
65
+ FILE* fp = fopen(filename, "w");
66
+ if (fp == NULL) abort();
67
+
68
+ auto* isolate = v8::Isolate::GetCurrent();
69
+
70
+ // Capturing a heap snapshot forces a garbage collection which can, in turn,
71
+ // trigger the OOM flow which causes recursion. To prevent this, this callback
72
+ // will raise the heap limit if the GC tries to go down that path again.
73
+ // Normally we would want to add a call to RemoveNearHeapLimitCallback() after
74
+ // we are done, but that is not necessary since we exit() before it matters.
75
+ isolate->AddNearHeapLimitCallback(RaiseLimit, nullptr);
76
+
77
+ // Create heapdump, depending on which Node.js version this can differ
78
+ // for now, just support Node.js 7 and higher
79
+ const HeapSnapshot* snap = isolate->GetHeapProfiler()->TakeHeapSnapshot();
80
+
81
+ FileOutputStream stream(fp);
82
+ snap->Serialize(&stream, HeapSnapshot::kJSON);
83
+ fclose(fp);
84
+
85
+ fprintf(stderr, "Done! Exiting process now.\n");
86
+ exit(1);
87
+ }
88
+
89
+ void ParseArgumentsAndSetErrorHandler(const FunctionCallbackInfo<Value>& args) {
90
+ Isolate* isolate = args.GetIsolate();
91
+ isolate->SetOOMErrorHandler(OnOOMError);
92
+
93
+ // parse JS arguments
94
+ // 1: filename
95
+ // 2: addTimestamp boolean
96
+ #if NODE_VERSION_AT_LEAST(13, 0, 0)
97
+ Local<Context> context = isolate->GetCurrentContext();
98
+ String::Utf8Value fArg(isolate, args[0]->ToString(context).ToLocalChecked());
99
+ #elif NODE_VERSION_AT_LEAST(12, 0, 0)
100
+ String::Utf8Value fArg(isolate, args[0]->ToString(isolate));
101
+ #elif NODE_VERSION_AT_LEAST(9, 0, 0)
102
+ String::Utf8Value fArg(isolate, args[0]->ToString());
103
+ #else
104
+ String::Utf8Value fArg(args[0]->ToString());
105
+ #endif
106
+ strncpy(filename, (const char*)(*fArg), sizeof(filename) - 1);
107
+
108
+ #if NODE_VERSION_AT_LEAST(12, 0, 0)
109
+ addTimestamp = args[1]->BooleanValue(isolate);
110
+ #else
111
+ addTimestamp = args[1]->BooleanValue();
112
+ #endif
113
+ }
114
+
115
+ void init(Local<Object> exports) {
116
+ NODE_SET_METHOD(exports, "call", ParseArgumentsAndSetErrorHandler);
117
+ }
118
+
119
+ NODE_MODULE(NODE_OOM_HEAPDUMP_NATIVE, init)