diff --git a/package-lock.json b/package-lock.json index 6c3e673..d2e7eac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,20 +8,12 @@ "name": "@matrixai/logger", "version": "4.0.4-alpha.1", "license": "Apache-2.0", - "dependencies": { - "fast-check": "^4.1.1", - "ink": "^3.2.0", - "react": "^17.0.2", - "react-dom": "^17.0.2" - }, "devDependencies": { + "@matrixai/id": "^4.0.0", "@swc/core": "1.3.82", "@swc/jest": "^0.2.29", - "@types/ink": "^0.5.2", "@types/jest": "^29.5.14", "@types/node": "^20.5.7", - "@types/react": "^19.0.12", - "@types/react-dom": "^19.0.4", "@typescript-eslint/eslint-plugin": "^5.61.0", "@typescript-eslint/parser": "^5.61.0", "benny": "^3.7.1", @@ -30,6 +22,7 @@ "eslint-config-prettier": "^8.8.0", "eslint-plugin-import": "^2.27.5", "eslint-plugin-prettier": "^5.0.0-alpha.2", + "fast-check": "^4.1.1", "jest": "^29.7.0", "jest-extended": "^4.0.0", "jest-junit": "^16.0.0", @@ -1605,6 +1598,17 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@matrixai/id": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@matrixai/id/-/id-4.0.0.tgz", + "integrity": "sha512-xLwYlK4d75wnpfIF+A0XRS5VmX/aDj/4E/XFkwrYsSDxoiWj7DoRRVSs/ryorwZHgufs/kL8aS1eTKadUQRevg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "multiformats": "^13.3.2", + "uuid": "^8.3.2" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1960,17 +1964,6 @@ "@types/node": "*" } }, - "node_modules/@types/ink": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@types/ink/-/ink-0.5.2.tgz", - "integrity": "sha512-yEuhWTRMXJkIWiaM58c5kuRot5HFccv9kjjgy0fBZG0+tYb+sMBaxHNPVqyZXspGGlmwDOQ1d3BsygWpWlW17w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/prop-types": "*" - } - }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", @@ -2027,33 +2020,6 @@ "undici-types": "~5.26.4" } }, - "node_modules/@types/prop-types": { - "version": "15.7.14", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", - "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/react": { - "version": "19.0.12", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.12.tgz", - "integrity": "sha512-V6Ar115dBDrjbtXSrS+/Oruobc+qVbbUxDFC1RSbRqLt5SYvxxyIDrSC85RWml54g+jfNeEMZhEj7wW07ONQhA==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "19.0.4", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.4.tgz", - "integrity": "sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^19.0.0" - } - }, "node_modules/@types/semver": { "version": "7.5.0", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", @@ -2083,12 +2049,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/yoga-layout": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@types/yoga-layout/-/yoga-layout-1.9.2.tgz", - "integrity": "sha512-S9q47ByT2pPvD65IvrWp7qppVMpk9WGMbVq9wbWZOHg6tnXSD4vyhao6nOSBwwfDdV2p3Kx9evA9vI+XWTfDvw==", - "license": "MIT" - }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "5.62.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", @@ -2319,6 +2279,7 @@ "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, "dependencies": { "type-fest": "^0.21.3" }, @@ -2333,6 +2294,7 @@ "version": "0.21.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, "engines": { "node": ">=10" }, @@ -2344,6 +2306,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, "engines": { "node": ">=8" } @@ -2358,6 +2321,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -2508,6 +2472,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, "engines": { "node": ">=8" } @@ -2519,18 +2484,6 @@ "dev": true, "license": "MIT" }, - "node_modules/auto-bind": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/auto-bind/-/auto-bind-4.0.0.tgz", - "integrity": "sha512-Hdw8qdNiqdJ8LqT0iK0sVzkFbzg6fhnQqqfWhBDxcHZvU75+B+ayzTy8x+k5Ix0Y92XOhOUlx74ps+bA6BeYMQ==", - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/available-typed-arrays": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", @@ -2882,6 +2835,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2925,22 +2879,11 @@ "dev": true, "license": "MIT" }, - "node_modules/cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, "dependencies": { "restore-cursor": "^3.1.0" }, @@ -2948,36 +2891,6 @@ "node": ">=8" } }, - "node_modules/cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", - "license": "MIT", - "dependencies": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate/node_modules/slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -3022,18 +2935,6 @@ "node": ">= 0.12.0" } }, - "node_modules/code-excerpt": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/code-excerpt/-/code-excerpt-3.0.0.tgz", - "integrity": "sha512-VHNTVhd7KsLGOqfX3SyeO8RyYPMp1GJOg194VITk04WMYCv4plV68YWe6TJZxd9MhobjtpMRnVky01gqZsalaw==", - "license": "MIT", - "dependencies": { - "convert-to-spaces": "^1.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/collect-v8-coverage": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", @@ -3045,6 +2946,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -3055,7 +2957,8 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, "node_modules/commander": { "version": "6.2.1", @@ -3088,15 +2991,6 @@ "dev": true, "license": "MIT" }, - "node_modules/convert-to-spaces": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/convert-to-spaces/-/convert-to-spaces-1.0.2.tgz", - "integrity": "sha512-cj09EBuObp9gZNQCzc7hByQyrs6jVGE+o9kSJmeUoj+GiPiJvi5LYqEH/Hmme4+MTLHM+Ejtq+FChpjjEnsPdQ==", - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, "node_modules/create-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", @@ -3133,13 +3027,6 @@ "node": ">= 8" } }, - "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "devOptional": true, - "license": "MIT" - }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -3443,7 +3330,8 @@ "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true }, "node_modules/error-ex": { "version": "1.3.2", @@ -4004,6 +3892,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-4.1.1.tgz", "integrity": "sha512-8+yQYeNYqBfWem0Nmm7BUnh27wm+qwGvI0xln60c8RPM5rVekxZf/Ildng2GNBfjaG6utIebFmVBPlNtZlBLxg==", + "dev": true, "funding": [ { "type": "individual", @@ -4026,6 +3915,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", + "dev": true, "funding": [ { "type": "individual", @@ -4493,6 +4383,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, "engines": { "node": ">=8" } @@ -4618,15 +4509,6 @@ "node": ">=0.8.19" } }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -4643,92 +4525,6 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "node_modules/ink": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ink/-/ink-3.2.0.tgz", - "integrity": "sha512-firNp1q3xxTzoItj/eOOSZQnYSlyrWks5llCTVX37nJ59K3eXbQ8PtzCguqo8YI19EELo5QxaKnJd4VxzhU8tg==", - "license": "MIT", - "dependencies": { - "ansi-escapes": "^4.2.1", - "auto-bind": "4.0.0", - "chalk": "^4.1.0", - "cli-boxes": "^2.2.0", - "cli-cursor": "^3.1.0", - "cli-truncate": "^2.1.0", - "code-excerpt": "^3.0.0", - "indent-string": "^4.0.0", - "is-ci": "^2.0.0", - "lodash": "^4.17.20", - "patch-console": "^1.0.0", - "react-devtools-core": "^4.19.1", - "react-reconciler": "^0.26.2", - "scheduler": "^0.20.2", - "signal-exit": "^3.0.2", - "slice-ansi": "^3.0.0", - "stack-utils": "^2.0.2", - "string-width": "^4.2.2", - "type-fest": "^0.12.0", - "widest-line": "^3.1.0", - "wrap-ansi": "^6.2.0", - "ws": "^7.5.5", - "yoga-layout-prebuilt": "^1.9.6" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": ">=16.8.0", - "react": ">=16.8.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/ink/node_modules/react-reconciler": { - "version": "0.26.2", - "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.26.2.tgz", - "integrity": "sha512-nK6kgY28HwrMNwDnMui3dvm3rCFjZrcGiuwLc5COUipBK5hWHLOxMJhSnSomirqWwjPBJKV1QcbkI0VJr7Gl1Q==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" - }, - "engines": { - "node": ">=0.10.0" - }, - "peerDependencies": { - "react": "^17.0.2" - } - }, - "node_modules/ink/node_modules/slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ink/node_modules/type-fest": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.12.0.tgz", - "integrity": "sha512-53RyidyjvkGpnWPMF9bQgFtWp+Sl8O2Rp13VavmJgfAP9WWG6q6TkrKU8iyJdnwnfgHI6k2hTlgqH4aSdjoTbg==", - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/internal-slot": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", @@ -4813,24 +4609,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "license": "MIT", - "dependencies": { - "ci-info": "^2.0.0" - }, - "bin": { - "is-ci": "bin.js" - } - }, - "node_modules/is-ci/node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "license": "MIT" - }, "node_modules/is-core-module": { "version": "2.13.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", @@ -4886,6 +4664,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, "engines": { "node": ">=8" } @@ -5823,7 +5602,8 @@ "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true }, "node_modules/js-yaml": { "version": "4.1.0", @@ -5985,7 +5765,8 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true }, "node_modules/lodash.get": { "version": "4.4.2", @@ -6024,18 +5805,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -6129,6 +5898,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, "engines": { "node": ">=6" } @@ -6172,6 +5942,13 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/multiformats": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-13.3.2.tgz", + "integrity": "sha512-qbB0CQDt3QKfiAzZ5ZYjLFOs+zW43vA4uyM8g27PeEuXZybUOFyjrVdP93HPBHMoglibwfkdVwbzfUq8qGcH6g==", + "dev": true, + "license": "Apache-2.0 OR MIT" + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -6220,15 +5997,6 @@ "node": ">=8" } }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object-inspect": { "version": "1.12.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", @@ -6324,6 +6092,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, "dependencies": { "mimic-fn": "^2.1.0" }, @@ -6440,15 +6209,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/patch-console": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/patch-console/-/patch-console-1.0.0.tgz", - "integrity": "sha512-nxl9nrnLQmh64iTzMfyylSlRozL7kAXIaxw1fVcLYdyhNkJCRUzirRZTikXGJsg+hc4fqpneTK6iU2H1Q8THSA==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -6728,43 +6488,6 @@ } ] }, - "node_modules/react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-devtools-core": { - "version": "4.28.5", - "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-4.28.5.tgz", - "integrity": "sha512-cq/o30z9W2Wb4rzBefjv5fBalHU0rJGZCHAkf/RHSBWSSYwh8PlQTqqOJmgIIbBtpj27T6FIPXeomIjZtCNVqA==", - "license": "MIT", - "dependencies": { - "shell-quote": "^1.6.1", - "ws": "^7" - } - }, - "node_modules/react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" - }, - "peerDependencies": { - "react": "17.0.2" - } - }, "node_modules/react-is": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", @@ -6882,6 +6605,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" @@ -6985,16 +6709,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, "node_modules/semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -7049,18 +6763,6 @@ "node": ">=8" } }, - "node_modules/shell-quote": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", - "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/shelljs": { "version": "0.8.5", "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", @@ -7123,7 +6825,8 @@ "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true }, "node_modules/sisteransi": { "version": "1.0.5", @@ -7189,6 +6892,7 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, "dependencies": { "escape-string-regexp": "^2.0.0" }, @@ -7200,6 +6904,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, "engines": { "node": ">=8" } @@ -7222,6 +6927,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -7280,6 +6986,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -7322,6 +7029,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -7920,22 +7628,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", - "license": "MIT", - "dependencies": { - "string-width": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -7965,27 +7662,6 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/ws": { - "version": "7.5.10", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", - "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", - "license": "MIT", - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/xml": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", @@ -8049,18 +7725,6 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } - }, - "node_modules/yoga-layout-prebuilt": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/yoga-layout-prebuilt/-/yoga-layout-prebuilt-1.10.0.tgz", - "integrity": "sha512-YnOmtSbv4MTf7RGJMK0FvZ+KD8OEe/J5BNnR0GHhD8J/XcG/Qvxgszm0Un6FTHWW4uHlTgP0IztiXQnGyIR45g==", - "license": "MIT", - "dependencies": { - "@types/yoga-layout": "1.9.2" - }, - "engines": { - "node": ">=8" - } } } } diff --git a/package.json b/package.json index ebf193f..2b2084c 100644 --- a/package.json +++ b/package.json @@ -37,13 +37,11 @@ "bench": "tsc -p ./tsconfig.build.json && shx rm -rf ./benches/results && tsx ./benches/index.ts" }, "devDependencies": { + "@matrixai/id": "^4.0.0", "@swc/core": "1.3.82", "@swc/jest": "^0.2.29", - "@types/ink": "^0.5.2", "@types/jest": "^29.5.14", "@types/node": "^20.5.7", - "@types/react": "^19.0.12", - "@types/react-dom": "^19.0.4", "@typescript-eslint/eslint-plugin": "^5.61.0", "@typescript-eslint/parser": "^5.61.0", "benny": "^3.7.1", @@ -52,6 +50,7 @@ "eslint-config-prettier": "^8.8.0", "eslint-plugin-import": "^2.27.5", "eslint-plugin-prettier": "^5.0.0-alpha.2", + "fast-check": "^4.1.1", "jest": "^29.7.0", "jest-extended": "^4.0.0", "jest-junit": "^16.0.0", @@ -62,11 +61,5 @@ "tsx": "^3.12.7", "typedoc": "^0.24.8", "typescript": "^5.1.6" - }, - "dependencies": { - "fast-check": "^4.1.1", - "ink": "^3.2.0", - "react": "^17.0.2", - "react-dom": "^17.0.2" } } diff --git a/src/bin/SpanTree.tsx b/src/bin/SpanTree.tsx deleted file mode 100644 index 1612fa6..0000000 --- a/src/bin/SpanTree.tsx +++ /dev/null @@ -1,113 +0,0 @@ -import type { FC } from 'react'; -import { Box, Text } from 'ink'; -import Span from '../lib/Span.js'; - -// Props for handling both root and child spans -interface SpanTreeProps { - spans: Array; - mode: 'logical' | 'time'; -} - -/** - * Sort spans based on the selected sampling mode. - */ -const sortSpans = (spans: Span[], mode: string): Span[] => { - if (mode === 'logical') { - const spanMap = new Map(); - - // Step 1: Convert raw objects to Span instances - spans.forEach((span) => { - if (!spanMap.has(span.spanId)) { - const newSpan = new Span(span.name, span.parentSpanId); - Object.assign(newSpan, span); - newSpan.children = []; - spanMap.set(span.spanId, newSpan); - } - }); - - const rootSpans: Array = []; - - // Step 2: Link children to parents - spans.forEach((span) => { - if (span.parentSpanId && spanMap.has(span.parentSpanId)) { - spanMap - .get(span.parentSpanId)! - .children.push(spanMap.get(span.spanId)!); - } - }); - - // Step 3: Collect only true root spans (avoiding duplicates) - spans.forEach((span) => { - if (!span.parentSpanId) { - const rootSpan = spanMap.get(span.spanId); - if (rootSpan) { - rootSpans.push(rootSpan); - } - } - }); - - return rootSpans; - } else { - return spans - .map((span) => new Span(span.name, span.parentSpanId)) - .sort((a, b) => a.startTime - b.startTime); - } -}; - -/** - * **Recursive Renderer** - * - Uses box-drawing characters (│ ├ └) for structured layout. - */ -const RecursiveSpanTree: FC<{ - span: Span; - prefix: string; - isLastChild: boolean; -}> = ({ span, prefix, isLastChild }) => { - const connector = isLastChild ? '└── ' : '├── '; - const newPrefix = prefix + (isLastChild ? ' ' : '│ '); - - return ( - - - {prefix} - {connector} - {span.name} - - - {span.children.map((child, idx) => ( - - ))} - - ); -}; - -/** - * **Main Component** (Sorts & Passes Data) - */ -const SpanTree: FC = ({ spans, mode }) => { - const sortedSpans = sortSpans(spans, mode); - - return ( - - {sortedSpans.length === 0 ? ( - No spans to display - ) : ( - sortedSpans.map((span, idx) => ( - - )) - )} - - ); -}; - -export default SpanTree; diff --git a/src/bin/TimeLineView.tsx b/src/bin/TimeLineView.tsx deleted file mode 100644 index cd35d5c..0000000 --- a/src/bin/TimeLineView.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import type { FC } from 'react'; -import { Box, Text } from 'ink'; - -interface Span { - spanId: string; - name: string; - parentSpanId: string | undefined; - startTime: number; - endTime: number | undefined; -} - -// We make each row = 1000 ms -const TIME_STEP_MS = 1000; - -function timeToRow(timeMs: number, baseTimeMs: number) { - return Math.floor((timeMs - baseTimeMs) / TIME_STEP_MS); -} - -function assignLanes(spans: Array): Map { - // Sort spans by startTime ascending - const sorted = [...spans].sort((a, b) => a.startTime - b.startTime); - const laneMap = new Map(); - const laneEndTime: number[] = []; - - for (const span of sorted) { - let assignedLane = -1; - for (let i = 0; i < laneEndTime.length; i++) { - if (laneEndTime[i] <= span.startTime) { - assignedLane = i; - break; - } - } - if (assignedLane < 0) { - assignedLane = laneEndTime.length; - laneEndTime.push(0); - } - laneMap.set(span.spanId, assignedLane); - - const realEnd = span.endTime ?? span.startTime + 3000; - laneEndTime[assignedLane] = Math.max(laneEndTime[assignedLane], realEnd); - } - return laneMap; -} - -const TimelineView: FC<{ spans: Span[] }> = ({ spans }) => { - if (!spans.length) { - return No spans; - } - - const laneMap = assignLanes(spans); - const earliest = - Math.floor(Math.min(...spans.map((s) => s.startTime)) / TIME_STEP_MS) * - TIME_STEP_MS; - - const latest = Math.max(...spans.map((s) => s.endTime ?? s.startTime + 3000)); - const maxLane = Math.max(...laneMap.values()); - const rowCount = 1 + timeToRow(latest, earliest); - - // Initialize a 2D grid: rowCount rows x (maxLane+1) lanes - const grid: Array> = Array.from({ length: rowCount }, () => - Array(maxLane + 1).fill(' '), - ); - - // Fill each lane with vertical bars and optional slash - for (const span of spans) { - const lane = laneMap.get(span.spanId)!; - const startRow = timeToRow(span.startTime, earliest); - const endRow = timeToRow(span.endTime ?? span.startTime + 3000, earliest); - - // Vertical bars - for (let r = startRow; r <= endRow; r++) { - grid[r][lane] = ' | '; - } - - // Insert the span name at the start row - grid[startRow][lane] = grid[startRow][lane].replace( - ' | ', - ` | (${span.name})`, - ); - - // If parent ended earlier, place a slash - if (span.parentSpanId) { - const parent = spans.find((s) => s.spanId === span.parentSpanId); - if (parent) { - const parentLane = laneMap.get(parent.spanId)!; - const parentEnd = timeToRow( - parent.endTime ?? parent.startTime, - earliest, - ); - - if (parentLane !== lane || parentEnd < endRow) { - if (parentLane < lane) { - grid[parentEnd][parentLane] = ' \\'; - } else if (parentLane > lane) { - grid[parentEnd][parentLane] = ' / '; - } - } - } - } - } - - const lines = grid.map((cols) => cols.join('')); - - return ( - - {lines.map((line, idx) => ( - - {line} - - ))} - - ); -}; - -export default TimelineView; diff --git a/src/bin/cli.tsx b/src/bin/cli.tsx deleted file mode 100644 index 507dfe4..0000000 --- a/src/bin/cli.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import type Span from '../lib/Span.js'; -import fs from 'fs'; -import { Command } from 'commander'; -import { useEffect, useState } from 'react'; -import { render, Box, Text } from 'ink'; -import SpanTree from './SpanTree.js'; - -// Use commander to parse CLI options -const program = new Command(); -program - .option('--sample ', 'Sampling mode: logical or time', 'time') - .parse(); - -const options = program.opts(); -const sampleMode = options.sample; - -async function loadSpans(): Promise> { - const spans: Array = []; - const file = await fs.promises.open('span.jsonl', 'r'); - for await (const line of file.readLines()) { - spans.push(JSON.parse(line)); - } - await file.close(); - return spans; -} - -const App = () => { - const [spans, setSpans] = useState>([]); - - useEffect(() => { - const id = setInterval(() => { - (async () => { - const result = await loadSpans(); - setSpans(result); - })(); - }, 1000); - - const handleExit = () => { - process.stdout.write('Stopping CLI...\n'); - clearInterval(id); - process.exit(0); - }; - - process.on('SIGINT', handleExit); - process.on('SIGTERM', handleExit); - process.on('SIGHUP', handleExit); - process.on('SIGABRT', handleExit); - - return () => clearInterval(id); - }, []); - - return ( - - - Real-Time Concurrency Timeline ({sampleMode}-based) - - - {spans.length > 0 ? ( - - ) : ( - No spans available - )} - - ); -}; - -render(); diff --git a/src/index.ts b/src/index.ts index 1f74c06..a81d094 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,8 +1,7 @@ export { default } from './Logger.js'; export { default as Handler } from './Handler.js'; -export { openSpan, closeSpan, getTraceJSON } from './lib/TracingManager.js'; -export { default as Span } from './lib/Span.js'; export * as formatting from './formatting.js'; export * from './handlers/index.js'; +export * from './tracer/index.js'; export * from './utils.js'; export * from './types.js'; diff --git a/src/lib/Span.ts b/src/lib/Span.ts deleted file mode 100644 index 24c26d7..0000000 --- a/src/lib/Span.ts +++ /dev/null @@ -1,39 +0,0 @@ -import type { SpanJSON } from './types.js'; - -class Span { - public spanId: string = `span-${Date.now()}-${Math.random() - .toString(36) - .substring(2, 5)}`; - public name: string; - public startTime: number = Date.now(); - public endTime?: number; - public parentSpanId?: string; - public children: Array = []; - - constructor(name: string, parentSpanId?: string) { - this.name = name; - this.parentSpanId = parentSpanId; - } - - public close(): void { - this.endTime = Date.now(); - } - - public isCompleted(): boolean { - return this.endTime != null; - } - - public toJSON(): SpanJSON { - return { - spanId: this.spanId, - name: this.name, - startTime: this.startTime, - endTime: this.endTime, - parentSpanId: this.parentSpanId, - isCompleted: this.isCompleted(), - children: this.children.map((child) => child.toJSON()), - }; - } -} - -export default Span; diff --git a/src/lib/Tracer.ts b/src/lib/Tracer.ts deleted file mode 100644 index e4679a1..0000000 --- a/src/lib/Tracer.ts +++ /dev/null @@ -1,74 +0,0 @@ -import type { SpanEvent } from './types.js'; -import Span from './Span.js'; - -class Tracer { - protected activeSpans: Map = new Map(); - protected queue: Array = []; - protected resolveWaitChunksP: (() => void) | undefined; - protected ended: boolean = false; - - protected queueSpanEvent(span: SpanEvent) { - this.queue.push(span); - if (this.resolveWaitChunksP != null) this.resolveWaitChunksP(); - } - - public startSpan(name: string, parentSpanId?: string): string { - const span = new Span(name, parentSpanId); - this.activeSpans.set(span.spanId, span); - if (parentSpanId && this.activeSpans.has(parentSpanId)) { - this.activeSpans.get(parentSpanId)!.children.push(span); - } - this.queueSpanEvent({ type: 'start', span: span.toJSON() }); - return span.spanId; - } - - public endSpan(spanId: string): Span | undefined { - const span = this.activeSpans.get(spanId); - if (!span) return; - - span.close(); - this.queueSpanEvent({ type: 'stop', span: span.toJSON() }); - return span; - } - - public async traced( - name: string, - fn: () => Promise, - parentSpanId?: string, - ): Promise { - const spanId = this.startSpan(name, parentSpanId); - return await fn().finally(() => this.endSpan(spanId)); - } - - public getActiveSpans(): Array { - return Array.from(this.activeSpans.values()); - } - - public getTraceJSON(): string { - return JSON.stringify( - this.getActiveSpans().map((s) => s.toJSON()), - null, - 2, - ); - } - - public endTracing(): void { - this.ended = true; - } - - public async *streamEvents(): AsyncGenerator { - while (true) { - const value = this.queue.shift(); - if (value == null) { - if (this.ended) break; - await new Promise((resolve) => { - this.resolveWaitChunksP = resolve; - }); - continue; - } - yield value; - } - } -} - -export default Tracer; diff --git a/src/lib/TracingManager.ts b/src/lib/TracingManager.ts deleted file mode 100644 index 5418967..0000000 --- a/src/lib/TracingManager.ts +++ /dev/null @@ -1,27 +0,0 @@ -import Tracer from '#lib/Tracer.js'; - -const tracer = new Tracer(); - -const openSpan = (spanId: string, parentSpanId?: string) => - tracer.startSpan(spanId, parentSpanId); -const closeSpan = (spanId: string) => tracer.endSpan(spanId); -const traced = ( - name: string, - fn: () => Promise, - parentSpanId?: string, -) => tracer.traced(name, fn, parentSpanId); -const getActiveSpans = () => tracer.getActiveSpans(); -const getTraceJSON = () => tracer.getTraceJSON(); -const streamEvents = () => tracer.streamEvents(); -const endTracing = () => tracer.endTracing(); - -export default tracer; -export { - openSpan, - closeSpan, - traced, - getActiveSpans, - getTraceJSON, - streamEvents, - endTracing, -}; diff --git a/src/lib/types.ts b/src/lib/types.ts deleted file mode 100644 index d2ee4c0..0000000 --- a/src/lib/types.ts +++ /dev/null @@ -1,16 +0,0 @@ -type SpanJSON = { - spanId: string; - name: string; - startTime: number; - endTime: number | undefined; - parentSpanId: string | undefined; - isCompleted: boolean; - children: Array; -}; - -type SpanEvent = { - type: 'start' | 'stop'; - span: SpanJSON; -}; - -export type { SpanJSON, SpanEvent }; diff --git a/src/tracer/Tracer.ts b/src/tracer/Tracer.ts new file mode 100644 index 0000000..804359b --- /dev/null +++ b/src/tracer/Tracer.ts @@ -0,0 +1,83 @@ +import type { SpanEvent, SpanId } from './types.js'; +import { IdSortable, utils as idUtils } from '@matrixai/id'; + +class Tracer { + protected activeSpans: Map = new Map(); + protected queue: Array = []; + protected resolveWaitChunksP: (() => void) | undefined; + protected ended: boolean = false; + + protected queueSpanEvent(evt: SpanEvent) { + // Convert the binary id to base64-encoded id + if (evt.id instanceof IdSortable) { + evt.id = idUtils.toMultibase(evt.id.get(), 'base64'); + } + if (evt.spanId instanceof IdSortable) { + evt.spanId = idUtils.toMultibase(evt.spanId.get(), 'base64'); + } + if (evt.parentSpanId instanceof IdSortable) { + evt.parentSpanId = idUtils.toMultibase(evt.parentSpanId.get(), 'base64'); + } + this.queue.push(evt); + if (this.resolveWaitChunksP != null) this.resolveWaitChunksP(); + } + + public startSpan(name: string, parentSpanId?: SpanId): SpanId { + const spanId = new IdSortable(); + this.activeSpans.set(spanId, name); + this.queueSpanEvent({ + type: 'start', + id: new IdSortable(), + spanId: spanId, + parentSpanId: parentSpanId, + name: name, + }); + return spanId; + } + + public endSpan(spanId: SpanId): void { + const name = this.activeSpans.get(spanId); + if (!name) return; + this.activeSpans.delete(spanId); + this.queueSpanEvent({ + type: 'end', + id: new IdSortable(), + spanId: spanId, + name: name, + }); + } + + public async traced( + name: string, + parentSpanId: SpanId | undefined, + fn: () => T | Promise, + ): Promise { + const fnProm = async () => { + const spanId = this.startSpan(name, parentSpanId); + const retval = await fn(); + this.endSpan(spanId); + return retval; + }; + return await fnProm(); + } + + public endTracing(): void { + this.ended = true; + } + + public async *streamEvents(): AsyncGenerator { + while (true) { + const value = this.queue.shift(); + if (value == null) { + if (this.ended) break; + await new Promise((resolve) => { + this.resolveWaitChunksP = resolve; + }); + continue; + } + yield value; + } + } +} + +export default Tracer; diff --git a/src/tracer/index.ts b/src/tracer/index.ts new file mode 100644 index 0000000..22cd708 --- /dev/null +++ b/src/tracer/index.ts @@ -0,0 +1,7 @@ +import Tracer from './Tracer.js'; + +// We don't export tracer class, but an instance which has all its methods +const tracer = new Tracer(); +export default tracer; + +export * from './types.js'; diff --git a/src/tracer/types.ts b/src/tracer/types.ts new file mode 100644 index 0000000..a52db4c --- /dev/null +++ b/src/tracer/types.ts @@ -0,0 +1,17 @@ +import type { IdSortable } from '@matrixai/id'; + +type SpanId = IdSortable | string; +type EventId = IdSortable | string; + +type Span = { + spanId: SpanId; + name: string; + parentSpanId?: SpanId; +}; + +type SpanEvent = Span & { + type: 'start' | 'end'; + id: EventId; +}; + +export type { SpanId, EventId, Span, SpanEvent }; diff --git a/tests/asciinemaTest.ts b/tests/asciinemaTest.ts index aafed31..2b268ca 100644 --- a/tests/asciinemaTest.ts +++ b/tests/asciinemaTest.ts @@ -1,15 +1,11 @@ +import type { SpanId } from '#tracer/index.js'; import fs from 'fs'; import * as fc from 'fast-check'; -import { - openSpan, - closeSpan, - traced, - streamEvents, -} from '#lib/TracingManager.js'; +import tracer from '#tracer/index.js'; let parentIndex = 0; let step = 0; -let nestedIds: Array = []; +let nestedIds: Array = []; type Flags = { hasForkA: boolean; @@ -23,9 +19,9 @@ type Flags = { }; const current: { - parentId?: string; - forkAId?: string; - forkBId?: string; + parentId?: SpanId; + forkAId?: SpanId; + forkBId?: SpanId; flags: Flags; } = { flags: { @@ -53,7 +49,7 @@ const flagArb = fc.record({ const saveToFileP = (async () => { const file = await fs.promises.open('span.jsonl', 'w'); - for await (const event of streamEvents()) { + for await (const event of tracer.streamEvents()) { await file.write(JSON.stringify(event) + '\n'); } await file.close(); @@ -63,56 +59,68 @@ setInterval(async () => { switch (step) { case 0: { current.flags = fc.sample(flagArb, 1)[0]; - current.parentId = openSpan(`Parent-${parentIndex}`); + current.parentId = tracer.startSpan(`Parent-${parentIndex}`); nestedIds = []; break; } case 1: { if (current.flags.hasForkA) { - await traced(`Parent-${parentIndex}-Fork-A`, async () => { - current.forkAId = openSpan( - `Parent-${parentIndex}-Fork-A`, - current.parentId, - ); - for (let i = 1; i <= current.flags.forkAChildren; i++) { - const id = openSpan(`Fork-A-Span-${i}`, current.forkAId); - closeSpan(id); - } - closeSpan(current.forkAId!); - }); + await tracer.traced( + `Parent-${parentIndex}-Fork-A`, + undefined, + async () => { + current.forkAId = tracer.startSpan( + `Parent-${parentIndex}-Fork-A`, + current.parentId, + ); + for (let i = 1; i <= current.flags.forkAChildren; i++) { + const id = tracer.startSpan(`Fork-A-Span-${i}`, current.forkAId); + tracer.endSpan(id); + } + tracer.endSpan(current.forkAId!); + }, + ); } break; } case 2: { if (current.flags.hasForkB) { - await traced(`Parent-${parentIndex}-Fork-B`, async () => { - current.forkBId = openSpan( - `Parent-${parentIndex}-Fork-B`, - current.parentId, - ); - for (let i = 1; i <= current.flags.forkBChildren; i++) { - const id = openSpan(`Fork-B-Span-${i}`, current.forkBId); - closeSpan(id); - } - closeSpan(current.forkBId!); - }); + await tracer.traced( + `Parent-${parentIndex}-Fork-B`, + undefined, + async () => { + current.forkBId = tracer.startSpan( + `Parent-${parentIndex}-Fork-B`, + current.parentId, + ); + for (let i = 1; i <= current.flags.forkBChildren; i++) { + const id = tracer.startSpan(`Fork-B-Span-${i}`, current.forkBId); + tracer.endSpan(id); + } + tracer.endSpan(current.forkBId!); + }, + ); } break; } case 3: { if (current.flags.hasNested) { - await traced(`Async-Chain-${parentIndex}`, async () => { - let lastId = current.parentId!; - for (let i = 1; i <= current.flags.nestedDepth; i++) { - const label = `Async-Job-${i}`; - const id = openSpan(label, lastId); - nestedIds.push(id); - lastId = id; - } - }); + await tracer.traced( + `Async-Chain-${parentIndex}`, + undefined, + async () => { + let lastId = current.parentId!; + for (let i = 1; i <= current.flags.nestedDepth; i++) { + const label = `Async-Job-${i}`; + const id = tracer.startSpan(label, lastId); + nestedIds.push(id); + lastId = id; + } + }, + ); } break; } @@ -122,32 +130,32 @@ setInterval(async () => { case 6: { if (nestedIds.length > 0) { const toClose = nestedIds.pop(); - if (toClose) closeSpan(toClose); + if (toClose) tracer.endSpan(toClose); } break; } case 7: { if (current.flags.hasRejoin) { - const merge = openSpan( + const merge = tracer.startSpan( `[Rejoins-Fork-${parentIndex}]`, current.parentId, ); - closeSpan(merge); + tracer.endSpan(merge); } break; } case 8: { if (current.flags.hasOrphan) { - const orphan = openSpan(`Orphan-${parentIndex}`); - closeSpan(orphan); + const orphan = tracer.startSpan(`Orphan-${parentIndex}`); + tracer.endSpan(orphan); } break; } case 9: { - closeSpan(current.parentId!); + tracer.endSpan(current.parentId!); break; }