├── .clang-format ├── .gitignore ├── LICENSE ├── README.md ├── binding.gyp ├── index.js ├── package.json ├── src ├── heapdump-posix.h ├── heapdump-win32.h └── heapdump.cc └── test ├── test-callback-error.js ├── test-callback-without-filename.js ├── test-callback.js └── test-sigusr2.js /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | # BasedOnStyle: Google 3 | AccessModifierOffset: -1 4 | ConstructorInitializerIndentWidth: 4 5 | AlignEscapedNewlinesLeft: true 6 | AlignTrailingComments: true 7 | AllowAllParametersOfDeclarationOnNextLine: true 8 | AllowShortIfStatementsOnASingleLine: true 9 | AllowShortLoopsOnASingleLine: true 10 | AlwaysBreakTemplateDeclarations: true 11 | AlwaysBreakBeforeMultilineStrings: true 12 | BreakBeforeBinaryOperators: false 13 | BreakBeforeTernaryOperators: true 14 | BreakConstructorInitializersBeforeComma: false 15 | BinPackParameters: true 16 | ColumnLimit: 80 17 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 18 | DerivePointerBinding: true 19 | ExperimentalAutoDetectBinPacking: false 20 | IndentCaseLabels: true 21 | MaxEmptyLinesToKeep: 1 22 | NamespaceIndentation: None 23 | ObjCSpaceBeforeProtocolList: false 24 | PenaltyBreakBeforeFirstCallParameter: 1 25 | PenaltyBreakComment: 60 26 | PenaltyBreakString: 1000 27 | PenaltyBreakFirstLessLess: 120 28 | PenaltyExcessCharacter: 1000000 29 | PenaltyReturnTypeOnItsOwnLine: 200 30 | PointerBindsToType: true 31 | SpacesBeforeTrailingComments: 2 32 | Cpp11BracedListStyle: true 33 | Standard: Auto 34 | IndentWidth: 2 35 | TabWidth: 8 36 | UseTab: Never 37 | BreakBeforeBraces: Attach 38 | IndentFunctionDeclarationAfterType: true 39 | SpacesInParentheses: false 40 | SpacesInAngles: false 41 | SpaceInEmptyParentheses: false 42 | SpacesInCStyleCastParentheses: false 43 | SpaceAfterControlStatementKeyword: true 44 | SpaceBeforeAssignmentOperators: true 45 | ContinuationIndentWidth: 4 46 | ... 47 | 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.lock-wscript 2 | /build/ 3 | /node_modules/ 4 | heapdump-*.heapsnapshot 5 | heapdump-*.log 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2012, Ben Noordhuis 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | === src/compat.h src/compat-inl.h === 18 | 19 | ISC License 20 | 21 | Copyright (c) 2014, StrongLoop Inc. 22 | 23 | Permission to use, copy, modify, and/or distribute this software for any 24 | purpose with or without fee is hereby granted, provided that the above 25 | copyright notice and this permission notice appear in all copies. 26 | 27 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 28 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 29 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 30 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 31 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 32 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 33 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | node-heapdump 2 | === 3 | 4 | Make a dump of the V8 heap for later inspection. 5 | 6 | ### Install 7 | 8 | npm install heapdump 9 | 10 | ### Build 11 | 12 | node-gyp configure build 13 | 14 | ### Usage 15 | 16 | Load the add-on in your application: 17 | 18 | var heapdump = require('heapdump'); 19 | 20 | The module exports a single `writeSnapshot([filename], [callback])` function 21 | that writes out a snapshot. `filename` defaults to 22 | `heapdump-..heapsnapshot` when omitted. 23 | 24 | heapdump.writeSnapshot('/var/local/' + Date.now() + '.heapsnapshot'); 25 | 26 | The function also takes an optional callback function which is called upon 27 | completion of the heap dump. 28 | 29 | heapdump.writeSnapshot(function(err, filename) { 30 | console.log('dump written to', filename); 31 | }); 32 | 33 | The snapshot is written synchronously to disk. When the JS heap is large, 34 | it may introduce a noticeable "hitch". 35 | 36 | On UNIX platforms, you can force a snapshot by sending the node.js process 37 | a SIGUSR2 signal: 38 | 39 | $ kill -USR2 40 | 41 | The SIGUSR2 signal handler is enabled by default but you can disable it 42 | by setting `NODE_HEAPDUMP_OPTIONS=nosignal` in the environment: 43 | 44 | $ env NODE_HEAPDUMP_OPTIONS=nosignal node script.js 45 | 46 | Catch the SIGUSR2 signal to write the snapshot to a custom location: 47 | 48 | ```js 49 | if (!/nosignal/.test(process.env.NODE_HEAPDUMP_OPTIONS)) { 50 | process.on("SIGUSR2", function() { 51 | heapdump.writeSnapshot('/var/local/' + Date.now() + '.heapsnapshot'); 52 | }); 53 | } 54 | ``` 55 | 56 | ### Inspecting the snapshot 57 | 58 | Open [Google Chrome](https://www.google.com/intl/en/chrome/browser/) and 59 | press F12 to open the developer toolbar. 60 | 61 | Go to the `Memory` tab, right-click in the tab pane and select 62 | `Load profile...`. 63 | 64 | Select the dump file and click `Open`. You can now inspect the heap snapshot 65 | at your leisure. Some snapshots may take a long time to load, on the order of 66 | minutes or even hours. 67 | 68 | Note that Chrome will refuse to load the file unless it has the `.heapsnapshot` 69 | extension. 70 | 71 | ### Caveats 72 | 73 | On UNIX systems, the rule of thumb for creating a heap snapshot is that it 74 | requires memory twice the size of the heap at the time of the snapshot. 75 | If you end up with empty or truncated snapshot files, check the output of 76 | `dmesg`; you may have had a run-in with the system's OOM killer or a resource 77 | limit enforcing policy, like `ulimit -u` (max user processes) or `ulimit -v` 78 | (max virtual memory size). 79 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2012, Ben Noordhuis 2 | # 3 | # Permission to use, copy, modify, and/or distribute this software for any 4 | # purpose with or without fee is hereby granted, provided that the above 5 | # copyright notice and this permission notice appear in all copies. 6 | # 7 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | { 16 | 'targets': [ 17 | { 18 | 'target_name': 'addon', 19 | 'win_delay_load_hook': 'false', 20 | 'include_dirs': [' 2 | // 3 | // Permission to use, copy, modify, and/or distribute this software for any 4 | // purpose with or without fee is hereby granted, provided that the above 5 | // copyright notice and this permission notice appear in all copies. 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | try { 16 | var addon = require('./build/Release/addon'); 17 | } catch (e) { 18 | if (e.code !== 'MODULE_NOT_FOUND') throw e; 19 | var addon = require('./build/Debug/addon'); 20 | } 21 | 22 | var kSignalFlag = addon.kSignalFlag; 23 | 24 | var flags = kSignalFlag; 25 | var options = (process.env.NODE_HEAPDUMP_OPTIONS || '').split(/\s*,\s*/); 26 | for (var i = 0, n = options.length; i < n; i += 1) { 27 | var option = options[i]; 28 | if (option === '') continue; 29 | else if (option === 'signal') flags |= kSignalFlag; 30 | else if (option === 'nosignal') flags &= ~kSignalFlag; 31 | else console.error('node-heapdump: unrecognized option:', option); 32 | } 33 | addon.configure(flags); 34 | 35 | var os = require('os'); 36 | var errno = []; 37 | if (os.constants && os.constants.errno) { 38 | Object.keys(os.constants.errno).forEach(function(key) { 39 | var value = os.constants.errno[key]; 40 | errno[value] = key; 41 | }); 42 | } 43 | 44 | exports.writeSnapshot = function(filename, cb) { 45 | if (typeof filename === 'function') cb = filename, filename = undefined; 46 | var result = addon.writeSnapshot(filename); 47 | var success = (typeof result === 'string'); // Filename or errno. 48 | // Make the callback. Yes, this is synchronous; it wasn't back when heapdump 49 | // forked before writing the snapshot, but it is now. index.js can postpone 50 | // the callback with process.nextTick() or setImmediate() if synchronicity 51 | // becomes an issue. Or just remove it, it's pretty pointless now. 52 | if (cb) { 53 | if (success) cb(null, result); 54 | else cb(new Error('heapdump write error ' + (errno[result] || result))); 55 | } 56 | return success; 57 | }; 58 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "heapdump", 3 | "version": "0.3.15", 4 | "description": "Make a dump of the V8 heap for later inspection.", 5 | "homepage": "https://github.com/bnoordhuis/node-heapdump", 6 | "author": { 7 | "name": "Ben Noordhuis", 8 | "email": "info@bnoordhuis.nl", 9 | "url": "http://bnoordhuis.nl/" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git://github.com/bnoordhuis/node-heapdump.git" 14 | }, 15 | "engines": { 16 | "node": ">=0.10.0" 17 | }, 18 | "license": "ISC", 19 | "scripts": { 20 | "test": "tap test/test-*" 21 | }, 22 | "dependencies": { 23 | "nan": "^2.13.2" 24 | }, 25 | "devDependencies": { 26 | "shelljs": "~0.3.0", 27 | "tap": "~0.4.12" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/heapdump-posix.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Ben Noordhuis 2 | // 3 | // Permission to use, copy, modify, and/or distribute this software for any 4 | // purpose with or without fee is hereby granted, provided that the above 5 | // copyright notice and this permission notice appear in all copies. 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | #ifndef SRC_HEAPDUMP_POSIX_H_ 16 | #define SRC_HEAPDUMP_POSIX_H_ 17 | 18 | #include 19 | #include 20 | 21 | namespace { 22 | 23 | static char snapshot_filename[kMaxPath]; 24 | static uv_signal_t signal_handle; 25 | 26 | inline void OnSIGUSR2(uv_signal_t* handle, int signo) { 27 | assert(handle == &signal_handle); 28 | v8::Isolate* isolate = reinterpret_cast(handle->data); 29 | RandomSnapshotFilename(snapshot_filename, sizeof(snapshot_filename)); 30 | WriteSnapshot(isolate, snapshot_filename); 31 | } 32 | 33 | inline void PlatformInit(v8::Isolate* isolate, int flags) { 34 | const bool nosignal = !(flags & kSignalFlag); 35 | if (nosignal == false) { 36 | uv_signal_init(uv_default_loop(), &signal_handle); 37 | uv_signal_start(&signal_handle, OnSIGUSR2, SIGUSR2); 38 | uv_unref(reinterpret_cast(&signal_handle)); 39 | signal_handle.data = isolate; 40 | } 41 | } 42 | 43 | } // namespace anonymous 44 | 45 | #endif // SRC_HEAPDUMP_POSIX_H_ 46 | -------------------------------------------------------------------------------- /src/heapdump-win32.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Ben Noordhuis 2 | // 3 | // Permission to use, copy, modify, and/or distribute this software for any 4 | // purpose with or without fee is hereby granted, provided that the above 5 | // copyright notice and this permission notice appear in all copies. 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | #ifndef SRC_HEAPDUMP_WIN32_H_ 16 | #define SRC_HEAPDUMP_WIN32_H_ 17 | 18 | namespace { 19 | 20 | inline void PlatformInit(v8::Isolate*, int) {} 21 | 22 | // Emulate snprintf() on windows, _snprintf() doesn't zero-terminate the buffer 23 | // on overflow. 24 | inline int snprintf(char* buf, size_t len, const char* fmt, ...) { 25 | va_list ap; 26 | va_start(ap, fmt); 27 | const int n = _vsprintf_p(buf, len, fmt, ap); 28 | if (len) buf[len - 1] = '\0'; 29 | va_end(ap); 30 | return n; 31 | } 32 | 33 | } // namespace anonymous 34 | 35 | #endif // SRC_HEAPDUMP_WIN32_H_ 36 | -------------------------------------------------------------------------------- /src/heapdump.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Ben Noordhuis 2 | // 3 | // Permission to use, copy, modify, and/or distribute this software for any 4 | // purpose with or without fee is hereby granted, provided that the above 5 | // copyright notice and this permission notice appear in all copies. 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | #include "node.h" // Picks up BUILDING_NODE_EXTENSION on Windows, see #30. 16 | 17 | #include "nan.h" 18 | #include "uv.h" 19 | #include "v8-profiler.h" 20 | #include "v8.h" 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | namespace { 29 | 30 | static const int kMaxPath = 4096; 31 | static const int kSignalFlag = 2; 32 | inline int WriteSnapshot(v8::Isolate* isolate, const char* filename); 33 | inline void PlatformInit(v8::Isolate* isolate, int flags); 34 | inline void RandomSnapshotFilename(char* buffer, size_t size); 35 | 36 | } // namespace anonymous 37 | 38 | #ifdef _WIN32 39 | #include "heapdump-win32.h" 40 | #else 41 | #include "heapdump-posix.h" 42 | #endif 43 | 44 | namespace { 45 | 46 | class FileOutputStream : public v8::OutputStream { 47 | public: 48 | explicit FileOutputStream(FILE* stream) : stream_(stream) {} 49 | 50 | virtual int GetChunkSize() { 51 | return 65536; // big chunks == faster 52 | } 53 | 54 | virtual void EndOfStream() {} 55 | 56 | virtual WriteResult WriteAsciiChunk(char* data, int size) { 57 | const size_t len = static_cast(size); 58 | size_t off = 0; 59 | 60 | while (off < len && !feof(stream_) && !ferror(stream_)) 61 | off += fwrite(data + off, 1, len - off, stream_); 62 | 63 | return off == len ? kContinue : kAbort; 64 | } 65 | 66 | private: 67 | FILE* stream_; 68 | }; 69 | 70 | const v8::HeapSnapshot* TakeHeapSnapshot(v8::Isolate* isolate) { 71 | (void) &isolate; 72 | #if NODE_VERSION_AT_LEAST(3, 0, 0) 73 | return isolate->GetHeapProfiler()->TakeHeapSnapshot(); 74 | #elif NODE_VERSION_AT_LEAST(0, 11, 0) 75 | return isolate->GetHeapProfiler()->TakeHeapSnapshot(Nan::EmptyString()); 76 | #else 77 | return v8::HeapProfiler::TakeSnapshot(Nan::EmptyString()); 78 | #endif 79 | } 80 | 81 | NAN_METHOD(WriteSnapshot) { 82 | v8::Isolate* const isolate = info.GetIsolate(); 83 | 84 | char filename[kMaxPath]; 85 | v8::Local filename_v = info[0]; 86 | if (filename_v->IsString()) { 87 | Nan::Utf8String filename_string(filename_v); 88 | snprintf(filename, sizeof(filename), "%s", *filename_string); 89 | } else { 90 | RandomSnapshotFilename(filename, sizeof(filename)); 91 | } 92 | 93 | if (const int err = WriteSnapshot(isolate, filename)) { 94 | info.GetReturnValue().Set(err); 95 | return; // Write error. 96 | } 97 | 98 | if (!filename_v->IsString()) filename_v = Nan::New(filename).ToLocalChecked(); 99 | info.GetReturnValue().Set(filename_v); 100 | } 101 | 102 | inline int WriteSnapshot(v8::Isolate* isolate, const char* filename) { 103 | FILE* fp = fopen(filename, "w"); 104 | if (fp == NULL) return errno; 105 | const v8::HeapSnapshot* const snap = TakeHeapSnapshot(isolate); 106 | FileOutputStream stream(fp); 107 | snap->Serialize(&stream, v8::HeapSnapshot::kJSON); 108 | int err = 0; 109 | if (fclose(fp)) err = errno; 110 | // Work around a deficiency in the API. The HeapSnapshot object is const 111 | // but we cannot call HeapProfiler::DeleteAllHeapSnapshots() because that 112 | // invalidates _all_ snapshots, including those created by other tools. 113 | const_cast(snap)->Delete(); 114 | return err; 115 | } 116 | 117 | inline void RandomSnapshotFilename(char* buffer, size_t size) { 118 | const uint64_t now = uv_hrtime(); 119 | const unsigned long sec = static_cast(now / 1000000); 120 | const unsigned long usec = static_cast(now % 1000000); 121 | snprintf(buffer, size, "heapdump-%lu.%lu.heapsnapshot", sec, usec); 122 | } 123 | 124 | NAN_METHOD(Configure) { 125 | PlatformInit(info.GetIsolate(), Nan::To(info[0]).FromJust()); 126 | } 127 | 128 | NAN_MODULE_INIT(Initialize) { 129 | Nan::Set(target, 130 | Nan::New("kSignalFlag").ToLocalChecked(), 131 | Nan::New(kSignalFlag)); 132 | Nan::SetMethod(target, "configure", Configure); 133 | Nan::SetMethod(target, "writeSnapshot", WriteSnapshot); 134 | } 135 | 136 | NODE_MODULE(addon, Initialize) 137 | 138 | } // namespace anonymous 139 | -------------------------------------------------------------------------------- /test/test-callback-error.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018, Ben Noordhuis 2 | // 3 | // Permission to use, copy, modify, and/or distribute this software for any 4 | // purpose with or without fee is hereby granted, provided that the above 5 | // copyright notice and this permission notice appear in all copies. 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | 'use strict'; 16 | 17 | var assert = require('assert'); 18 | var heapdump = require('../'); 19 | 20 | var ncalls = 0; 21 | heapdump.writeSnapshot('/does/not/exist', function(err) { 22 | assert(/heapdump write error ENOENT/.test(err.message)); 23 | ncalls++; 24 | }); 25 | assert(ncalls === 1); 26 | -------------------------------------------------------------------------------- /test/test-callback-without-filename.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014, Krishna Raman 2 | // 3 | // Permission to use, copy, modify, and/or distribute this software for any 4 | // purpose with or without fee is hereby granted, provided that the above 5 | // copyright notice and this permission notice appear in all copies. 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | var path = require('path'); 16 | var http = require('http'); 17 | var shelljs = require('shelljs'); 18 | var test = require('tap').test; 19 | var heapdump = require('../'); 20 | 21 | process.chdir(__dirname); 22 | 23 | function testFuncCall(test){ 24 | var server = http.createServer(function(req, res) { 25 | res.writeHeader(200); 26 | res.end(); 27 | }); 28 | server.on('listening', function(){ 29 | console.log('Listening on http://127.0.0.1:8000/'); 30 | console.log('PID %d', process.pid); 31 | 32 | var heapSnapshotFile = 'heapdump-*.heapsnapshot'; 33 | shelljs.rm('-f', heapSnapshotFile); 34 | 35 | function waitForHeapdump(err, filename) { 36 | var files = shelljs.ls(heapSnapshotFile); 37 | test.equals(err, null); 38 | test.equals(files.length, 1); 39 | test.equals(filename, files[0]); 40 | server.close(); 41 | test.end(); 42 | } 43 | 44 | heapdump.writeSnapshot(waitForHeapdump); 45 | }); 46 | server.listen(0); 47 | } 48 | 49 | test('Test writeSnapshot and callback', testFuncCall); 50 | -------------------------------------------------------------------------------- /test/test-callback.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014, Krishna Raman 2 | // 3 | // Permission to use, copy, modify, and/or distribute this software for any 4 | // purpose with or without fee is hereby granted, provided that the above 5 | // copyright notice and this permission notice appear in all copies. 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | var path = require('path'); 16 | var http = require('http'); 17 | var shelljs = require('shelljs'); 18 | var test = require('tap').test; 19 | var heapdump = require('../'); 20 | 21 | process.chdir(__dirname); 22 | 23 | function testFuncCall(test){ 24 | var server = http.createServer(function(req, res) { 25 | res.writeHeader(200); 26 | res.end(); 27 | }); 28 | server.on('listening', function(){ 29 | console.log('Listening on http://127.0.0.1:8000/'); 30 | console.log('PID %d', process.pid); 31 | 32 | var heapSnapshotFile = 'heapdump-' + Date.now() + '.heapsnapshot'; 33 | shelljs.rm('-f', heapSnapshotFile); 34 | 35 | function waitForHeapdump(err, filename) { 36 | var files = shelljs.ls(heapSnapshotFile); 37 | test.equals(err, null); 38 | test.equals(files.length, 1); 39 | test.equals(filename, files[0]); 40 | server.close(); 41 | test.end(); 42 | } 43 | 44 | heapdump.writeSnapshot(heapSnapshotFile, waitForHeapdump); 45 | }); 46 | server.listen(0); 47 | } 48 | 49 | test('Test writeSnapshot and callback', testFuncCall); 50 | -------------------------------------------------------------------------------- /test/test-sigusr2.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012, Ben Noordhuis 2 | // 3 | // Permission to use, copy, modify, and/or distribute this software for any 4 | // purpose with or without fee is hereby granted, provided that the above 5 | // copyright notice and this permission notice appear in all copies. 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | var path = require('path'); 16 | var http = require('http'); 17 | var shelljs = require('shelljs'); 18 | var test = require('tap').test; 19 | var heapdump = require('../'); 20 | 21 | process.chdir(__dirname); 22 | 23 | function testSigUsr2(test){ 24 | var server = http.createServer(function(req, res) { 25 | res.writeHeader(200, {'Content-Type':'text/plain;charset=utf-8', 26 | 'Content-Length':'2'}); 27 | res.end('OK'); 28 | }); 29 | 30 | server.on('listening', function(){ 31 | console.log('Listening on http://127.0.0.1:8000/'); 32 | console.log('now sending SIGUSR2 to %d', process.pid); 33 | 34 | var heapSnapshotFile = 'heapdump-*.heapsnapshot'; 35 | shelljs.rm('-f', heapSnapshotFile); 36 | 37 | var killCmd = shelljs.which('kill'); 38 | var cmd = [killCmd, '-usr2', process.pid].join(' '); 39 | shelljs.exec(cmd); 40 | 41 | function waitForHeapdump(){ 42 | var files = shelljs.ls(heapSnapshotFile); 43 | test.equals(files.length, 1, 'Heap file should be present'); 44 | server.close(); 45 | test.end(); 46 | } 47 | 48 | setTimeout(waitForHeapdump, 500); 49 | }); 50 | 51 | server.listen(0); 52 | } 53 | 54 | test('test heapdump on SIGUSR2', testSigUsr2); 55 | --------------------------------------------------------------------------------