-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 39e060e
Showing
9 changed files
with
3,598 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
{ | ||
"root": true, | ||
"extends": [ | ||
"neon/common", | ||
"neon/node", | ||
"neon/typescript" | ||
], | ||
"parserOptions": { | ||
"project": "./tsconfig.json" | ||
}, | ||
"ignorePatterns": [ | ||
"**/dist/*" | ||
], | ||
"rules": { | ||
"@typescript-eslint/indent": [ | ||
"error", | ||
4 | ||
] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
* text=auto eol=lf |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# Packages | ||
node_modules/ | ||
|
||
# Log files | ||
logs/ | ||
*.log | ||
npm-debug.log* | ||
|
||
# Runtime data | ||
pids | ||
*.pid | ||
*.seed | ||
|
||
# Env | ||
.env | ||
|
||
# Dist | ||
dist/ | ||
|
||
# Miscellaneous | ||
.tmp/ | ||
.vscode/* | ||
!.vscode/extensions.json | ||
!.vscode/settings.json | ||
.idea/ | ||
.DS_Store | ||
.turbo | ||
tsconfig.tsbuildinfo | ||
coverage/ | ||
|
||
# yarn | ||
.pnp.* | ||
.yarn/* | ||
!.yarn/patches | ||
!.yarn/plugins | ||
!.yarn/releases | ||
!.yarn/sdks | ||
!.yarn/versions | ||
|
||
# Cache | ||
.prettiercache | ||
.eslintcache |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# Asynchronous Operations Debugger | ||
|
||
<div align="center"> | ||
<br /> | ||
<p> | ||
<a href="https://www.npmjs.com/package/async-debug"><img src="https://img.shields.io/npm/v/async-debug.svg?maxAge=3600" alt="npm version" /></a> | ||
<a href="https://www.npmjs.com/package/async-debug"><img src="https://img.shields.io/npm/dt/async-debug.svg?maxAge=3600" alt="npm downloads" /></a> | ||
</p> | ||
</div> | ||
|
||
## About | ||
|
||
``async-debug`` is a Node.js module that debugs your asynchronous operations, inspired by [asyncio debug mode](https://docs.python.org/3/library/asyncio-dev.html#debug-mode) of python. | ||
|
||
Currently, the only feature of this module is to listen for your asynchronous operations and log them to the console if they take too long to complete (considered "slow"). | ||
|
||
## Installation | ||
|
||
```sh-session | ||
npm install async-debug | ||
yarn add async-debug | ||
pnpm add async-debug | ||
``` | ||
|
||
## Usage | ||
|
||
```js | ||
import { configure } from "async-debug"; | ||
|
||
const asyncDebugger = configure({ | ||
longTaskThreshold: 250, // 0.25 seconds, default is 300 (0.3 seconds) | ||
}) | ||
|
||
if (process.env.NODE_ENV === 'development') { | ||
asyncDebugger.enable(); | ||
} | ||
|
||
// Your code here | ||
|
||
// Output: | ||
// Executing asynchronous operation 15 using HTTPCLIENTREQUEST took 313.654224999249ms to complete. | ||
``` | ||
|
||
And that's it! You can now debug your asynchronous operations. | ||
|
||
If you want to setup different thresholds for different operations, you can pass `object` to the ``longTaskThreshold`` parameter like below. | ||
|
||
```js | ||
configure({ | ||
longTaskThreshold: { | ||
HTTPCLIENTREQUEST: 300, | ||
TCPCONNECTWRAP: 100, | ||
FSREQCALLBACK: 150, | ||
// ... | ||
} | ||
}) | ||
``` | ||
|
||
### Configuration | ||
|
||
All options are described as JSDoc comments, but if I think it's necessary, I'll add them here later. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
{ | ||
"name": "async-debug", | ||
"version": "1.0.0", | ||
"description": "Asynchronous operation debugger built on top of async_hooks.", | ||
"scripts": { | ||
"build": "tsup", | ||
"lint": "eslint src", | ||
"fmt": "eslint src --fix", | ||
"prepack": "yarn lint && yarn build" | ||
}, | ||
"author": "zero734kr <zero734kr@gmail.com>", | ||
"license": "Apache-2.0", | ||
"private": false, | ||
"main": "./dist/index.js", | ||
"module": "./dist/index.mjs", | ||
"typings": "./dist/index.d.ts", | ||
"exports": { | ||
"import": "./dist/index.mjs", | ||
"require": "./dist/index.js", | ||
"types": "./dist/index.d.ts" | ||
}, | ||
"files": [ | ||
"dist" | ||
], | ||
"keywords": [ | ||
"async", | ||
"debug", | ||
"async_hooks", | ||
"performance", | ||
"tracing" | ||
], | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/zero734kr/async-debug.git" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/zero734kr/async-debug/issues" | ||
}, | ||
"devDependencies": { | ||
"@swc/core": "^1.3.10", | ||
"@types/node": "^18.11.3", | ||
"eslint": "^8.26.0", | ||
"eslint-config-neon": "^0.1.39", | ||
"tsup": "^6.3.0", | ||
"typescript": "^4.8.4" | ||
}, | ||
"engines": { | ||
"node": ">=8.5.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import type { AsyncHook } from "node:async_hooks"; | ||
import { createHook } from "node:async_hooks"; | ||
import { writeSync } from "node:fs"; | ||
import { performance } from "node:perf_hooks"; | ||
import process from "node:process"; | ||
|
||
/** | ||
* Options to configure the async hook. | ||
*/ | ||
export type DebugOptions = { | ||
/** | ||
* The threshold to determine if an asynchronous task is taking too long in milliseconds. | ||
* If an object is passed as a parameter, each key of object is the type of the asynchronous | ||
* resource and the value will be used for each of them, | ||
* and if no corresponding key is found, the default below will be used. | ||
* If threshold is not specified, the default value is 300ms. | ||
* If a number is passed as a parameter, it will be used for all async resources. | ||
*/ | ||
longTaskThreshold?: Record<string, number> | number; | ||
}; | ||
|
||
export enum DebugEventType { | ||
LISTENING = "LISTENING", | ||
} | ||
|
||
export type DebugEvent = { | ||
asyncId: number; | ||
resourceType: string; | ||
startTime?: number; | ||
type: DebugEventType; | ||
}; | ||
|
||
/** | ||
* Storing information about the asynchronous execution context. | ||
*/ | ||
export const asyncTaskContextStore = new Map(); | ||
|
||
/** | ||
* According to node.js async_hooks documentation, | ||
* printing to the console is an asynchronous operation. | ||
* So `console.log` will cause an infinite loop as the hook callbacks are called recursively. | ||
* we need to print to the console synchronously. | ||
* | ||
* @see https://nodejs.org/api/async_hooks.html#printing-in-asynchook-callbacks | ||
*/ | ||
function debugLogSync(...args: any[]) { | ||
if (process.env.AD_DEBUGGING !== "1") { | ||
return; | ||
} | ||
|
||
return writeSync(process.stdout.fd, `${args.join(" ")}\n`); | ||
} | ||
|
||
/** | ||
* Creates an async hook to debug asynchronous tasks. | ||
*/ | ||
export function configure({ longTaskThreshold = 300 }: DebugOptions = {}): AsyncHook { | ||
// I haven't used before/after hook because it not worked correctly. | ||
|
||
return createHook({ | ||
init(asyncId, type, eid) { | ||
debugLogSync(`INIT: ${asyncId}(${type}) - ${eid}`); | ||
|
||
if (asyncTaskContextStore.has(asyncId)) { | ||
return; | ||
} | ||
|
||
asyncTaskContextStore.set(asyncId, { | ||
asyncId, | ||
type: DebugEventType.LISTENING, | ||
startTime: performance.now(), | ||
resourceType: type, | ||
}); | ||
}, | ||
destroy(asyncId) { | ||
const event = asyncTaskContextStore.get(asyncId); | ||
|
||
if (event && event.type === DebugEventType.LISTENING) { | ||
const duration = performance.now() - event.startTime!; | ||
|
||
debugLogSync(`DESTROY: ${asyncId} - ${duration}ms`); | ||
|
||
const threshold = typeof longTaskThreshold === "number" ? | ||
longTaskThreshold : | ||
longTaskThreshold[event.resourceType] ?? 300; | ||
|
||
if (duration > threshold) { | ||
console.log(`Executing asynchronous task ${asyncId} using ${event.resourceType} took ${duration}ms to complete.`); | ||
} | ||
} | ||
|
||
asyncTaskContextStore.delete(asyncId); | ||
}, | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
{ | ||
// Mapped from https://www.typescriptlang.org/tsconfig | ||
"compilerOptions": { | ||
// Type Checking | ||
"allowUnreachableCode": false, | ||
"allowUnusedLabels": false, | ||
"exactOptionalPropertyTypes": true, | ||
"noFallthroughCasesInSwitch": true, | ||
"noImplicitOverride": true, | ||
"noImplicitReturns": true, | ||
"noUnusedLocals": true, | ||
"noUnusedParameters": true, | ||
"strict": true, | ||
"useUnknownInCatchVariables": true, | ||
"noUncheckedIndexedAccess": true, | ||
// Modules | ||
"module": "ESNext", | ||
"moduleResolution": "node", | ||
"resolveJsonModule": true, | ||
// Emit | ||
"declaration": true, | ||
"declarationMap": true, | ||
"importHelpers": true, | ||
"importsNotUsedAsValues": "error", | ||
"inlineSources": true, | ||
"newLine": "lf", | ||
"noEmitHelpers": true, | ||
"outDir": "dist", | ||
"preserveConstEnums": true, | ||
"removeComments": false, | ||
"sourceMap": true, | ||
"esModuleInterop": true, | ||
"forceConsistentCasingInFileNames": true, | ||
// Language and Environment | ||
"emitDecoratorMetadata": true, | ||
"experimentalDecorators": true, | ||
"lib": [ | ||
"ESNext" | ||
], | ||
"target": "ES2021", | ||
"useDefineForClassFields": true | ||
}, | ||
"include": [ | ||
"src/**/*.ts", | ||
"**/*.config.js" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { defineConfig } from "tsup"; | ||
|
||
export default defineConfig({ | ||
entry: ["src/index.ts"], | ||
platform: "node", | ||
format: ["esm", "cjs"], | ||
target: "es2020", | ||
clean: true, | ||
dts: true, | ||
keepNames: true, | ||
shims: true, | ||
skipNodeModulesBundle: true, | ||
}); |
Oops, something went wrong.