@sentry-internal/node-native-stacktrace
Advanced tools
+21
| MIT License | ||
| Copyright (c) 2025 Functional Software, Inc. dba Sentry | ||
| Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
| this software and associated documentation files (the "Software"), to deal in | ||
| the Software without restriction, including without limitation the rights to | ||
| use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | ||
| of the Software, and to permit persons to whom the Software is furnished to do | ||
| so, subject to the following conditions: | ||
| The above copyright notice and this permission notice shall be included in all | ||
| copies or substantial portions of the Software. | ||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| SOFTWARE. |
+17
-3
| { | ||
| "name": "@sentry-internal/node-native-stacktrace", | ||
| "version": "0.1.0", | ||
| "version": "0.1.1", | ||
| "main": "lib/index.js", | ||
| "types": "lib/index.d.ts", | ||
| "repository": "git://github.com/getsentry/sentry-javascript-node-native-stacktrace.git", | ||
| "homepage": "https://github.com/getsentry/sentry-javascript-node-native-stacktrace", | ||
| "author": "Sentry", | ||
| "license": "MIT", | ||
| "description": "A native Node.js module that can capture JavaScript stack traces from main and worker threads, even with blocked event loops.", | ||
| "keywords": [ | ||
| "stacktrace", | ||
| "native", | ||
| "nodejs", | ||
| "worker", | ||
| "sentry" | ||
| ], | ||
| "scripts": { | ||
@@ -26,4 +37,4 @@ "install": "node scripts/check-build.mjs", | ||
| }, | ||
| "volta": { | ||
| "node": "24.1.0" | ||
| "engines": { | ||
| "node": ">=18" | ||
| }, | ||
@@ -55,3 +66,6 @@ "dependencies": { | ||
| "access": "public" | ||
| }, | ||
| "volta": { | ||
| "node": "24.1.0" | ||
| } | ||
| } |
+92
-33
| # `@sentry-internal/node-native-stacktrace` | ||
| Native Node module to capture stack traces from all registered threads. | ||
| A native Node.js module that can capture JavaScript stack traces for registered | ||
| main or worker threads from any other thread, even if event loops are blocked. | ||
| This allows capturing main and worker thread stack traces from another watchdog | ||
| thread, even if the event loops are blocked. | ||
| The module also provides a means to create a watchdog system to track event loop | ||
| blocking via periodic heartbeats. When the time from the last heartbeat crosses | ||
| a threshold, JavaScript stack traces can be captured. The heartbeats can | ||
| optionally include state information which is included with the corresponding | ||
| stack trace. | ||
| In the main or worker threads: | ||
| ## Basic Usage | ||
| ### 1. Register threads you want to monitor | ||
| In your main thread or worker threads: | ||
| ```ts | ||
| const { registerThread } = require("@sentry-internal/node-native-stacktrace"); | ||
| import { registerThread } from "@sentry-internal/node-native-stacktrace"; | ||
| // Register this thread for monitoring | ||
| registerThread(); | ||
| ``` | ||
| Watchdog thread: | ||
| ### 2. Capture stack traces from any thread | ||
| ```ts | ||
| const { | ||
| captureStackTrace, | ||
| } = require("@sentry-internal/node-native-stacktrace"); | ||
| import { captureStackTrace } from "@sentry-internal/node-native-stacktrace"; | ||
| // Capture stack traces from all registered threads | ||
| const stacks = captureStackTrace(); | ||
@@ -27,4 +35,6 @@ console.log(stacks); | ||
| Results in: | ||
| ### Example Output | ||
| Stack traces show where each thread is currently executing: | ||
| ```js | ||
@@ -87,31 +97,37 @@ { | ||
| ## Detecting blocked event loops | ||
| ## Advanced Usage: Automatic blocked event loop Detection | ||
| In the main or worker threads if you call `registerThread()` regularly, times | ||
| are recorded. | ||
| Set up automatic detection of blocked event loops: | ||
| ### 1. Set up thread heartbeats | ||
| Send regular heartbeats with optional state information: | ||
| ```ts | ||
| const { | ||
| import { | ||
| registerThread, | ||
| threadPoll, | ||
| } = require("@sentry-internal/node-native-stacktrace"); | ||
| } from "@sentry-internal/node-native-stacktrace"; | ||
| // Register this thread | ||
| registerThread(); | ||
| // Send heartbeats every 200ms with optional state | ||
| setInterval(() => { | ||
| threadPoll({ optional_state: "some_value" }); | ||
| threadPoll({ | ||
| endpoint: "/api/current-request", | ||
| userId: getCurrentUserId(), | ||
| }); | ||
| }, 200); | ||
| ``` | ||
| In the watchdog thread you can call `getThreadsLastSeen()` to get how long it's | ||
| been in milliseconds since each thread polled. | ||
| ### 2. Monitor from a watchdog thread | ||
| If any thread has exceeded a threshold, you can call `captureStackTrace()` to | ||
| get the stack traces for all threads. | ||
| Monitor all registered threads from a dedicated thread: | ||
| ```ts | ||
| const { | ||
| import { | ||
| captureStackTrace, | ||
| getThreadsLastSeen, | ||
| } = require("@sentry-internal/node-native-stacktrace"); | ||
| } from "@sentry-internal/node-native-stacktrace"; | ||
@@ -121,15 +137,58 @@ const THRESHOLD = 1000; // 1 second | ||
| setInterval(() => { | ||
| for (const [thread, time] in Object.entries(getThreadsLastSeen())) { | ||
| if (time > THRESHOLD) { | ||
| const threads = captureStackTrace(); | ||
| const blockedThread = threads[thread]; | ||
| const { frames, state } = blockedThread; | ||
| console.log( | ||
| `Thread '${thread}' blocked more than ${THRESHOLD}ms`, | ||
| frames, | ||
| state, | ||
| ); | ||
| const threadsLastSeen = getThreadsLastSeen(); | ||
| for (const [threadId, timeSinceLastSeen] of Object.entries(threadsLastSeen)) { | ||
| if (timeSinceLastSeen > THRESHOLD) { | ||
| // Thread appears to be blocked - capture diagnostics | ||
| const stackTraces = captureStackTrace(); | ||
| const blockedThread = stackTraces[threadId]; | ||
| console.error(`🚨 Thread ${threadId} blocked for ${timeSinceLastSeen}ms`); | ||
| console.error("Stack trace:", blockedThread.frames); | ||
| console.error("Last known state:", blockedThread.state); | ||
| } | ||
| } | ||
| }, 1000); | ||
| }, 500); // Check every 500ms | ||
| ``` | ||
| ## API Reference | ||
| ### Functions | ||
| #### `registerThread(threadName?: string): void` | ||
| Registers the current thread for monitoring. Must be called from each thread you | ||
| want to capture stack traces from. | ||
| - `threadName` (optional): Name for the thread. Defaults to the current thread | ||
| ID. | ||
| #### `captureStackTrace<State>(): Record<string, Thread<State>>` | ||
| Captures stack traces from all registered threads. Can be called from any thread | ||
| but will not capture the stack trace of the calling thread itself. | ||
| ```ts | ||
| type Thread<S> = { | ||
| frames: StackFrame[]; | ||
| state?: S; | ||
| }; | ||
| type StackFrame = { | ||
| function: string; | ||
| filename: string; | ||
| lineno: number; | ||
| colno: number; | ||
| }; | ||
| ``` | ||
| #### `threadPoll<State>(state?: State): void` | ||
| Sends a heartbeat from the current thread with optional state information. The | ||
| state object will be serialized and included as a JavaScript object with the | ||
| corresponding stack trace. | ||
| #### `getThreadsLastSeen(): Record<string, number>` | ||
| Returns the time in milliseconds since each registered thread called | ||
| `threadPoll()`. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
No contributors or author data
MaintenancePackage does not specify a list of contributors or an author in package.json.
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
No website
QualityPackage does not have a website.
2468231
0.14%40
2.56%1
-50%1
-50%192
44.36%