From 8df66ffcc6887707c6faeac95e0d69cb2bbce6e3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 8 Jan 2023 22:44:12 +0000 Subject: [PATCH 01/45] Bump json5 from 2.2.1 to 2.2.3 Bumps [json5](https://github.com/json5/json5) from 2.2.1 to 2.2.3. - [Release notes](https://github.com/json5/json5/releases) - [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md) - [Commits](https://github.com/json5/json5/compare/v2.2.1...v2.2.3) --- updated-dependencies: - dependency-name: json5 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index e988965..f5b75d8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4577,9 +4577,9 @@ "dev": true }, "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "bin": { "json5": "lib/cli.js" @@ -10429,9 +10429,9 @@ "dev": true }, "json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true }, "kind-of": { From 94728d69b9a9ebce1515127365dae20976e779fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Mar 2023 02:38:47 +0000 Subject: [PATCH 02/45] Bump webpack from 5.73.0 to 5.76.1 Bumps [webpack](https://github.com/webpack/webpack) from 5.73.0 to 5.76.1. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.73.0...v5.76.1) --- updated-dependencies: - dependency-name: webpack dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index e988965..e326946 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3317,9 +3317,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz", - "integrity": "sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow==", + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", + "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", "dev": true, "peer": true, "dependencies": { @@ -6758,9 +6758,9 @@ } }, "node_modules/webpack": { - "version": "5.73.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.73.0.tgz", - "integrity": "sha512-svjudQRPPa0YiOYa2lM/Gacw0r6PvxptHj4FuEKQ2kX05ZLkjbVc5MnPs6its5j7IZljnIqSVo/OsY2X0IpHGA==", + "version": "5.76.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz", + "integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==", "dev": true, "peer": true, "dependencies": { @@ -6769,11 +6769,11 @@ "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/wasm-edit": "1.11.1", "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.4.1", + "acorn": "^8.7.1", "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.9.3", + "enhanced-resolve": "^5.10.0", "es-module-lexer": "^0.9.0", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -6786,7 +6786,7 @@ "schema-utils": "^3.1.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.3.1", + "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" }, "bin": { @@ -9488,9 +9488,9 @@ "dev": true }, "enhanced-resolve": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz", - "integrity": "sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow==", + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", + "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", "dev": true, "peer": true, "requires": { @@ -11933,9 +11933,9 @@ } }, "webpack": { - "version": "5.73.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.73.0.tgz", - "integrity": "sha512-svjudQRPPa0YiOYa2lM/Gacw0r6PvxptHj4FuEKQ2kX05ZLkjbVc5MnPs6its5j7IZljnIqSVo/OsY2X0IpHGA==", + "version": "5.76.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz", + "integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==", "dev": true, "peer": true, "requires": { @@ -11944,11 +11944,11 @@ "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/wasm-edit": "1.11.1", "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.4.1", + "acorn": "^8.7.1", "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.9.3", + "enhanced-resolve": "^5.10.0", "es-module-lexer": "^0.9.0", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -11961,7 +11961,7 @@ "schema-utils": "^3.1.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.3.1", + "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" }, "dependencies": { From d91ff60cd2bb6ac469e5b9e3e5f4f848e608e088 Mon Sep 17 00:00:00 2001 From: Github Actions Date: Mon, 17 Apr 2023 18:41:42 +0000 Subject: [PATCH 03/45] Version bump --- box.json | 2 +- changelog.md | 234 ++++++++++++++++++++++++++------------------------- 2 files changed, 121 insertions(+), 115 deletions(-) diff --git a/box.json b/box.json index 17a3489..9d0b321 100644 --- a/box.json +++ b/box.json @@ -2,7 +2,7 @@ "name":"ColdBox Debugger", "author":"Ortus Solutions 2022-NOV-22 ### Fixed -* Adobe dumb array by value +- Adobe dumb array by value ## [4.0.0] => 2022-NOV-22 ### Added -* ColdBox 7 support -* New `TimerDelegate` that can be used to add timer functions to any model -* Timer service rewritten to support nesting and included metadata -* Ability to open views and layouts from the execution timers in any Code Editor -* New `WireBoxCollector` which is only used if enabled. This greatly accelerates the performance of the request collector since before they where in the same collector. -* Ability to open CFCs that are profiled by the WireBox Collector in any Code Editor. -* Ability to open the Handler events that are profiled by the Request Collector in any Code Editor. -* New life-cycle events: `onDebuggerUnload`, `onDebuggerLoad` -* Ability for the custom `timeIt()` functions to accept metdata to store in the execution timer -* New `Slowest` Queries panel for cborm, acf, and qb/quick -* New visualizer total db time as well as request time including percentage of the request time -* Ability to export a profiler in json -* Ability to sort the visualizer's profilers +- ColdBox 7 support +- New `TimerDelegate` that can be used to add timer functions to any model +- Timer service rewritten to support nesting and included metadata +- Ability to open views and layouts from the execution timers in any Code Editor +- New `WireBoxCollector` which is only used if enabled. This greatly accelerates the performance of the request collector since before they where in the same collector. +- Ability to open CFCs that are profiled by the WireBox Collector in any Code Editor. +- Ability to open the Handler events that are profiled by the Request Collector in any Code Editor. +- New life-cycle events: `onDebuggerUnload`, `onDebuggerLoad` +- Ability for the custom `timeIt()` functions to accept metdata to store in the execution timer +- New `Slowest` Queries panel for cborm, acf, and qb/quick +- New visualizer total db time as well as request time including percentage of the request time +- Ability to export a profiler in json +- Ability to sort the visualizer's profilers ### Fixed -* Timer service reconstructing the timer hashes and profilers twice. -* `timeIt()` helper was not passing the closure correctly -* If doing a fwreinit on the visualizer, the current profiler was still being show even thought it was empty. Add an empty check to avoid the big bang! -* Empty response codes for Adobe, due to their incredibly weird Response object nesting. -* Migration to java random id's for speed +- Timer service reconstructing the timer hashes and profilers twice. +- `timeIt()` helper was not passing the closure correctly +- If doing a fwreinit on the visualizer, the current profiler was still being show even thought it was empty. Add an empty check to avoid the big bang! +- Empty response codes for Adobe, due to their incredibly weird Response object nesting. +- Migration to java random id's for speed ### Changed -* Tracers are now streamlined and stored alongside the request profilers -* Small UI fixes on request profiler HTTP methods -* WireBox collecting is now done by the WireBox collector not the Request Collector. -* Adobe 2016 Dropped +- Tracers are now streamlined and stored alongside the request profilers +- Small UI fixes on request profiler HTTP methods +- WireBox collecting is now done by the WireBox collector not the Request Collector. +- Adobe 2016 Dropped ## [3.4.1] => 2022-JUL-12 ### Fixed -* If the debugger is disabled or not in debug mode, the panels and visualizers are still being rendered and exploding. This should be a 404. +- If the debugger is disabled or not in debug mode, the panels and visualizers are still being rendered and exploding. This should be a 404. ## [3.4.0] => 2022-JUN-27 ### Added -* Upgraded entire front end build process to ColdBox Elixir v4 -* Upgraded to Node 16 for all front end processes +- Upgraded entire front end build process to ColdBox Elixir v4 +- Upgraded to Node 16 for all front end processes ### Fixed -* If the cbdebugger was embedded within an app already using Alpine, it will fail. Now it will leach on to the running Alpine app. +- If the cbdebugger was embedded within an app already using Alpine, it will fail. Now it will leach on to the running Alpine app. ## [3.3.2] => 2022-MAY-02 ### Fixed -* [CBDEBUGGER-19](https://ortussolutions.atlassian.net/browse/CBDEBUGGER-19) - JSON Form serialization not working on formatting. +- [CBDEBUGGER-19](https://ortussolutions.atlassian.net/browse/CBDEBUGGER-19) - JSON Form serialization not working on formatting. ## [3.3.1] => 2022-APR-21 ### Fixed -* [CBDEBUGGER-17](https://ortussolutions.atlassian.net/browse/CBDEBUGGER-17) If you change the monitor frequency, it does not clear the old monitor and you get n monitors -* [CBDEBUGGER-16](https://ortussolutions.atlassian.net/browse/CBDEBUGGER-16) Left double hash on no state for request tracker profiler -* [CBDEBUGGER-15](https://ortussolutions.atlassian.net/browse/CBDEBUGGER-15) Auto-Refresh is not working in latest version -* [CBDEBUGGER-10](https://ortussolutions.atlassian.net/browse/CBDEBUGGER-10) Executing Event That Uses QB From Interceptor Generates CBDebugger Exception -* [CBDEBUGGER-6](https://ortussolutions.atlassian.net/browse/CBDEBUGGER-6) Stop auto-refresh when visiting a actual request report +- [CBDEBUGGER-17](https://ortussolutions.atlassian.net/browse/CBDEBUGGER-17) If you change the monitor frequency, it does not clear the old monitor and you get n monitors +- [CBDEBUGGER-16](https://ortussolutions.atlassian.net/browse/CBDEBUGGER-16) Left double hash on no state for request tracker profiler +- [CBDEBUGGER-15](https://ortussolutions.atlassian.net/browse/CBDEBUGGER-15) Auto-Refresh is not working in latest version +- [CBDEBUGGER-10](https://ortussolutions.atlassian.net/browse/CBDEBUGGER-10) Executing Event That Uses QB From Interceptor Generates CBDebugger Exception +- [CBDEBUGGER-6](https://ortussolutions.atlassian.net/browse/CBDEBUGGER-6) Stop auto-refresh when visiting a actual request report ## [3.3.0] => 2022-APR-21 ### Added -* Asynchronous saving of storage at end of requests -* Asynchronous size checks of storage -* Free memory diff in the visualizers -* Ability for each profiler to track how much memory they used during the course of the transaction by analyzing free memory -* New setting `requestPanelDock` to show/hide the request panel in the dock -* Migration to use new module template approaches that supports github releases, compilation and more -* Exception bean delegations in debugger service to avoid multi-instantiations `performance` -* Refactoring to increase `performance` and reusability -* Migration to AlpineJS from jquery -* New `sqlformatter` module from @michaelborn -* Updated to faster wasy to get a local ip and local hostname +- Asynchronous saving of storage at end of requests +- Asynchronous size checks of storage +- Free memory diff in the visualizers +- Ability for each profiler to track how much memory they used during the course of the transaction by analyzing free memory +- New setting `requestPanelDock` to show/hide the request panel in the dock +- Migration to use new module template approaches that supports github releases, compilation and more +- Exception bean delegations in debugger service to avoid multi-instantiations `performance` +- Refactoring to increase `performance` and reusability +- Migration to AlpineJS from jquery +- New `sqlformatter` module from @michaelborn +- Updated to faster wasy to get a local ip and local hostname ### Fixed -* Actually show a 404 if debug mode is off -* JS Bumps +- Actually show a 404 if debug mode is off +- JS Bumps ### Removed -* Reload all modules. Makes no sense as you can just reinit. +- Reload all modules. Makes no sense as you can just reinit. ## [3.2.0] => 2021-JUL-21 ### Changed -* Thanks to @homestar9 changed the elixir asset to a specific of `cbdebugger.(js.css)` to avoid collisions with main app. +- Thanks to @homestar9 changed the elixir asset to a specific of `cbdebugger.(js.css)` to avoid collisions with main app. ### Added -* Adobe 2021 support and automated testing -* Migration to github actions +- Adobe 2021 support and automated testing +- Migration to github actions ## [3.1.1] => 2021-JUN-05 ### Fixed -* Do not render when the request's content type is NOT html +- Do not render when the request's content type is NOT html ## [3.1.0] => 2021-MAy-19 ### Fixed -* Fix wrong cborm reference on QBCollector -* Look at the renderdata content type instead of type as it's more consistent in order to turn off the debugger on multi-marshalled sites -* [CBDEBUGGER-1] - Lucee debugger no longer shows below the cbDebugger. Turn off only on Ajax Calls +- Fix wrong cborm reference on QBCollector +- Look at the renderdata content type instead of type as it's more consistent in order to turn off the debugger on multi-marshalled sites +- [CBDEBUGGER-1] - Lucee debugger no longer shows below the cbDebugger. Turn off only on Ajax Calls ### Changed -* Use Java property for version to work with jdk8+ -* [CBDEBUGGER-2] - Made `cborm` and `qb` disabled by default +- Use Java property for version to work with jdk8+ +- [CBDEBUGGER-2] - Made `cborm` and `qb` disabled by default ## [3.0.0] => 2021-APR-07 ### Added -* Completely rewritten debugger -* Updated tracers to match all logbox options so we can use them for display instead of hardcoding them in the push operation -* Complete migration to elixir for assets -* Complete migration to runnable events to make things easier for rendering and debugging -* New interceptor profiling via AOP `announce` interceptions -* New object profiling via metadata AOP aspects via new settings: `profileObjects`, `traceObjectResults` -* New visualizer route `/cbdebugger` that if you are in debug mode, you can visualize the panels. Great for API apps -* New method: `timer.timeIt()` so you can time code execution via a closure wrapper -* New Helper Methods: `startCBTimer(), stopCBTimer(), cbTimeIt()` -* Added the route record to the info panel so you can debug the selected route -* Highlights transactions that take over `200ms` or using the `slowExecutionThreshold` setting -* Refactored to use array of structs instead of queries for even faster timer performance +- Completely rewritten debugger +- Updated tracers to match all logbox options so we can use them for display instead of hardcoding them in the push operation +- Complete migration to elixir for assets +- Complete migration to runnable events to make things easier for rendering and debugging +- New interceptor profiling via AOP `announce` interceptions +- New object profiling via metadata AOP aspects via new settings: `profileObjects`, `traceObjectResults` +- New visualizer route `/cbdebugger` that if you are in debug mode, you can visualize the panels. Great for API apps +- New method: `timer.timeIt()` so you can time code execution via a closure wrapper +- New Helper Methods: `startCBTimer(), stopCBTimer(), cbTimeIt()` +- Added the route record to the info panel so you can debug the selected route +- Highlights transactions that take over `200ms` or using the `slowExecutionThreshold` setting +- Refactored to use array of structs instead of queries for even faster timer performance ### Changed -* Encapsualted request timers UI into a single template -* `Timer` is now built in script and optimized -* Show timers as they start instead of how they end, huge UI update to visualize the timers -* Refactored the logbox appenders from `includes/appenders` to `appenders` +- Encapsualted request timers UI into a single template +- `Timer` is now built in script and optimized +- Show timers as they start instead of how they end, huge UI update to visualize the timers +- Refactored the logbox appenders from `includes/appenders` to `appenders` ### Security -* `Dumpar` facilities removed due to security concerns +- `Dumpar` facilities removed due to security concerns ### Removed -* Old `debugger` settings instead use the `modulesettings.cbdebugger` according to ColdBox 5+ standards -* Old helper code to remove helpers -* Removed the loaded modules as it just produced noise -* Removed the rc/prc snapshot comparisons, causes too much noise and not helpful anymore +- Old `debugger` settings instead use the `modulesettings.cbdebugger` according to ColdBox 5+ standards +- Old helper code to remove helpers +- Removed the loaded modules as it just produced noise +- Removed the rc/prc snapshot comparisons, causes too much noise and not helpful anymore ## [2.2.0] => 2020-MAY-18 ### Added -* Upgraded Appender to script and fixes for LogBox 6 -* More tests for logbox loading and appender registration +- Upgraded Appender to script and fixes for LogBox 6 +- More tests for logbox loading and appender registration ### Fixed -* Visual display of the debugger version +- Visual display of the debugger version ## [2.1.0] => 2020-MAY-14 ### Added -* ColdBox 6 support -* Formatting +- ColdBox 6 support +- Formatting ## Removed -* ColdBox 4 lingering code +- ColdBox 4 lingering code ## [2.0.0] => 2020-MAY-04 ### Added -* Formatting updates -* Quick/QB Panels +- Formatting updates +- Quick/QB Panels ### Removed -* Dropped ACF 11 support +- Dropped ACF 11 support ## [1.7.1] => 2019-MAR-06 -* Updated location protocol +- Updated location protocol ## [1.7.0] => 2019-MAR-06 -* Missing interception points for extending the panels: `afterDebuggerPanel`, `beforeDebuggerPanel` -* New Module Layout -* Dropping lucee 4.5 support +- Missing interception points for extending the panels: `afterDebuggerPanel`, `beforeDebuggerPanel` +- New Module Layout +- Dropping lucee 4.5 support ## [1.6.0 ] -* ColdBox 5 Support +- ColdBox 5 Support ## [1.5.0] -* Case-Sensitive filesystems fix -* Updated travis builds -* Unified workbench approach +- Case-Sensitive filesystems fix +- Updated travis builds +- Unified workbench approach ## [1.4.0] -* ColdBox Tracer Appender added by Default by Eric Peterson +- ColdBox Tracer Appender added by Default by Eric Peterson ## [1.3.0] -* Travis integration -* DocBox update -* Build process update +- Travis integration +- DocBox update +- Build process update ## [1.2.0] -* Fix unscoped currentrow which was throwing an error when debugging was enabled. -* Removed reference to missing images in CSS -* Updated build scripts -* How to turn off debugger for tests, it does this automatically now. -* filename cases don't match #5 on certain includes +- Fix unscoped currentrow which was throwing an error when debugging was enabled. +- Removed reference to missing images in CSS +- Updated build scripts +- How to turn off debugger for tests, it does this automatically now. +- filename cases don't match #5 on certain includes ## [1.1.0] -* https://ortussolutions.atlassian.net/browse/CCM-14 Issue with unloading modules -* https://ortussolutions.atlassian.net/browse/CCM-25 Lucee support -* https://ortussolutions.atlassian.net/browse/CCM-24 Added names of rendered -* Unloading of helpers on unload -views and layouts -* Updated production ignore lists +- Issue with unloading modules +- Lucee support +- Added names of rendered +- Unloading of helpers on unload + views and layouts +- Updated production ignore lists ## [1.0.1] -* Bug fixes on caching panels and chicken/egg issues for ColdBox loading +- Bug fixes on caching panels and chicken/egg issues for ColdBox loading ## [1.0.0] -* Create first module version +- Create first module version + +[Unreleased]: https://github.com/coldbox-modules/cbdebugger/compare/v4.1.0...HEAD + +[4.1.0]: https://github.com/coldbox-modules/cbdebugger/compare/b070b77d9edee7725c052eab41bf3513a3a9f6d8...v4.1.0 From c8f38eab730d3456bf44ae2b7321ff2d20c124a5 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Wed, 19 Apr 2023 14:49:14 +0200 Subject: [PATCH 04/45] github support docs --- .github/CODE_OF_CONDUCT.MD | 3 + .github/ISSUE_TEMPLATE/BUG_REPORT.md | 33 +++++++++ .github/ISSUE_TEMPLATE/FEATURE_REQUEST.md | 18 +++++ .github/PULL_REQUEST_TEMPLATE.md | 29 ++++++++ .github/SECURITY.md | 3 + .github/SUPPORT.md | 3 + CONTRIBUTING.md | 88 +++++++++++++++++++++++ 7 files changed, 177 insertions(+) create mode 100644 .github/CODE_OF_CONDUCT.MD create mode 100644 .github/ISSUE_TEMPLATE/BUG_REPORT.md create mode 100644 .github/ISSUE_TEMPLATE/FEATURE_REQUEST.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/SECURITY.md create mode 100644 .github/SUPPORT.md create mode 100644 CONTRIBUTING.md diff --git a/.github/CODE_OF_CONDUCT.MD b/.github/CODE_OF_CONDUCT.MD new file mode 100644 index 0000000..12507ab --- /dev/null +++ b/.github/CODE_OF_CONDUCT.MD @@ -0,0 +1,3 @@ +# Code of Conduct + +Please see it in our [Contributing Guidelines](../CONTRIBUTING.md#code-of-conduct). diff --git a/.github/ISSUE_TEMPLATE/BUG_REPORT.md b/.github/ISSUE_TEMPLATE/BUG_REPORT.md new file mode 100644 index 0000000..300232e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/BUG_REPORT.md @@ -0,0 +1,33 @@ +--- +name: Bug report +about: Create a report to help us improve +--- + + + +## What are the steps to reproduce this issue? + +1. … +2. … +3. … + +## What happens? + +… + +## What were you expecting to happen? + +… + +## Any logs, error output, etc? + +… + +## Any other comments? + +… + +## What versions are you using? + +**Operating System:** … +**Package Version:** … diff --git a/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md new file mode 100644 index 0000000..c10946f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md @@ -0,0 +1,18 @@ +--- +name: Feature Request +about: Request a new feature or enhancement +--- + + + +## Summary + + + +## Detailed Description + + + +## Possible Implementation Ideas + + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..e8bd9f9 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,29 @@ +# Description + +Please include a summary of the changes and which issue(s) is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. + +**Please note that all PRs must have tests attached to them** + +IMPORTANT: Please review the [CONTRIBUTING.md](../CONTRIBUTING.md) file for detailed contributing guidelines. + +## Issues + +All PRs must have an accompanied issue. Please make sure you created it and linked it here. + +## Type of change + +Please delete options that are not relevant. + +- [ ] Bug Fix +- [ ] Improvement +- [ ] New Feature +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] This change requires a documentation update + +## Checklist + +- [ ] My code follows the style guidelines of this project [cfformat](../.cfformat.json) +- [ ] I have commented my code, particularly in hard-to-understand areas +- [ ] I have made corresponding changes to the documentation +- [ ] I have added tests that prove my fix is effective or that my feature works +- [ ] New and existing unit tests pass locally with my changes diff --git a/.github/SECURITY.md b/.github/SECURITY.md new file mode 100644 index 0000000..f057099 --- /dev/null +++ b/.github/SECURITY.md @@ -0,0 +1,3 @@ +# Security Policy + +Please see it in our [Contributing Guidelines](../CONTRIBUTING.md#security-vulnerabilities). diff --git a/.github/SUPPORT.md b/.github/SUPPORT.md new file mode 100644 index 0000000..3bb8adb --- /dev/null +++ b/.github/SUPPORT.md @@ -0,0 +1,3 @@ +# Support & Help + +Please see it in our [Contributing Guidelines](../CONTRIBUTING.md#support-questions). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..9e0f1be --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,88 @@ +# CBSecurity Contributing Guide + +Hola amigo! I'm really excited that you are interested in contributing to our project. Before submitting your contribution, please make sure to take a moment and read through the following guidelines: + +- [Code Of Conduct](#code-of-conduct) +- [Bug Reporting](#bug-reporting) +- [Support Questions](#support-questions) +- [Security Vulnerabilities](#security-vulnerabilities) +- [Language Compatibility](#language-compatibility) +- [Coding Styles \& Formatting](#coding-styles--formatting) +- [CFC Docs With DocBox](#cfc-docs-with-docbox) +- [Financial Contributions](#financial-contributions) +- [Contributors](#contributors) + +## Code Of Conduct + +This project is open source, and as such, the maintainers give their free time to build and maintain the source code held within. They make the code freely available in the hope that it will be of use to other developers and/or businesses. Please be considerate towards maintainers when raising issues or presenting pull requests. **We all follow the Golden Rule: Do to others as you want them to do to you.** + +- As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. +- Participants will be tolerant of opposing views. +- Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. +- Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned with this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team. +- When interpreting the words and actions of others, participants should always assume good intentions. Emotions cannot be derived from textual representations. +- Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. + +## Bug Reporting + +Each of the main standalone frameworks in ColdBox has its separate locations for submitting bug reports. Please make sure also that if you submit a pull request, you link it to the appropriate issue. + +https://github.com/coldbox-modules/cbsecurity + +If you file a bug report, your issue should contain a title, a clear description of the issue, a way to replicate the issue, and any support files that we might need to replicate your issue. The goal of a bug report is to make it easy for yourself - and others - to replicate the bug and develop a fix for it. All issues that do not contain a way to replicate will not be addressed. + +## Support Questions + +If you have any questions on usage, professional support or just ideas to bounce off the maintainers, please do not create an issue. Leverage our support channels first. + +- Ortus Community Discourse: https://community.ortussolutions.com/ +- Box Slack Team : https://boxteam.ortussolutions.com/ +- Professional Support : https://www.ortussolutions.com/services/support + +## Security Vulnerabilities + +If you discover a security vulnerability, please send an email to the development team at [security@ortussolutions.com](mailto:security@ortussolutions.com?subject=security) and make sure you report it to the `#security` channel in our Box Team Slack Channel. All security vulnerabilities will be promptly addressed. + +## Language Compatibility + +Please make sure your code runs on the following CFML Engines: + +- Lucee 5+ +- Adobe ColdFusion 2018+ + +## Coding Styles & Formatting + +We are big on coding styles and have included a `.cfformat.json` in the root of the project so that you can run the formatting tools and CommandBox scripts: + +```bash +# Format everything +box run-script format + +# Start a watcher, type away, save and auto-format for you +box run-script format: watch +``` + +We recommend that anytime you hack on the core you start the formatter watcher (`box run-script format:watch`). This will monitor your changes and auto-format your code for you. + +You can also see the Ortus Coding Standards you must follow here: https://github.com/Ortus-Solutions/coding-standards. + +## CFC Docs With DocBox + +All CFCs are self-documenting and we leverage [DocBox](https://docbox.ortusbooks.com/) to document the entire software. All functions must be properly documented using the DocBox syntax: https://docbox.ortusbooks.com/getting-started/annotating-your-code + +## Financial Contributions + +You can support ColdBox and all of our Open Source initiatives at Ortus Solutions by becoming a patreon. You can also get lots of goodies and services depending on the level of contributions. + +- [Become a backer or sponsor on Patreon](https://www.patreon.com/ortussolutions) +- [One-time donations via PayPal](https://www.paypal.com/paypalme/ortussolutions) + +## Contributors + +Thank you to all the people who have already contributed to ColdBox! We: heart: : heart: : heart: love you! + + + + + +Made with [contributors-img](https://contrib.rocks) From c957c07372d2c6fc10c1a6a620ec4002b55e2122 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Wed, 19 Apr 2023 15:31:15 +0200 Subject: [PATCH 05/45] 2023 testing --- .github/workflows/tests.yml | 3 +++ server-adobe@2023.json | 29 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 server-adobe@2023.json diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 06f349c..5a3e701 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -22,6 +22,9 @@ jobs: coldboxVersion: [ "^6.0.0" ] experimental: [ false ] include: + - cfengine: "adobe@2023" + coldboxVersion: "^6.0.0" + experimental: true - coldboxVersion: "be" cfengine: "lucee@5" experimental: true diff --git a/server-adobe@2023.json b/server-adobe@2023.json new file mode 100644 index 0000000..565f79d --- /dev/null +++ b/server-adobe@2023.json @@ -0,0 +1,29 @@ +{ + "name":"@MODULE_NAME@-adobe@2023", + "app":{ + "serverHomeDirectory":".engine/adobe2023", + "cfengine":"adobe@2023.0.0-beta.1" + }, + "web":{ + "http":{ + "port":"60299" + }, + "rewrites":{ + "enable":"true" + }, + "webroot": "test-harness", + "aliases":{ + "/moduleroot/@MODULE_NAME@":"../" + } + }, + "jvm":{ + "heapSize":"1024" + }, + "openBrowser":"false", + "cfconfig": { + "file" : ".cfconfig.json" + }, + "scripts" : { + "onServerInstall":"cfpm install zip,debugger" + } +} From bac87542777b780ac3d583966baf624961287752 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Wed, 19 Apr 2023 15:32:14 +0200 Subject: [PATCH 06/45] missing packages --- server-adobe@2023.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server-adobe@2023.json b/server-adobe@2023.json index 565f79d..0fa7912 100644 --- a/server-adobe@2023.json +++ b/server-adobe@2023.json @@ -24,6 +24,6 @@ "file" : ".cfconfig.json" }, "scripts" : { - "onServerInstall":"cfpm install zip,debugger" + "onServerInstall":"cfpm install zip,orm,mysql,postgresql,sqlserver,feed,chart,debugger" } } From 4341e3185082035eae1767f95e2e378f5af1d2ba Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Wed, 19 Apr 2023 18:11:57 +0200 Subject: [PATCH 07/45] name updates --- CONTRIBUTING.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9e0f1be..885e3c9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,4 @@ -# CBSecurity Contributing Guide +# cbdebugger Contributing Guide Hola amigo! I'm really excited that you are interested in contributing to our project. Before submitting your contribution, please make sure to take a moment and read through the following guidelines: @@ -27,7 +27,7 @@ This project is open source, and as such, the maintainers give their free time t Each of the main standalone frameworks in ColdBox has its separate locations for submitting bug reports. Please make sure also that if you submit a pull request, you link it to the appropriate issue. -https://github.com/coldbox-modules/cbsecurity +https://github.com/coldbox-modules/cbdebugger If you file a bug report, your issue should contain a title, a clear description of the issue, a way to replicate the issue, and any support files that we might need to replicate your issue. The goal of a bug report is to make it easy for yourself - and others - to replicate the bug and develop a fix for it. All issues that do not contain a way to replicate will not be addressed. @@ -81,8 +81,8 @@ You can support ColdBox and all of our Open Source initiatives at Ortus Solution Thank you to all the people who have already contributed to ColdBox! We: heart: : heart: : heart: love you! - - + + Made with [contributors-img](https://contrib.rocks) From b3aa2fa06981032f94a35942a166418ccbe15234 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Thu, 20 Apr 2023 13:42:33 +0200 Subject: [PATCH 08/45] fixing artifacts and adobe 2023 server name --- .github/workflows/release.yml | 26 +++++++++++++++++++++++++- server-adobe@2023.json | 4 ++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a047e57..68619e3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -96,9 +96,33 @@ jobs: .artifacts/**/* changelog.md + - name: Upload Binaries to S3 + uses: jakejarvis/s3-sync-action@master + with: + args: --acl public-read + env: + AWS_S3_BUCKET: "downloads.ortussolutions.com" + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_ACCESS_SECRET }} + SOURCE_DIR: ".artifacts/${{ env.MODULE_ID }}" + DEST_DIR: "ortussolutions/coldbox-modules/${{ env.MODULE_ID }}" + + - name: Upload API Docs to S3 + uses: jakejarvis/s3-sync-action@master + with: + args: --acl public-read + env: + AWS_S3_BUCKET: "apidocs.ortussolutions.com" + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_ACCESS_SECRET }} + SOURCE_DIR: ".tmp/apidocs" + DEST_DIR: "coldbox-modules/${{ env.MODULE_ID }}/${{ env.VERSION }}" + - name: Publish To ForgeBox run: | - cd .tmp/${{ env.MODULE_ID }} && box forgebox publish --force + cd .tmp/${{ env.MODULE_ID }} + cat box.json + box forgebox publish --force - name: Create Github Release uses: taiki-e/create-gh-release-action@v1.6.2 diff --git a/server-adobe@2023.json b/server-adobe@2023.json index 0fa7912..b7463e6 100644 --- a/server-adobe@2023.json +++ b/server-adobe@2023.json @@ -1,5 +1,5 @@ { - "name":"@MODULE_NAME@-adobe@2023", + "name":"cbdebugger-adobe@2023", "app":{ "serverHomeDirectory":".engine/adobe2023", "cfengine":"adobe@2023.0.0-beta.1" @@ -13,7 +13,7 @@ }, "webroot": "test-harness", "aliases":{ - "/moduleroot/@MODULE_NAME@":"../" + "/moduleroot/cbdebugger":"../" } }, "jvm":{ From f499748d33a37acda856a94356dd2daa779b72d5 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Thu, 20 Apr 2023 14:40:45 +0200 Subject: [PATCH 09/45] changelog lint fix --- .github/workflows/release.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 68619e3..bd3231a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -67,6 +67,8 @@ jobs: npm install npm run prod rm -Rf node_modules + npm install -g markdownlint-cli + markdownlint changelog.md --fix box install commandbox-docbox box task run taskfile=build/Build target=run :version=${{ env.VERSION }} :projectName=${{ env.MODULE_ID }} :buildID=${{ github.run_number }} :branch=${{ env.BRANCH }} From 68b662327820d1e4c1745becd9a0f82c548164ac Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Sat, 10 Jun 2023 15:22:25 +0200 Subject: [PATCH 10/45] fix: :zap: Better error handling when Debugger assets are not compiled instead of a cryptic error message: `The parameter [str] to function [closure_m] is required but was not passed in.` --- changelog.md | 229 +++++++++++++++++++++++----------------------- handlers/Main.cfc | 107 ++++++++++++---------- 2 files changed, 176 insertions(+), 160 deletions(-) diff --git a/changelog.md b/changelog.md index 9362038..258cd76 100644 --- a/changelog.md +++ b/changelog.md @@ -9,262 +9,267 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- Better error handling when Debugger assets are not compiled instead of a cryptic error message: +`The parameter [str] to function [closure_m] is required but was not passed in.` + ## [4.1.0] - 2023-04-17 ### Added -- New github actions -- Donot enable debugger in testing mode +- New github actions +- Donot enable debugger in testing mode ## [4.0.1] => 2022-NOV-22 ### Fixed -- Adobe dumb array by value +- Adobe dumb array by value ## [4.0.0] => 2022-NOV-22 ### Added -- ColdBox 7 support -- New `TimerDelegate` that can be used to add timer functions to any model -- Timer service rewritten to support nesting and included metadata -- Ability to open views and layouts from the execution timers in any Code Editor -- New `WireBoxCollector` which is only used if enabled. This greatly accelerates the performance of the request collector since before they where in the same collector. -- Ability to open CFCs that are profiled by the WireBox Collector in any Code Editor. -- Ability to open the Handler events that are profiled by the Request Collector in any Code Editor. -- New life-cycle events: `onDebuggerUnload`, `onDebuggerLoad` -- Ability for the custom `timeIt()` functions to accept metdata to store in the execution timer -- New `Slowest` Queries panel for cborm, acf, and qb/quick -- New visualizer total db time as well as request time including percentage of the request time -- Ability to export a profiler in json -- Ability to sort the visualizer's profilers +- ColdBox 7 support +- New `TimerDelegate` that can be used to add timer functions to any model +- Timer service rewritten to support nesting and included metadata +- Ability to open views and layouts from the execution timers in any Code Editor +- New `WireBoxCollector` which is only used if enabled. This greatly accelerates the performance of the request collector since before they where in the same collector. +- Ability to open CFCs that are profiled by the WireBox Collector in any Code Editor. +- Ability to open the Handler events that are profiled by the Request Collector in any Code Editor. +- New life-cycle events: `onDebuggerUnload`, `onDebuggerLoad` +- Ability for the custom `timeIt()` functions to accept metdata to store in the execution timer +- New `Slowest` Queries panel for cborm, acf, and qb/quick +- New visualizer total db time as well as request time including percentage of the request time +- Ability to export a profiler in json +- Ability to sort the visualizer's profilers ### Fixed -- Timer service reconstructing the timer hashes and profilers twice. -- `timeIt()` helper was not passing the closure correctly -- If doing a fwreinit on the visualizer, the current profiler was still being show even thought it was empty. Add an empty check to avoid the big bang! -- Empty response codes for Adobe, due to their incredibly weird Response object nesting. -- Migration to java random id's for speed +- Timer service reconstructing the timer hashes and profilers twice. +- `timeIt()` helper was not passing the closure correctly +- If doing a fwreinit on the visualizer, the current profiler was still being show even thought it was empty. Add an empty check to avoid the big bang! +- Empty response codes for Adobe, due to their incredibly weird Response object nesting. +- Migration to java random id's for speed ### Changed -- Tracers are now streamlined and stored alongside the request profilers -- Small UI fixes on request profiler HTTP methods -- WireBox collecting is now done by the WireBox collector not the Request Collector. -- Adobe 2016 Dropped +- Tracers are now streamlined and stored alongside the request profilers +- Small UI fixes on request profiler HTTP methods +- WireBox collecting is now done by the WireBox collector not the Request Collector. +- Adobe 2016 Dropped ## [3.4.1] => 2022-JUL-12 ### Fixed -- If the debugger is disabled or not in debug mode, the panels and visualizers are still being rendered and exploding. This should be a 404. +- If the debugger is disabled or not in debug mode, the panels and visualizers are still being rendered and exploding. This should be a 404. ## [3.4.0] => 2022-JUN-27 ### Added -- Upgraded entire front end build process to ColdBox Elixir v4 -- Upgraded to Node 16 for all front end processes +- Upgraded entire front end build process to ColdBox Elixir v4 +- Upgraded to Node 16 for all front end processes ### Fixed -- If the cbdebugger was embedded within an app already using Alpine, it will fail. Now it will leach on to the running Alpine app. +- If the cbdebugger was embedded within an app already using Alpine, it will fail. Now it will leach on to the running Alpine app. ## [3.3.2] => 2022-MAY-02 ### Fixed -- [CBDEBUGGER-19](https://ortussolutions.atlassian.net/browse/CBDEBUGGER-19) - JSON Form serialization not working on formatting. +- [CBDEBUGGER-19](https://ortussolutions.atlassian.net/browse/CBDEBUGGER-19) - JSON Form serialization not working on formatting. ## [3.3.1] => 2022-APR-21 ### Fixed -- [CBDEBUGGER-17](https://ortussolutions.atlassian.net/browse/CBDEBUGGER-17) If you change the monitor frequency, it does not clear the old monitor and you get n monitors -- [CBDEBUGGER-16](https://ortussolutions.atlassian.net/browse/CBDEBUGGER-16) Left double hash on no state for request tracker profiler -- [CBDEBUGGER-15](https://ortussolutions.atlassian.net/browse/CBDEBUGGER-15) Auto-Refresh is not working in latest version -- [CBDEBUGGER-10](https://ortussolutions.atlassian.net/browse/CBDEBUGGER-10) Executing Event That Uses QB From Interceptor Generates CBDebugger Exception -- [CBDEBUGGER-6](https://ortussolutions.atlassian.net/browse/CBDEBUGGER-6) Stop auto-refresh when visiting a actual request report +- [CBDEBUGGER-17](https://ortussolutions.atlassian.net/browse/CBDEBUGGER-17) If you change the monitor frequency, it does not clear the old monitor and you get n monitors +- [CBDEBUGGER-16](https://ortussolutions.atlassian.net/browse/CBDEBUGGER-16) Left double hash on no state for request tracker profiler +- [CBDEBUGGER-15](https://ortussolutions.atlassian.net/browse/CBDEBUGGER-15) Auto-Refresh is not working in latest version +- [CBDEBUGGER-10](https://ortussolutions.atlassian.net/browse/CBDEBUGGER-10) Executing Event That Uses QB From Interceptor Generates CBDebugger Exception +- [CBDEBUGGER-6](https://ortussolutions.atlassian.net/browse/CBDEBUGGER-6) Stop auto-refresh when visiting a actual request report ## [3.3.0] => 2022-APR-21 ### Added -- Asynchronous saving of storage at end of requests -- Asynchronous size checks of storage -- Free memory diff in the visualizers -- Ability for each profiler to track how much memory they used during the course of the transaction by analyzing free memory -- New setting `requestPanelDock` to show/hide the request panel in the dock -- Migration to use new module template approaches that supports github releases, compilation and more -- Exception bean delegations in debugger service to avoid multi-instantiations `performance` -- Refactoring to increase `performance` and reusability -- Migration to AlpineJS from jquery -- New `sqlformatter` module from @michaelborn -- Updated to faster wasy to get a local ip and local hostname +- Asynchronous saving of storage at end of requests +- Asynchronous size checks of storage +- Free memory diff in the visualizers +- Ability for each profiler to track how much memory they used during the course of the transaction by analyzing free memory +- New setting `requestPanelDock` to show/hide the request panel in the dock +- Migration to use new module template approaches that supports github releases, compilation and more +- Exception bean delegations in debugger service to avoid multi-instantiations `performance` +- Refactoring to increase `performance` and reusability +- Migration to AlpineJS from jquery +- New `sqlformatter` module from @michaelborn +- Updated to faster wasy to get a local ip and local hostname ### Fixed -- Actually show a 404 if debug mode is off -- JS Bumps +- Actually show a 404 if debug mode is off +- JS Bumps ### Removed -- Reload all modules. Makes no sense as you can just reinit. +- Reload all modules. Makes no sense as you can just reinit. ## [3.2.0] => 2021-JUL-21 ### Changed -- Thanks to @homestar9 changed the elixir asset to a specific of `cbdebugger.(js.css)` to avoid collisions with main app. +- Thanks to @homestar9 changed the elixir asset to a specific of `cbdebugger.(js.css)` to avoid collisions with main app. ### Added -- Adobe 2021 support and automated testing -- Migration to github actions +- Adobe 2021 support and automated testing +- Migration to github actions ## [3.1.1] => 2021-JUN-05 ### Fixed -- Do not render when the request's content type is NOT html +- Do not render when the request's content type is NOT html ## [3.1.0] => 2021-MAy-19 ### Fixed -- Fix wrong cborm reference on QBCollector -- Look at the renderdata content type instead of type as it's more consistent in order to turn off the debugger on multi-marshalled sites -- [CBDEBUGGER-1] - Lucee debugger no longer shows below the cbDebugger. Turn off only on Ajax Calls +- Fix wrong cborm reference on QBCollector +- Look at the renderdata content type instead of type as it's more consistent in order to turn off the debugger on multi-marshalled sites +- [CBDEBUGGER-1] - Lucee debugger no longer shows below the cbDebugger. Turn off only on Ajax Calls ### Changed -- Use Java property for version to work with jdk8+ -- [CBDEBUGGER-2] - Made `cborm` and `qb` disabled by default +- Use Java property for version to work with jdk8+ +- [CBDEBUGGER-2] - Made `cborm` and `qb` disabled by default ## [3.0.0] => 2021-APR-07 ### Added -- Completely rewritten debugger -- Updated tracers to match all logbox options so we can use them for display instead of hardcoding them in the push operation -- Complete migration to elixir for assets -- Complete migration to runnable events to make things easier for rendering and debugging -- New interceptor profiling via AOP `announce` interceptions -- New object profiling via metadata AOP aspects via new settings: `profileObjects`, `traceObjectResults` -- New visualizer route `/cbdebugger` that if you are in debug mode, you can visualize the panels. Great for API apps -- New method: `timer.timeIt()` so you can time code execution via a closure wrapper -- New Helper Methods: `startCBTimer(), stopCBTimer(), cbTimeIt()` -- Added the route record to the info panel so you can debug the selected route -- Highlights transactions that take over `200ms` or using the `slowExecutionThreshold` setting -- Refactored to use array of structs instead of queries for even faster timer performance +- Completely rewritten debugger +- Updated tracers to match all logbox options so we can use them for display instead of hardcoding them in the push operation +- Complete migration to elixir for assets +- Complete migration to runnable events to make things easier for rendering and debugging +- New interceptor profiling via AOP `announce` interceptions +- New object profiling via metadata AOP aspects via new settings: `profileObjects`, `traceObjectResults` +- New visualizer route `/cbdebugger` that if you are in debug mode, you can visualize the panels. Great for API apps +- New method: `timer.timeIt()` so you can time code execution via a closure wrapper +- New Helper Methods: `startCBTimer(), stopCBTimer(), cbTimeIt()` +- Added the route record to the info panel so you can debug the selected route +- Highlights transactions that take over `200ms` or using the `slowExecutionThreshold` setting +- Refactored to use array of structs instead of queries for even faster timer performance ### Changed -- Encapsualted request timers UI into a single template -- `Timer` is now built in script and optimized -- Show timers as they start instead of how they end, huge UI update to visualize the timers -- Refactored the logbox appenders from `includes/appenders` to `appenders` +- Encapsualted request timers UI into a single template +- `Timer` is now built in script and optimized +- Show timers as they start instead of how they end, huge UI update to visualize the timers +- Refactored the logbox appenders from `includes/appenders` to `appenders` ### Security -- `Dumpar` facilities removed due to security concerns +- `Dumpar` facilities removed due to security concerns ### Removed -- Old `debugger` settings instead use the `modulesettings.cbdebugger` according to ColdBox 5+ standards -- Old helper code to remove helpers -- Removed the loaded modules as it just produced noise -- Removed the rc/prc snapshot comparisons, causes too much noise and not helpful anymore +- Old `debugger` settings instead use the `modulesettings.cbdebugger` according to ColdBox 5+ standards +- Old helper code to remove helpers +- Removed the loaded modules as it just produced noise +- Removed the rc/prc snapshot comparisons, causes too much noise and not helpful anymore ## [2.2.0] => 2020-MAY-18 ### Added -- Upgraded Appender to script and fixes for LogBox 6 -- More tests for logbox loading and appender registration +- Upgraded Appender to script and fixes for LogBox 6 +- More tests for logbox loading and appender registration ### Fixed -- Visual display of the debugger version +- Visual display of the debugger version ## [2.1.0] => 2020-MAY-14 ### Added -- ColdBox 6 support -- Formatting +- ColdBox 6 support +- Formatting ## Removed -- ColdBox 4 lingering code +- ColdBox 4 lingering code ## [2.0.0] => 2020-MAY-04 ### Added -- Formatting updates -- Quick/QB Panels +- Formatting updates +- Quick/QB Panels ### Removed -- Dropped ACF 11 support +- Dropped ACF 11 support ## [1.7.1] => 2019-MAR-06 -- Updated location protocol +- Updated location protocol ## [1.7.0] => 2019-MAR-06 -- Missing interception points for extending the panels: `afterDebuggerPanel`, `beforeDebuggerPanel` -- New Module Layout -- Dropping lucee 4.5 support +- Missing interception points for extending the panels: `afterDebuggerPanel`, `beforeDebuggerPanel` +- New Module Layout +- Dropping lucee 4.5 support ## [1.6.0 ] -- ColdBox 5 Support +- ColdBox 5 Support ## [1.5.0] -- Case-Sensitive filesystems fix -- Updated travis builds -- Unified workbench approach +- Case-Sensitive filesystems fix +- Updated travis builds +- Unified workbench approach ## [1.4.0] -- ColdBox Tracer Appender added by Default by Eric Peterson +- ColdBox Tracer Appender added by Default by Eric Peterson ## [1.3.0] -- Travis integration -- DocBox update -- Build process update +- Travis integration +- DocBox update +- Build process update ## [1.2.0] -- Fix unscoped currentrow which was throwing an error when debugging was enabled. -- Removed reference to missing images in CSS -- Updated build scripts -- How to turn off debugger for tests, it does this automatically now. -- filename cases don't match #5 on certain includes +- Fix unscoped currentrow which was throwing an error when debugging was enabled. +- Removed reference to missing images in CSS +- Updated build scripts +- How to turn off debugger for tests, it does this automatically now. +- filename cases don't match #5 on certain includes ## [1.1.0] -- Issue with unloading modules -- Lucee support -- Added names of rendered -- Unloading of helpers on unload +- Issue with unloading modules +- Lucee support +- Added names of rendered +- Unloading of helpers on unload views and layouts -- Updated production ignore lists +- Updated production ignore lists ## [1.0.1] -- Bug fixes on caching panels and chicken/egg issues for ColdBox loading +- Bug fixes on caching panels and chicken/egg issues for ColdBox loading ## [1.0.0] -- Create first module version +- Create first module version [Unreleased]: https://github.com/coldbox-modules/cbdebugger/compare/v4.1.0...HEAD diff --git a/handlers/Main.cfc b/handlers/Main.cfc index ec2fe16..b80361b 100644 --- a/handlers/Main.cfc +++ b/handlers/Main.cfc @@ -1,5 +1,5 @@ /** - * Main ColdBox Debugger Visualizer + * Main ColdBox Debugger Visualizer Handler */ component extends="coldbox.system.RestHandler" { @@ -55,40 +55,46 @@ component extends="coldbox.system.RestHandler" { setting showdebugoutput=false; // Return the debugger layout+view // We pass in all the variables needed, to avoid prc/rc conflicts - return layout( - layout : isVisualizer ? "Monitor" : "Main", - module : "cbdebugger", - view : "main/debugger", - viewModule: "cbdebugger", - args : { - // Get the current profiler for the current request. Basically the first in the stack - currentProfiler : variables.debuggerService.getCurrentProfiler(), - // Module Config - debuggerConfig : variables.debuggerConfig, - // Service pointer - debuggerService : variables.debuggerService, - // When debugging starts - debugStartTime : getTickCount(), - // Env struct - environment : variables.debuggerService.getEnvironment(), - // Visualizer mode or panel at bottom mode - isVisualizer : isVisualizer, - // Manifest Root - manifestRoot : event.getModuleRoot( "cbDebugger" ) & "/includes", - // Module Root - moduleRoot : event.getModuleRoot( "cbDebugger" ), - // All Module Settings - moduleSettings : getSetting( "modules" ), - // Rendering page title - pageTitle : "ColdBox Debugger", - // Profilers storage to display - profilers : variables.debuggerService.getProfilerStorage(), - // Incoming frequency if in visualizer mode - refreshFrequency : rc.frequency, - // Url build base - urlBase : event.buildLink( "" ) - } - ); + try { + return layout( + layout : isVisualizer ? "Monitor" : "Main", + module : "cbdebugger", + view : "main/debugger", + viewModule: "cbdebugger", + args : { + // Get the current profiler for the current request. Basically the first in the stack + currentProfiler : variables.debuggerService.getCurrentProfiler(), + // Module Config + debuggerConfig : variables.debuggerConfig, + // Service pointer + debuggerService : variables.debuggerService, + // When debugging starts + debugStartTime : getTickCount(), + // Env struct + environment : variables.debuggerService.getEnvironment(), + // Visualizer mode or panel at bottom mode + isVisualizer : isVisualizer, + // Manifest Root + manifestRoot : event.getModuleRoot( "cbDebugger" ) & "/includes", + // Module Root + moduleRoot : event.getModuleRoot( "cbDebugger" ), + // All Module Settings + moduleSettings : getSetting( "modules" ), + // Rendering page title + pageTitle : "ColdBox Debugger", + // Profilers storage to display + profilers : variables.debuggerService.getProfilerStorage(), + // Incoming frequency if in visualizer mode + refreshFrequency : rc.frequency, + // Url build base + urlBase : event.buildLink( "" ) + } + ); + } catch ( any e ) { + var eMessage = "Error rendering the ColdBox Debugger: #e.message & e.detail#"; + log.error( eMessage, e ) + return eMessage; + } } /** @@ -126,18 +132,6 @@ component extends="coldbox.system.RestHandler" { ); } - private function paramSorting( rc ){ - param rc.sortBy = "timestamp"; - param rc.sortOrder = "desc"; - if ( !len( rc.sortBy ) ) { - rc.sortby = "timestamp"; - } - if ( !len( rc.sortOrder ) ) { - rc.sortOrder = "desc"; - } - return this; - } - /** * Get a profiler report via ajax */ @@ -179,7 +173,7 @@ component extends="coldbox.system.RestHandler" { } /** - * Reload a modules + * Reload a module */ function reloadModule( event, rc, prc ){ event.paramValue( "module", "" ); @@ -194,4 +188,21 @@ component extends="coldbox.system.RestHandler" { event.getResponse().setData( variables.debuggerService.getEnvironment() ); } + // ################################################# PRIVATE ######################################################// + + /** + * Internal param sorting defaults + */ + private function paramSorting( rc ){ + param rc.sortBy = "timestamp"; + param rc.sortOrder = "desc"; + if ( !len( rc.sortBy ) ) { + rc.sortby = "timestamp"; + } + if ( !len( rc.sortOrder ) ) { + rc.sortOrder = "desc"; + } + return this; + } + } From 2b4cfa227d7de4842975068bd533bbaa00e2855b Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Mon, 12 Jun 2023 17:40:31 +0200 Subject: [PATCH 11/45] ### Added - New `LuceeSqlCollector` you can use to profile all SQL calls in Lucee - New `luceeSql` configuration to control the Lucee SQL calls collector - Changed the `instance` argument to `any` in the `debuggerService.openInEditorURL` to allow for a flat representational string of the URL to open in the editor. ### Fixed - Dumb whitespace added by CFML engines when doing inline `
#method()#
` calls. --- .DS_Store | Bin 0 -> 6148 bytes .markdownlint.json | 6 +- ModuleConfig.cfc | 17 +- build/Build.cfc | 45 ++- changelog.md | 7 + handlers/Main.cfc | 5 +- interceptors/LuceeSqlCollector.cfc | 70 +++++ models/DebuggerService.cfc | 24 +- models/JVMUtil.cfc | 47 +++ readme.md | 30 ++ test-harness/.DS_Store | Bin 0 -> 6148 bytes test-harness/config/Coldbox.cfc | 3 +- test-harness/views/main/index.cfm | 2 +- .../panels/requestTracker/acfSqlPanel.cfm | 5 +- .../panels/requestTracker/acfSqlTable.cfm | 3 +- .../main/panels/requestTracker/cbormPanel.cfm | 5 +- .../panels/requestTracker/cbormSqlTable.cfm | 3 +- .../panels/requestTracker/luceeSqlPanel.cfm | 275 ++++++++++++++++++ .../panels/requestTracker/luceeSqlTable.cfm | 88 ++++++ views/main/panels/requestTracker/qbPanel.cfm | 5 +- .../main/panels/requestTracker/qbSqlTable.cfm | 3 +- views/main/partials/profilerReport.cfm | 16 + 22 files changed, 608 insertions(+), 51 deletions(-) create mode 100644 .DS_Store create mode 100644 interceptors/LuceeSqlCollector.cfc create mode 100644 models/JVMUtil.cfc create mode 100644 test-harness/.DS_Store create mode 100755 views/main/panels/requestTracker/luceeSqlPanel.cfm create mode 100644 views/main/panels/requestTracker/luceeSqlTable.cfm diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..941cb39f7f600c39d1c26dae41d326c891053d4f GIT binary patch literal 6148 zcmeHK%}T>S5T0$TO{hW-DjpZSR%}HP@e*o%0V8@)sR=1I7_+5G?V%KM)EDwmd>&_Z zw_>Ticn~QwF!Sxs&SaTy!~Ot(Xpf>6Kpg-aRKk*r<_Dp1(gi75524WC*oQs@FoYC( z3(@TOj||Y-Z9tCem7)ExpI2(kC3NhwA93*j;H=7@#RIaS8SF3KdR=xN8YV7Ah zKFZp`@RoX4N+sc}9fa3$Z``eKovSnt;E)le$%@6)nraRzVLSX$kSKTH#q zK4Q!)f0oC{3@`)Cz-lvKcRi=J+GTQe%m6d+3kGO^kf?;7#loQ8I?&Mdk;W^8B-p06 z1fjI(Su70V2#PSNh$dCoCx$TT=$AImvsf53=^*sX_#Hd5urCy$XGg!(;UGMNY?%RO zV4i`p>DKA|zgYhMpHJc*Gr$b26a%8t@jGoS$)2qX#nD+SQ6ErAD6TO0m4Xd@6k{wM d#k;6l&@ZWh=vgcbq6dX90-6Rk%)p;A@Cn%1PJsXb literal 0 HcmV?d00001 diff --git a/.markdownlint.json b/.markdownlint.json index 0f20d70..76f7f8c 100644 --- a/.markdownlint.json +++ b/.markdownlint.json @@ -6,5 +6,7 @@ "no-multiple-blanks": { "maximum": 2 }, - "no-inline-html" : false -} \ No newline at end of file + "no-inline-html" : false, + "no-hard-tabs": false, + "no-bare-urls": false +} diff --git a/ModuleConfig.cfc b/ModuleConfig.cfc index 73abae0..e2c21d8 100644 --- a/ModuleConfig.cfc +++ b/ModuleConfig.cfc @@ -114,9 +114,11 @@ component { logParams : true }, // Adobe ColdFusion SQL Collector - acfSql : { enabled : false, expanded : false, logParams : true }, + acfSql : { enabled : false, expanded : false, logParams : true }, + // Lucee SQL Collector + luceeSQL : { enabled : false, expanded : false, logParams : true }, // Async Manager Reporting - async : { enabled : true, expanded : false } + async : { enabled : true, expanded : false } }; // Visualizer Route @@ -272,6 +274,17 @@ component { variables.settings.acfSql.enabled = false; } + /******************** Lucee SQL COLLECTOR ************************************/ + + if ( variables.settings.luceeSQL.enabled && server.keyExists( "lucee" ) ) { + interceptorService.registerInterceptor( + interceptorClass = "#moduleMapping#.interceptors.LuceeSqlCollector", + interceptorName = "LuceeSqlCollector@cbdebugger" + ); + } else { + variables.settings.luceeSQL.enabled = false; + } + // Announce debugger loaded interceptorService.announce( "onDebuggerLoad" ); } diff --git a/build/Build.cfc b/build/Build.cfc index 926cce1..ee9366e 100644 --- a/build/Build.cfc +++ b/build/Build.cfc @@ -76,9 +76,6 @@ component { // checksums buildChecksums(); - // Build latest changelog - latestChangelog(); - // Finalize Message print .line() @@ -130,9 +127,7 @@ component { ) .toConsole(); - // Prepare exports directory - variables.exportsDir = variables.artifactsDir & "/#projectName#/#arguments.version#"; - directoryCreate( variables.exportsDir, true, true ); + ensureExportDir( argumentCollection = arguments ); // Project Build Dir variables.projectBuildDir = variables.buildDir & "/#projectName#"; @@ -200,11 +195,12 @@ component { version = "1.0.0", outputDir = ".tmp/apidocs" ){ + ensureExportDir( argumentCollection = arguments ); + // Create project mapping fileSystemUtil.createMapping( arguments.projectName, variables.cwd ); // Generate Docs print.greenLine( "Generating API Docs, please wait..." ).toConsole(); - directoryCreate( arguments.outputDir, true, true ); command( "docbox generate" ) .params( @@ -228,27 +224,6 @@ component { ); } - /** - * Build the latest changelog file: changelog-latest.md - */ - function latestChangelog(){ - print.blueLine( "Building latest changelog..." ).toConsole(); - - if ( !fileExists( variables.cwd & "changelog.md" ) ) { - return error( "Cannot continue building, changelog.md file doesn't exist!" ); - } - - fileWrite( - variables.cwd & "changelog-latest.md", - fileRead( variables.cwd & "changelog.md" ).split( "----" )[ 2 ].trim() & chr( 13 ) & chr( 10 ) - ); - - print - .greenLine( "Latest changelog file created at `changelog-latest.md`" ) - .line() - .line( fileRead( variables.cwd & "changelog-latest.md" ) ); - } - /********************************************* PRIVATE HELPERS *********************************************/ /** @@ -315,4 +290,18 @@ component { return ( createObject( "java", "java.lang.System" ).getProperty( "cfml.cli.exitCode" ) ?: 0 ); } + /** + * Ensure the export directory exists at artifacts/NAME/VERSION/ + */ + private function ensureExportDir( + required projectName, + version = "1.0.0" + ){ + if ( structKeyExists( variables, "exportsDir" ) && directoryExists( variables.exportsDir ) ){ + return; + } + // Prepare exports directory + variables.exportsDir = variables.artifactsDir & "/#projectName#/#arguments.version#"; + directoryCreate( variables.exportsDir, true, true ); + } } diff --git a/changelog.md b/changelog.md index 258cd76..f77c6a6 100644 --- a/changelog.md +++ b/changelog.md @@ -9,8 +9,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- New `LuceeSqlCollector` you can use to profile all SQL calls in Lucee +- New `luceeSql` configuration to control the Lucee SQL calls collector +- Changed the `instance` argument to `any` in the `debuggerService.openInEditorURL` to allow for a flat representational string of the URL to open in the editor. + ### Fixed +- Dumb whitespace added by CFML engines when doing inline `
#method()#
` calls. - Better error handling when Debugger assets are not compiled instead of a cryptic error message: `The parameter [str] to function [closure_m] is required but was not passed in.` diff --git a/handlers/Main.cfc b/handlers/Main.cfc index b80361b..89ea51c 100644 --- a/handlers/Main.cfc +++ b/handlers/Main.cfc @@ -91,9 +91,8 @@ component extends="coldbox.system.RestHandler" { } ); } catch ( any e ) { - var eMessage = "Error rendering the ColdBox Debugger: #e.message & e.detail#"; - log.error( eMessage, e ) - return eMessage; + writeDump( var = e, top = 5 ); + abort; } } diff --git a/interceptors/LuceeSqlCollector.cfc b/interceptors/LuceeSqlCollector.cfc new file mode 100644 index 0000000..04b274f --- /dev/null +++ b/interceptors/LuceeSqlCollector.cfc @@ -0,0 +1,70 @@ +/** + * Lucee SQL Collector Interecptor + * Requires debug mode and database activity to be turned on. Just add the following to your .cfconfig.json + * . + *
+ * "debuggingDBEnabled":"true",
+ * "debuggingEnabled":"true",
+ * "debuggingQueryUsageEnabled":"false", // Extra Info
+ * 
+ */ +component extends="coldbox.system.Interceptor" { + + // DI + property name="debuggerService" inject="debuggerService@cbdebugger"; + property name="debuggerConfig" inject="coldbox:moduleSettings:cbdebugger"; + + /** + * Listen to when the tracker gets created + */ + function onDebuggerRequestTrackerCreation( event, interceptData, rc, prc ){ + // prep collector + arguments.interceptData.requestTracker[ "cfQueries" ] = { + "all" : [], + "grouped" : {}, + "totalQueries" : 0, + "totalExecutionTime" : 0 + }; + } + + /** + * Listen when request tracker is being recorded + */ + function onDebuggerProfilerRecording( event, interceptData, rc, prc ){ + var requestTracker = arguments.interceptData.requestTracker; + + // Get the query tracker data + requestTracker.cfQueries.all = getPageContext() + .getDebugger() + .getQueries() + .map( ( row ) => { + return { + "startTime" : row.getStartTime(), + "datasource" : row.getDatasource(), + "recordCount" : row.getRecordCount(), + "executionTime" : row.getExecutionTime(), + "sql" : variables.debuggerConfig.luceeSQL.logParams ? row.getSql().toString() : row + .getSql() + .getSqlString(), + "src" : row.getTemplateLine().toString() + } + } ); + + // Process grouped sql + requestTracker.cfQueries.all.each( ( row ) => { + var sqlHash = hash( row.sql ); + + if ( !requestTracker.cfQueries.grouped.keyExists( sqlHash ) ) { + requestTracker.cfQueries.grouped[ sqlHash ] = { "sql" : row.sql, "count" : 0, "records" : [] }; + } + + requestTracker.cfqueries.grouped[ sqlHash ].count++; + requestTracker.cfqueries.grouped[ sqlHash ].records.append( row ); + } ); + + // Store total number of queries executed + requestTracker.cfQueries[ "totalQueries" ] = requestTracker.cfQueries.all.len(); + requestTracker.cfQueries[ "totalExecutionTime" ] = requestTracker.cfQueries.all.reduce( ( total, q ) => arguments.total + ( arguments.q.executionTime ), 0 ); + } + +} diff --git a/models/DebuggerService.cfc b/models/DebuggerService.cfc index aafe1ad..5551fb1 100755 --- a/models/DebuggerService.cfc +++ b/models/DebuggerService.cfc @@ -593,6 +593,19 @@ component return getCurrentThread().getName(); } + /** + * Converts epoch milliseconds to a date time object + * + * @epoch The epoch to convert, must be in milliseconds + */ + function fromEpoch( required epoch ){ + return dateAdd( + "s", + arguments.epoch / 1000, + dateConvert( "utc2local", "January 1 1970 00:00 " ) + ); + } + /** * Process Stack trace for errors * @@ -608,11 +621,18 @@ component * Compose a screen for a file to open in an editor * * @event The request context - * @instance An instance of a tag context array + * @instance An instance of a tag context array { template, line } * * @return The string for the IDE */ - function openInEditorURL( required event, required struct instance ){ + function openInEditorURL( required event, required instance ){ + if ( isSimpleValue( arguments.instance ) ) { + arguments.instance = { + template : arguments.instance.getToken( 1, ":" ), + line : arguments.instance.getToken( 2, ":" ) + }; + } + return getExceptionBean().openInEditorURL( argumentCollection = arguments ); } diff --git a/models/JVMUtil.cfc b/models/JVMUtil.cfc new file mode 100644 index 0000000..7b27a6f --- /dev/null +++ b/models/JVMUtil.cfc @@ -0,0 +1,47 @@ +component singleton{ + + /** + * Get the current request's thread stack + */ + array function getThreadInfo(){ + // Get the ThreadMXBean instance + var threadMXBean = createObject( "java", "java.lang.management.ManagementFactory" ).getThreadMXBean(); + // Set the option to include locked monitors and synchronizers + threadMXBean.setThreadContentionMonitoringEnabled( true) ; + // Get the thread information for each thread ID + var threadInfo = []; + return threadInfo.append( + threadMXBean.getThreadInfo( + threadMXBean.getAllThreadIds(), + createObject( "java", "java.lang.Integer" ).MAX_VALUE + ), + true + ); + } + + /** + * Generate a heap dump and store it at the given directory path + * The generated heap dump will be named with the following pattern:
cbdebugger-heapdump-mmm-dd-yyyy_HHnnss_l.hprof
+ * + * @directoryPath The directory path to store the heap dump, must be absolute + */ + void function generateHeapDump( required directoryPath ){ + // Create it if it doesn't exist + if( !directoryExists( arguments.directoryPath ) ){ + directoryCreate( arguments.directoryPath ); + } + + // Get the HotSpotDiagnosticMXBean instance + var ManagementFactory = createObject( "java", "java.lang.management.ManagementFactory" ); + var HotSpotDiagnosticMXBeanClass = createObject( "java", "com.sun.management.HotSpotDiagnosticMXBean" ).getClass(); + var mBeanServer = ManagementFactory.getPlatformMBeanServer(); + var dumpFilePath = arguments.directoryPath & "/cbdebugger-heapdump-#dateTimeFormat( now(), "mmm-dd-yyyy_HHnnss_l" )#.hprof"; + + ManagementFactory.newPlatformMXBeanProxy( + mBeanServer, + "com.sun.management:type=HotSpotDiagnostic", + HotSpotDiagnosticMXBeanClass.getClass() + ).dumpHeap( dumpFilePath, javaCast( "boolean", true ) ); + } + +} diff --git a/readme.md b/readme.md index 4253624..6aea7ac 100644 --- a/readme.md +++ b/readme.md @@ -190,6 +190,13 @@ moduleSettings = { // Log the binding parameters logParams : true }, + // Lucee SQL Collector + luceeSql : { + enabled : true, + expanded : false, + // Log the binding parameters + logParams : true + }, // Async Manager Reporting async : { enabled : true, @@ -482,8 +489,31 @@ acfSql : { logParams : true }, ``` + **Note:** This feature works with `ColdFusion 2018+` and requires the `Database Activity` box to be checked in the ACF `Debugging & Logging` page. If using ColdFusion 2021, you will need the `CF debugger` module installed as well. You can use the ACF CLI package manager, or the CommandBox command of `cfpm install debugger`. If it is not installed, install it and then restart the server before using this module. +## Lucee SQL Tracking + +We have also created a `Lucee Sql` panel which will track all SQL calls made during your request. We offer the same grouped or timeline visualizer for all these sql calls and even the capability to track from where the calls where made from and open them in your favorite editor to the line number. All you have to do is activate it: + +```js +luceeSql : { + enabled : true, + expanded : false, + logParams : true +}, +``` + +> **IMPORTANT** Please note that to use this feature the engine must have two debugging settings enabled + +```json +"debuggingDBEnabled":"true", +"debuggingEnabled":"true", +``` + +You can easily add those to your `.cfconfig.json` or enable it under the `Debugging` panel in the Lucee Admin. + + ## Modules Panel

diff --git a/test-harness/.DS_Store b/test-harness/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0

Debugger

- \ No newline at end of file + diff --git a/views/main/panels/requestTracker/acfSqlPanel.cfm b/views/main/panels/requestTracker/acfSqlPanel.cfm index 37ac200..d0ff12b 100755 --- a/views/main/panels/requestTracker/acfSqlPanel.cfm +++ b/views/main/panels/requestTracker/acfSqlPanel.cfm @@ -155,9 +155,8 @@ > -
#sqlFormatter.format(
-											args.profiler.cfQueries.grouped[ sqlHash ].sql
-										)#
+ +
#withoutDumbWhitespace#
diff --git a/views/main/panels/requestTracker/acfSqlTable.cfm b/views/main/panels/requestTracker/acfSqlTable.cfm index b383857..d11aa44 100644 --- a/views/main/panels/requestTracker/acfSqlTable.cfm +++ b/views/main/panels/requestTracker/acfSqlTable.cfm @@ -78,7 +78,8 @@ > -
#args.sqlFormatter.format( q.body )#
+ +
#withoutDumbWhitespace#
diff --git a/views/main/panels/requestTracker/cbormPanel.cfm b/views/main/panels/requestTracker/cbormPanel.cfm index 61009fe..c950a08 100644 --- a/views/main/panels/requestTracker/cbormPanel.cfm +++ b/views/main/panels/requestTracker/cbormPanel.cfm @@ -152,9 +152,8 @@ > -
#ltrim(
-											sqlFormatter.format( args.profiler.cborm.grouped[ sqlHash ].sql )
-											)#
+ +
#withoutDumbWhitespace#
diff --git a/views/main/panels/requestTracker/cbormSqlTable.cfm b/views/main/panels/requestTracker/cbormSqlTable.cfm index 182bf09..b9003c2 100644 --- a/views/main/panels/requestTracker/cbormSqlTable.cfm +++ b/views/main/panels/requestTracker/cbormSqlTable.cfm @@ -71,7 +71,8 @@ > -
#args.sqlFormatter.format( q.sql )#
+ +
#withoutDumbWhitespace#
diff --git a/views/main/panels/requestTracker/luceeSqlPanel.cfm b/views/main/panels/requestTracker/luceeSqlPanel.cfm new file mode 100755 index 0000000..a712642 --- /dev/null +++ b/views/main/panels/requestTracker/luceeSqlPanel.cfm @@ -0,0 +1,275 @@ + + + + + sqlFormatter = args.debuggerService.getSqlFormatter(); + jsonFormatter = args.debuggerService.getjsonFormatter(); + appPath = getSetting( "ApplicationPath" ); + totalExecutionTime = numberFormat( args.profiler.cfQueries.totalExecutionTime / 1000000 ); + + + + +
+ +
+   + + + + Lucee Sql + + + + + + + + + + #args.profiler.cfQueries.totalQueries# + + + + + #totalExecutionTime# ms +
+ + +
+ + +
+
+ Total Queries: +
+ #args.profiler.cfQueries.totalQueries# +
+
+ +
+ Total Execution Time: +
+ #totalExecutionTime# ms +
+
+
+ + +
+ + + + + + +
+ + + +
+ No queries executed +
+ + +
+ + + + + + + + + + + + + + + + + + + +
CountQuery
+
+ #args.profiler.cfQueries.grouped[ sqlHash ].count# +
+
+ + + + + +
#withoutDumbWhitespace#
+
+
+ + + + + + + + + + + + + + + + + + + + +
TimestampExecution TimeDatasourceSource/Params
+ #timeFormat( + args.debuggerService.fromEpoch( q.startTime ), + "hh:MM:SS.l tt" + )# + + #numberFormat( q.executionTime / 1000000 )# ms + + #q.datasource# + + +
+ + Called From: + + + + + +
+ + #q.src# + +
+
+
+
+
+
+ + +
+ #view( + view : "main/panels/requestTracker/luceeSqlTable", + module : "cbdebugger", + args : { + sqlData : args.profiler.cfQueries.all, + debuggerService : args.debuggerService, + sqlFormatter : sqlFormatter, + jsonFormatter : jsonFormatter, + appPath : appPath + }, + prePostExempt : true + )# +
+ + +
+ #view( + view : "main/panels/requestTracker/luceeSqlTable", + module : "cbdebugger", + args : { + sqlData : args.profiler.cfQueries.all.sort( ( a, b ) => a.executionTime < b.executionTime ? 1 : -1 ), + debuggerService : args.debuggerService, + sqlFormatter : sqlFormatter, + jsonFormatter : jsonFormatter, + appPath : appPath + }, + prePostExempt : true + )# +
+
+
+ +
+ +
diff --git a/views/main/panels/requestTracker/luceeSqlTable.cfm b/views/main/panels/requestTracker/luceeSqlTable.cfm new file mode 100644 index 0000000..236d557 --- /dev/null +++ b/views/main/panels/requestTracker/luceeSqlTable.cfm @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + +
TimestampExecution TimeDatasourceQuery
+ #timeFormat( + args.debuggerService.fromEpoch( q.startTime ), + "hh:MM:SS.l tt" + )# + + #numberFormat( ( q.executionTime / 1000000 ) )# ms + + #q.datasource# + + +
+ + Called From: + + + + + +
+ + #q.src# + +
+
+
+ + + + + + + +
#withoutDumbWhitespace#
+
+
+
diff --git a/views/main/panels/requestTracker/qbPanel.cfm b/views/main/panels/requestTracker/qbPanel.cfm index 2d00ad8..3bf30d6 100755 --- a/views/main/panels/requestTracker/qbPanel.cfm +++ b/views/main/panels/requestTracker/qbPanel.cfm @@ -159,9 +159,8 @@ > -
#sqlFormatter.format(
-												args.profiler.qbQueries.grouped[ sqlHash ].sql
-											)#
+ +
#withoutDumbWhitespace#
diff --git a/views/main/panels/requestTracker/qbSqlTable.cfm b/views/main/panels/requestTracker/qbSqlTable.cfm index 4cc23c6..3dde4a5 100644 --- a/views/main/panels/requestTracker/qbSqlTable.cfm +++ b/views/main/panels/requestTracker/qbSqlTable.cfm @@ -63,7 +63,8 @@ > -
#args.sqlFormatter.format( q.sql )#
+ +
#withoutDumbWhitespace#
diff --git a/views/main/partials/profilerReport.cfm b/views/main/partials/profilerReport.cfm index cf0a3a6..fc85277 100644 --- a/views/main/partials/profilerReport.cfm +++ b/views/main/partials/profilerReport.cfm @@ -305,6 +305,22 @@ )# + + + + + #view( + view : "main/panels/requestTracker/luceeSqlPanel", + module : "cbdebugger", + args : { + profiler : args.profiler, + debuggerConfig : args.debuggerConfig, + debuggerService : args.debuggerService + }, + prePostExempt : true + )# + + From 718a73b159b14703aa34efd3186a6fbe0b5e1ab8 Mon Sep 17 00:00:00 2001 From: lmajano Date: Mon, 12 Jun 2023 15:41:19 +0000 Subject: [PATCH 12/45] Apply cfformat changes --- models/JVMUtil.cfc | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/models/JVMUtil.cfc b/models/JVMUtil.cfc index 7b27a6f..4657f6b 100644 --- a/models/JVMUtil.cfc +++ b/models/JVMUtil.cfc @@ -1,4 +1,4 @@ -component singleton{ +component singleton { /** * Get the current request's thread stack @@ -7,7 +7,7 @@ component singleton{ // Get the ThreadMXBean instance var threadMXBean = createObject( "java", "java.lang.management.ManagementFactory" ).getThreadMXBean(); // Set the option to include locked monitors and synchronizers - threadMXBean.setThreadContentionMonitoringEnabled( true) ; + threadMXBean.setThreadContentionMonitoringEnabled( true ); // Get the thread information for each thread ID var threadInfo = []; return threadInfo.append( @@ -27,21 +27,23 @@ component singleton{ */ void function generateHeapDump( required directoryPath ){ // Create it if it doesn't exist - if( !directoryExists( arguments.directoryPath ) ){ + if ( !directoryExists( arguments.directoryPath ) ) { directoryCreate( arguments.directoryPath ); } // Get the HotSpotDiagnosticMXBean instance - var ManagementFactory = createObject( "java", "java.lang.management.ManagementFactory" ); + var ManagementFactory = createObject( "java", "java.lang.management.ManagementFactory" ); var HotSpotDiagnosticMXBeanClass = createObject( "java", "com.sun.management.HotSpotDiagnosticMXBean" ).getClass(); - var mBeanServer = ManagementFactory.getPlatformMBeanServer(); - var dumpFilePath = arguments.directoryPath & "/cbdebugger-heapdump-#dateTimeFormat( now(), "mmm-dd-yyyy_HHnnss_l" )#.hprof"; + var mBeanServer = ManagementFactory.getPlatformMBeanServer(); + var dumpFilePath = arguments.directoryPath & "/cbdebugger-heapdump-#dateTimeFormat( now(), "mmm-dd-yyyy_HHnnss_l" )#.hprof"; - ManagementFactory.newPlatformMXBeanProxy( - mBeanServer, - "com.sun.management:type=HotSpotDiagnostic", - HotSpotDiagnosticMXBeanClass.getClass() - ).dumpHeap( dumpFilePath, javaCast( "boolean", true ) ); + ManagementFactory + .newPlatformMXBeanProxy( + mBeanServer, + "com.sun.management:type=HotSpotDiagnostic", + HotSpotDiagnosticMXBeanClass.getClass() + ) + .dumpHeap( dumpFilePath, javacast( "boolean", true ) ); } } From 504fc1c4930dfbf0349a07ef23d41f92a5a1768f Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Mon, 12 Jun 2023 18:13:42 +0200 Subject: [PATCH 13/45] - Ability to download a heap dump snapshot from the visualizer --- ModuleConfig.cfc | 1 + changelog.md | 1 + handlers/Main.cfc | 10 ++++ models/JVMUtil.cfc | 8 ++- views/main/panels/requestTrackerPanel.cfm | 65 +++++++++++++---------- 5 files changed, 54 insertions(+), 31 deletions(-) diff --git a/ModuleConfig.cfc b/ModuleConfig.cfc index e2c21d8..3ce15bc 100644 --- a/ModuleConfig.cfc +++ b/ModuleConfig.cfc @@ -125,6 +125,7 @@ component { router .route( "/" ) .to( "Main.index" ) + // Conventions .route( "/:action" ) .toHandler( "Main" ); ; diff --git a/changelog.md b/changelog.md index f77c6a6..bcf7a17 100644 --- a/changelog.md +++ b/changelog.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - New `LuceeSqlCollector` you can use to profile all SQL calls in Lucee - New `luceeSql` configuration to control the Lucee SQL calls collector - Changed the `instance` argument to `any` in the `debuggerService.openInEditorURL` to allow for a flat representational string of the URL to open in the editor. +- Ability to download a heap dump snapshot from the visualizer ### Fixed diff --git a/handlers/Main.cfc b/handlers/Main.cfc index 89ea51c..2125dd6 100644 --- a/handlers/Main.cfc +++ b/handlers/Main.cfc @@ -96,6 +96,16 @@ component extends="coldbox.system.RestHandler" { } } + /** + * Download a heapdump snapshot + */ + function heapDump( event, rc, prc ){ + event.sendFile( + file : getInstance( "JVMUtil@cbdebugger" ).generateHeapDump( getTempDirectory() ), + deleteFile : true + ); + } + /** * This action renders out the caching panel only */ diff --git a/models/JVMUtil.cfc b/models/JVMUtil.cfc index 4657f6b..e7aabce 100644 --- a/models/JVMUtil.cfc +++ b/models/JVMUtil.cfc @@ -24,8 +24,10 @@ component singleton { * The generated heap dump will be named with the following pattern:
cbdebugger-heapdump-mmm-dd-yyyy_HHnnss_l.hprof
* * @directoryPath The directory path to store the heap dump, must be absolute + * + * @return The absolute path to the generated heap dump */ - void function generateHeapDump( required directoryPath ){ + string function generateHeapDump( required directoryPath ){ // Create it if it doesn't exist if ( !directoryExists( arguments.directoryPath ) ) { directoryCreate( arguments.directoryPath ); @@ -41,9 +43,11 @@ component singleton { .newPlatformMXBeanProxy( mBeanServer, "com.sun.management:type=HotSpotDiagnostic", - HotSpotDiagnosticMXBeanClass.getClass() + HotSpotDiagnosticMXBeanClass ) .dumpHeap( dumpFilePath, javacast( "boolean", true ) ); + + return dumpFilePath; } } diff --git a/views/main/panels/requestTrackerPanel.cfm b/views/main/panels/requestTrackerPanel.cfm index c5a7933..8a45f0d 100755 --- a/views/main/panels/requestTrackerPanel.cfm +++ b/views/main/panels/requestTrackerPanel.cfm @@ -119,6 +119,42 @@ + + + + + + + + + @@ -133,35 +169,6 @@ - - - - - - - - - - From 0929fdb04af5e51de931c5e6c987548ca475d678 Mon Sep 17 00:00:00 2001 From: lmajano Date: Mon, 12 Jun 2023 16:14:22 +0000 Subject: [PATCH 14/45] Apply cfformat changes --- handlers/Main.cfc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/handlers/Main.cfc b/handlers/Main.cfc index 2125dd6..fed94c9 100644 --- a/handlers/Main.cfc +++ b/handlers/Main.cfc @@ -101,8 +101,8 @@ component extends="coldbox.system.RestHandler" { */ function heapDump( event, rc, prc ){ event.sendFile( - file : getInstance( "JVMUtil@cbdebugger" ).generateHeapDump( getTempDirectory() ), - deleteFile : true + file : getInstance( "JVMUtil@cbdebugger" ).generateHeapDump( getTempDirectory() ), + deleteFile: true ); } From 5c721008b26cbb5bfcf793b848fdb903a298a047 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Tue, 13 Jun 2023 22:27:59 +0200 Subject: [PATCH 15/45] cb version --- test-harness/box.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-harness/box.json b/test-harness/box.json index 4de8f82..5d4359f 100644 --- a/test-harness/box.json +++ b/test-harness/box.json @@ -5,7 +5,7 @@ "private":true, "description":"", "dependencies":{ - "coldbox":"be", + "coldbox":"^7.0.0", "quick":"^4.2.4", "cborm":"^4.0.0" }, From d75fe011564ea6560fd449101868a322e59922ca Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Tue, 13 Jun 2023 23:26:59 +0200 Subject: [PATCH 16/45] verify if you don't have db activity or debug enabled, so you can enable it --- views/main/panels/requestTracker/luceeSqlPanel.cfm | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/views/main/panels/requestTracker/luceeSqlPanel.cfm b/views/main/panels/requestTracker/luceeSqlPanel.cfm index a712642..c48ec9a 100755 --- a/views/main/panels/requestTracker/luceeSqlPanel.cfm +++ b/views/main/panels/requestTracker/luceeSqlPanel.cfm @@ -111,6 +111,17 @@ + + +
+ It seems you don't have Lucee debugging enabled, please enable it! +
+"debuggingDBEnabled":"true",
+"debuggingEnabled":"true",
+
+
+
+
From 5265f79e0262d8ce05d1bd0abb0493d6761b22f8 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Fri, 16 Jun 2023 16:12:33 +0200 Subject: [PATCH 17/45] debugging keys for cfconfig --- .cfconfig.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.cfconfig.json b/.cfconfig.json index d4130d7..0168b5b 100644 --- a/.cfconfig.json +++ b/.cfconfig.json @@ -1,6 +1,8 @@ { "adminPassword" : "coldbox", - "debuggingEnabled":true, + "debuggingDBEnabled":"true", + "debuggingEnabled":"true", + "debuggingShowDatabase" : true, "debuggingReportExecutionTimes":false, "disableInternalCFJavaComponents":false, "inspectTemplate":"always", From 08cc3da3aaf0e238b2a15bec1df56a47f9c3b64c Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Fri, 16 Jun 2023 16:12:42 +0200 Subject: [PATCH 18/45] adobe 2023 --- .github/workflows/tests.yml | 10 +++++----- server-adobe@2023.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5a3e701..9271bb2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -18,13 +18,10 @@ jobs: strategy: fail-fast: false matrix: - cfengine: [ "lucee@5", "adobe@2018", "adobe@2021" ] - coldboxVersion: [ "^6.0.0" ] + cfengine: [ "lucee@5", "adobe@2018", "adobe@2021", "adobe@2023" ] + coldboxVersion: [ "^6.0.0", "^7.0.0" ] experimental: [ false ] include: - - cfengine: "adobe@2023" - coldboxVersion: "^6.0.0" - experimental: true - coldboxVersion: "be" cfengine: "lucee@5" experimental: true @@ -34,6 +31,9 @@ jobs: - coldboxVersion: "be" cfengine: "adobe@2021" experimental: true + - coldboxVersion: "be" + cfengine: "adobe@2023" + experimental: true steps: - name: Checkout Repository uses: actions/checkout@v3 diff --git a/server-adobe@2023.json b/server-adobe@2023.json index b7463e6..f051571 100644 --- a/server-adobe@2023.json +++ b/server-adobe@2023.json @@ -2,7 +2,7 @@ "name":"cbdebugger-adobe@2023", "app":{ "serverHomeDirectory":".engine/adobe2023", - "cfengine":"adobe@2023.0.0-beta.1" + "cfengine":"adobe@2023" }, "web":{ "http":{ From 22bdd59abba2da190fc12944a1f68fd85fc04717 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Fri, 16 Jun 2023 16:12:49 +0200 Subject: [PATCH 19/45] more debugging --- test-harness/config/Coldbox.cfc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-harness/config/Coldbox.cfc b/test-harness/config/Coldbox.cfc index f1616e7..93b77b3 100644 --- a/test-harness/config/Coldbox.cfc +++ b/test-harness/config/Coldbox.cfc @@ -86,7 +86,7 @@ // How many tracking profilers to keep in stack: Default is to monitor the last 20 requests maxProfilers : 25, // If enabled, the debugger will monitor the creation time of CFC objects via WireBox - profileWireBoxObjectCreation : false, + profileWireBoxObjectCreation : true, // Profile model objects annotated with the `profile` annotation profileObjects : true, // If enabled, will trace the results of any methods that are being profiled From 2e327af26e4dd35cd6206e82f6595485d57c1c28 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Mon, 19 Jun 2023 21:42:39 +0200 Subject: [PATCH 20/45] add new data action --- test-harness/handlers/Main.cfc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test-harness/handlers/Main.cfc b/test-harness/handlers/Main.cfc index b4578fb..496906a 100644 --- a/test-harness/handlers/Main.cfc +++ b/test-harness/handlers/Main.cfc @@ -98,6 +98,14 @@ component { event.renderData( data = "

Hello

" ); } + any function data( event, rc, prc ){ + return [ + { id = 1, name = "Bob" }, + { id = 2, name = "Sam" }, + { id = 3, name = "Joe" } + ]; + } + /** * error */ From 13ff5a5731515e9b61ae2dc4725c1437a7c80d7d Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Mon, 19 Jun 2023 21:54:18 +0200 Subject: [PATCH 21/45] - Updated test harness UI to make it easier to create debugging events --- changelog.md | 4 + resources/assets/images/CBDebugger-logo.png | Bin 0 -> 29378 bytes resources/assets/images/CBDebugger-logo.svg | 1 + test-harness/box.json | 8 +- test-harness/config/Coldbox.cfc | 2 +- .../includes/images/CBDebugger-logo.png | Bin 0 -> 29378 bytes .../includes/images/CBDebugger-logo.svg | 1 + .../includes/images/CBDebugger300.png | Bin 0 -> 12840 bytes test-harness/includes/js/color-modes.js | 86 ++++++++ test-harness/layouts/Main.cfm | 195 +++++++++++++++++- 10 files changed, 290 insertions(+), 7 deletions(-) create mode 100644 resources/assets/images/CBDebugger-logo.png create mode 100644 resources/assets/images/CBDebugger-logo.svg create mode 100644 test-harness/includes/images/CBDebugger-logo.png create mode 100644 test-harness/includes/images/CBDebugger-logo.svg create mode 100644 test-harness/includes/images/CBDebugger300.png create mode 100644 test-harness/includes/js/color-modes.js diff --git a/changelog.md b/changelog.md index bcf7a17..5e4eed3 100644 --- a/changelog.md +++ b/changelog.md @@ -16,6 +16,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Changed the `instance` argument to `any` in the `debuggerService.openInEditorURL` to allow for a flat representational string of the URL to open in the editor. - Ability to download a heap dump snapshot from the visualizer +### Improved + +- Updated test harness UI to make it easier to create debugging events + ### Fixed - Dumb whitespace added by CFML engines when doing inline `
#method()#
` calls. diff --git a/resources/assets/images/CBDebugger-logo.png b/resources/assets/images/CBDebugger-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f01ed204724572ae5354e6ec77210f4d8e12228e GIT binary patch literal 29378 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 CMd4)t literal 0 HcmV?d00001 diff --git a/resources/assets/images/CBDebugger-logo.svg b/resources/assets/images/CBDebugger-logo.svg new file mode 100644 index 0000000..19f32f0 --- /dev/null +++ b/resources/assets/images/CBDebugger-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test-harness/box.json b/test-harness/box.json index 5d4359f..67fc0b8 100644 --- a/test-harness/box.json +++ b/test-harness/box.json @@ -7,7 +7,9 @@ "dependencies":{ "coldbox":"^7.0.0", "quick":"^4.2.4", - "cborm":"^4.0.0" + "cborm":"^4.0.0", + "cbmailservices":"^2.7.1+112", + "hyper":"^7.1.0" }, "devDependencies":{ "testbox":"*" @@ -16,6 +18,8 @@ "coldbox":"coldbox/", "testbox":"testbox/", "quick":"modules/quick/", - "cborm":"modules/cborm/" + "cborm":"modules/cborm/", + "cbmailservices":"modules/cbmailservices/", + "hyper":"modules/hyper/" } } diff --git a/test-harness/config/Coldbox.cfc b/test-harness/config/Coldbox.cfc index 93b77b3..a8ce526 100644 --- a/test-harness/config/Coldbox.cfc +++ b/test-harness/config/Coldbox.cfc @@ -94,7 +94,7 @@ // Profile Custom or Core interception points profileInterceptions : true, // By default all interception events are excluded, you must include what you want to profile - includedInterceptions : [ "ORMPostLoad", "ORMPostNew" ], + includedInterceptions : [ "ORMPostNew" ], // Control the execution timers executionTimers : { expanded : true, diff --git a/test-harness/includes/images/CBDebugger-logo.png b/test-harness/includes/images/CBDebugger-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f01ed204724572ae5354e6ec77210f4d8e12228e GIT binary patch literal 29378 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 CMd4)t literal 0 HcmV?d00001 diff --git a/test-harness/includes/images/CBDebugger-logo.svg b/test-harness/includes/images/CBDebugger-logo.svg new file mode 100644 index 0000000..19f32f0 --- /dev/null +++ b/test-harness/includes/images/CBDebugger-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test-harness/includes/images/CBDebugger300.png b/test-harness/includes/images/CBDebugger300.png new file mode 100644 index 0000000000000000000000000000000000000000..d5cd6f710c22467815c045f465c66af68be37445 GIT binary patch literal 12840 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 literal 0 HcmV?d00001 diff --git a/test-harness/includes/js/color-modes.js b/test-harness/includes/js/color-modes.js new file mode 100644 index 0000000..5e7559f --- /dev/null +++ b/test-harness/includes/js/color-modes.js @@ -0,0 +1,86 @@ +/*! + * Color mode toggler for Bootstrap's docs (https://getbootstrap.com/) + * Copyright 2011-2023 The Bootstrap Authors + * Licensed under the Creative Commons Attribution 3.0 Unported License. + */ + +(() => { + 'use strict' + + const getStoredTheme = () => localStorage.getItem('theme') + const setStoredTheme = theme => localStorage.setItem('theme', theme) + + const getPreferredTheme = () => { + const storedTheme = getStoredTheme() + if (storedTheme) + { + return storedTheme + } + + return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' + } + + const setTheme = theme => { + if (theme === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches) + { + document.documentElement.setAttribute('data-bs-theme', 'dark') + } else + { + document.documentElement.setAttribute('data-bs-theme', theme) + } + } + + setTheme(getPreferredTheme()) + + const showActiveTheme = (theme, focus = false) => { + const themeSwitcher = document.querySelector('#bd-theme') + + if (!themeSwitcher) + { + return + } + + const themeSwitcherText = document.querySelector('#bd-theme-text') + const activeThemeIcon = document.querySelector('.theme-icon-active use') + const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`) + const svgOfActiveBtn = btnToActive.querySelector('svg use').getAttribute('href') + + document.querySelectorAll('[data-bs-theme-value]').forEach(element => { + element.classList.remove('active') + element.setAttribute('aria-pressed', 'false') + }) + + btnToActive.classList.add('active') + btnToActive.setAttribute('aria-pressed', 'true') + activeThemeIcon.setAttribute('href', svgOfActiveBtn) + const themeSwitcherLabel = `${themeSwitcherText.textContent} (${btnToActive.dataset.bsThemeValue})` + themeSwitcher.setAttribute('aria-label', themeSwitcherLabel) + + if (focus) + { + themeSwitcher.focus() + } + } + + window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { + const storedTheme = getStoredTheme() + if (storedTheme !== 'light' && storedTheme !== 'dark') + { + setTheme(getPreferredTheme()) + } + }) + + window.addEventListener('DOMContentLoaded', () => { + showActiveTheme(getPreferredTheme()) + + document.querySelectorAll('[data-bs-theme-value]') + .forEach(toggle => { + toggle.addEventListener('click', () => { + const theme = toggle.getAttribute('data-bs-theme-value') + setStoredTheme(theme) + setTheme(theme) + showActiveTheme(theme, true) + }) + }) + }) +})() diff --git a/test-harness/layouts/Main.cfm b/test-harness/layouts/Main.cfm index b50f9ab..a0909a8 100644 --- a/test-harness/layouts/Main.cfm +++ b/test-harness/layouts/Main.cfm @@ -1,6 +1,193 @@  -

Module Tester

-
- #view()# -
+ + + + + + + ColdBox Debugger + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + From 787fc022dccbad5000bc1e46716caba46b62147f Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Mon, 19 Jun 2023 22:15:40 +0200 Subject: [PATCH 22/45] more test scenarios --- test-harness/box.json | 6 ++- test-harness/handlers/Api.cfc | 39 +++++++++++++++++ test-harness/handlers/Main.cfc | 43 ++++++++++++++++++ test-harness/layouts/Main.cfm | 49 +-------------------- test-harness/views/main/hyperData.cfm | 4 ++ test-harness/views/main/index.cfm | 63 ++++++++++++++++++++++++++- 6 files changed, 153 insertions(+), 51 deletions(-) create mode 100644 test-harness/handlers/Api.cfc create mode 100644 test-harness/views/main/hyperData.cfm diff --git a/test-harness/box.json b/test-harness/box.json index 67fc0b8..bf9f0bf 100644 --- a/test-harness/box.json +++ b/test-harness/box.json @@ -9,7 +9,8 @@ "quick":"^4.2.4", "cborm":"^4.0.0", "cbmailservices":"^2.7.1+112", - "hyper":"^7.1.0" + "hyper":"^7.1.0", + "mockdatacfc":"^3.6.0+13" }, "devDependencies":{ "testbox":"*" @@ -20,6 +21,7 @@ "quick":"modules/quick/", "cborm":"modules/cborm/", "cbmailservices":"modules/cbmailservices/", - "hyper":"modules/hyper/" + "hyper":"modules/hyper/", + "mockdatacfc":"modules/mockdatacfc/" } } diff --git a/test-harness/handlers/Api.cfc b/test-harness/handlers/Api.cfc new file mode 100644 index 0000000..99a9889 --- /dev/null +++ b/test-harness/handlers/Api.cfc @@ -0,0 +1,39 @@ +component extends="coldbox.system.RestHandler"{ + + any function index( event, rc, prc ){ + sleep( randRange(100,2000 ) ); + event.getResponse() + .setData( + getInstance( "MockData@MockDataCFC" ) + .mock( + $num = "rnd:10:20", + name = "name", + id = "uuid", + email = "email", + biography = "lorem", + createdDate = "datetime", + updatedDate = "datetime", + profileUrl = "imageURL" + ) + ); + } + + any function person( event, rc, prc ){ + sleep( randRange(100,2000 ) ); + event.getResponse() + .setData( + getInstance( "MockData@MockDataCFC" ) + .mock( + $returnType = "struct", + name = "name", + id = "uuid", + email = "email", + biography = "lorem", + createdDate = "datetime", + updatedDate = "datetime", + profileUrl = "imageURL" + ) + ); + } + +} diff --git a/test-harness/handlers/Main.cfc b/test-harness/handlers/Main.cfc index 496906a..7a075d2 100644 --- a/test-harness/handlers/Main.cfc +++ b/test-harness/handlers/Main.cfc @@ -6,6 +6,7 @@ component { property name="qb" inject="queryBuilder@qb"; property name="roleService" inject="entityService:Role"; property name="userService" inject="entityService:User"; + property name="hyper" inject="HyperBuilder@hyper"; /** @@ -106,6 +107,48 @@ component { ]; } + function hyperData1( event, rc, prc ){ + prc.data = hyper + .setMethod( "GET" ) + .setUrl( event.buildLink( "/api/index" ) ) + .withHeaders( { + "Authorization" = "Bearer #createUUID()#", + "Accept" = "application/json", + "Test" = "test", + "When" = now() + } ) + .setBody( { + title : "Hello World", + } ) + .send(); + event.setView( "main/hyperData" ); + } + + function hyperData2( event, rc, prc ){ + prc.data = hyper + .setMethod( "GET" ) + .setUrl( event.buildLink( "/api/person" ) ) + .withHeaders( { + "Authorization" = "Bearer #createUUID()#", + "Accept" = "application/json", + "Test" = "test", + "When" = now() + } ) + .setBody( { + title : "Hello World", + } ) + .send(); + event.setView( "main/hyperData" ); + } + + function hyperInvalidUrl( event, rc, prc ){ + prc.data = hyper + .setMethod( "GET" ) + .setUrl( "http://lolcalhost:3234223333/api/index" ) + .send(); + event.setView( "main/hyperData" ); + } + /** * error */ diff --git a/test-harness/layouts/Main.cfm b/test-harness/layouts/Main.cfm index a0909a8..378fb4f 100644 --- a/test-harness/layouts/Main.cfm +++ b/test-harness/layouts/Main.cfm @@ -131,54 +131,7 @@
- - -
-
-

Debugging Events

-

- Use the links below to generate debugging data -

- -
-
+ #view()#
diff --git a/test-harness/views/main/hyperData.cfm b/test-harness/views/main/hyperData.cfm new file mode 100644 index 0000000..0221e7b --- /dev/null +++ b/test-harness/views/main/hyperData.cfm @@ -0,0 +1,4 @@ + +

Hyper Data

+ +
diff --git a/test-harness/views/main/index.cfm b/test-harness/views/main/index.cfm index 615d4c7..0dc9279 100644 --- a/test-harness/views/main/index.cfm +++ b/test-harness/views/main/index.cfm @@ -1,3 +1,64 @@ -

Debugger

+ + +
+
+

Debugging Events

+

+ Use the links below to generate debugging data +

+ +
+
From 4ac9ca659517b96b06cc47836a3ae26af855fae9 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Tue, 20 Jun 2023 23:00:50 +0200 Subject: [PATCH 23/45] - New fast and furious and tiny SQL/JSON Formatter --- box.json | 4 -- changelog.md | 1 + models/DebuggerService.cfc | 3 +- models/Formatter.cfc | 67 +++++++++++++++++++ .../panels/requestTracker/acfSqlPanel.cfm | 13 ++-- .../panels/requestTracker/acfSqlTable.cfm | 4 +- .../main/panels/requestTracker/cbormPanel.cfm | 13 ++-- .../panels/requestTracker/cbormSqlTable.cfm | 4 +- .../panels/requestTracker/coldboxPanel.cfm | 5 +- .../requestTracker/httpRequestPanel.cfm | 9 ++- .../panels/requestTracker/luceeSqlPanel.cfm | 11 ++- .../panels/requestTracker/luceeSqlTable.cfm | 2 +- views/main/panels/requestTracker/qbPanel.cfm | 13 ++-- .../main/panels/requestTracker/qbSqlTable.cfm | 4 +- 14 files changed, 101 insertions(+), 52 deletions(-) create mode 100644 models/Formatter.cfc diff --git a/box.json b/box.json index 9d0b321..523c7f1 100644 --- a/box.json +++ b/box.json @@ -25,8 +25,6 @@ "Luis Majano " ], "dependencies":{ - "JSONPrettyPrint":"^1.4.1", - "sqlformatter":"^1.0.1" }, "devDependencies":{ "commandbox-cfformat":"*", @@ -67,7 +65,5 @@ "logs:2021":"server log name=cbdebugger-adobe@2021 --follow" }, "installPaths":{ - "JSONPrettyPrint":"modules/JSONPrettyPrint/", - "sqlformatter":"modules/sqlformatter/" } } diff --git a/changelog.md b/changelog.md index 5e4eed3..15bba33 100644 --- a/changelog.md +++ b/changelog.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- New fast and furious and tiny SQL/JSON Formatter - New `LuceeSqlCollector` you can use to profile all SQL calls in Lucee - New `luceeSql` configuration to control the Lucee SQL calls collector - Changed the `instance` argument to `any` in the `debuggerService.openInEditorURL` to allow for a flat representational string of the URL to open in the editor. diff --git a/models/DebuggerService.cfc b/models/DebuggerService.cfc index 5551fb1..1e9bddf 100755 --- a/models/DebuggerService.cfc +++ b/models/DebuggerService.cfc @@ -20,8 +20,7 @@ component property name="asyncManager" inject="coldbox:asyncManager"; property name="interceptorService" inject="coldbox:interceptorService"; property name="timerService" inject="provider:Timer@cbdebugger"; - property name="jsonFormatter" inject="provider:JSONPrettyPrint@JSONPrettyPrint"; - property name="sqlFormatter" inject="provider:Formatter@sqlformatter"; + property name="formatter" inject="provider:Formatter@cbdebugger"; /** * -------------------------------------------------------------------------- diff --git a/models/Formatter.cfc b/models/Formatter.cfc new file mode 100644 index 0000000..f4142ee --- /dev/null +++ b/models/Formatter.cfc @@ -0,0 +1,67 @@ +/** + * Basic sql + json formatter + * This will be removed once CB7 is the default, since it's included in the core. + */ +component singleton { + + variables.NEW_LINE = chr( 13 ) & chr( 10 ); + variables.TAB = chr( 9 ); + + /** + * Format an incoming sql string to a pretty version + * + * @target The target sql to prettify + * @return The prettified sql + */ + function prettySql( string target = "" ) { + var keywords = [ + "SELECT","FROM","WHERE","GROUP BY","HAVING","ORDER BY", + "INSERT INTO","UPDATE","DELETE","CREATE TABLE","ALTER TABLE","DROP TABLE", + "UNION" + ]; + var indentedKeywords = [ "JOIN", "LEFT JOIN", "INNER JOIN", "OUTER JOIN", "FULL JOIN" ]; + var indent = " "; + + return arguments.target + .listToArray( variables.NEW_LINE ) + .map( ( item ) => item.trim() ) + .map( ( item ) => item.reReplace( "(\s)*,(\s)*", ",#variables.NEW_LINE##indent#", "all" ) ) + .map( ( item ) => { + return item.reReplacenocase( "(\s)*(#keywords.toList( '|' )#)(\s)*", "\2#variables.NEW_LINE##indent#", "all" ) + }) + .map( ( item ) => { + return item.reReplacenocase( "(#indentedKeywords.toList( '|' )#)", "#variables.NEW_LINE##indent#\1", "all" ) + }) + .toList( variables.NEW_LINE ); + } + + /** + * Format an incoming json string to a pretty version + * + * @target The target json to prettify + * @return The prettified json + */ + string function prettyJson( string target = "" ){ + var padding = 0; + return arguments.target + .reReplace( + "([\{|\}|\[|\]|\(|\)|,])", + "\1#variables.NEW_LINE#", + "all" + ) + .reReplace( "(\]|\})#variables.NEW_LINE#", "#variables.NEW_LINE#\1", "all" ) + .listToArray( variables.NEW_LINE ) + .map( ( token ) => { + if ( token.reFind( "[\}|\)|\]]" ) && padding > 0 ) { + padding--; + }; + var newToken = repeatString( variables.TAB, padding ) & token.trim(); + if ( token.reFind( "[\{|\(|\[]" ) ) { + padding++; + }; + return newToken; + } ) + .toList( variables.NEW_LINE ); + } + +} diff --git a/views/main/panels/requestTracker/acfSqlPanel.cfm b/views/main/panels/requestTracker/acfSqlPanel.cfm index d0ff12b..8ddf323 100755 --- a/views/main/panels/requestTracker/acfSqlPanel.cfm +++ b/views/main/panels/requestTracker/acfSqlPanel.cfm @@ -2,8 +2,7 @@ - sqlFormatter = args.debuggerService.getSqlFormatter(); - jsonFormatter = args.debuggerService.getjsonFormatter(); + formatter = args.debuggerService.getFormatter(); appPath = getSetting( "ApplicationPath" ); @@ -155,7 +154,7 @@ > - +
#withoutDumbWhitespace#
@@ -229,7 +228,7 @@ > -
#jsonFormatter.formatJSON( json : q.attributes, spaceAfterColon : true )#
+
#formatter.prettyJson( json : q.attributes, spaceAfterColon : true )#
@@ -255,8 +254,7 @@ args : { sqlData : args.profiler.cfQueries.all, debuggerService : args.debuggerService, - sqlFormatter : sqlFormatter, - jsonFormatter : jsonFormatter, + formatter : formatter, appPath : appPath }, prePostExempt : true @@ -278,8 +276,7 @@ return executionTimeA < executionTimeB ? 1 : -1; } ), debuggerService : args.debuggerService, - sqlFormatter : sqlFormatter, - jsonFormatter : jsonFormatter, + formatter : formatter, appPath : appPath }, prePostExempt : true diff --git a/views/main/panels/requestTracker/acfSqlTable.cfm b/views/main/panels/requestTracker/acfSqlTable.cfm index d11aa44..c7178e1 100644 --- a/views/main/panels/requestTracker/acfSqlTable.cfm +++ b/views/main/panels/requestTracker/acfSqlTable.cfm @@ -78,7 +78,7 @@ > - +
#withoutDumbWhitespace#
@@ -101,7 +101,7 @@ > -
#args.jsonFormatter.formatJSON( json : q.attributes, spaceAfterColon : true )#
+
#args.formatter.prettyJson( json : q.attributes, spaceAfterColon : true )#
+ +
+ + + ColdBox Debugger Test Harness + +
+ +
+ + +
+
+

Debugging Events

+

+ Use the links below to generate debugging data +

+ +
+
+
+ +
+ Created by Ortus Solutions +
+
diff --git a/views/main/panels/requestTracker/cbormPanel.cfm b/views/main/panels/requestTracker/cbormPanel.cfm index c950a08..5d99cbe 100644 --- a/views/main/panels/requestTracker/cbormPanel.cfm +++ b/views/main/panels/requestTracker/cbormPanel.cfm @@ -2,8 +2,7 @@ - sqlFormatter = args.debuggerService.getSqlFormatter(); - jsonFormatter = args.debuggerService.getjsonFormatter(); + formatter = args.debuggerService.getFormatter(); appPath = getSetting( "ApplicationPath" ); @@ -152,7 +151,7 @@ > - +
#withoutDumbWhitespace#
@@ -230,7 +229,7 @@ > -
#jsonFormatter.formatJSON( json : q.params, spaceAfterColon : true )#
+
#formatter.prettyJson( json : q.params, spaceAfterColon : true )#
@@ -257,8 +256,7 @@ args : { sqlData : args.profiler.cborm.all, debuggerService : args.debuggerService, - sqlFormatter : sqlFormatter, - jsonFormatter : jsonFormatter, + formatter : formatter, appPath : appPath }, prePostExempt : true @@ -279,8 +277,7 @@ return a.executionTime < b.executionTime ? 1 : -1; } ), debuggerService : args.debuggerService, - sqlFormatter : sqlFormatter, - jsonFormatter : jsonFormatter, + formatter : formatter, appPath : appPath }, prePostExempt : true diff --git a/views/main/panels/requestTracker/cbormSqlTable.cfm b/views/main/panels/requestTracker/cbormSqlTable.cfm index b9003c2..906e083 100644 --- a/views/main/panels/requestTracker/cbormSqlTable.cfm +++ b/views/main/panels/requestTracker/cbormSqlTable.cfm @@ -71,7 +71,7 @@ > - +
#withoutDumbWhitespace#
@@ -94,7 +94,7 @@ > -
#args.jsonFormatter.formatJSON( json : q.params, spaceAfterColon : true )#
+
#args.formatter.prettyJson( json : q.params, spaceAfterColon : true )#
diff --git a/views/main/panels/requestTracker/coldboxPanel.cfm b/views/main/panels/requestTracker/coldboxPanel.cfm index 40c4bf1..b0e15fe 100644 --- a/views/main/panels/requestTracker/coldboxPanel.cfm +++ b/views/main/panels/requestTracker/coldboxPanel.cfm @@ -2,8 +2,7 @@ - sqlFormatter = args.debuggerService.getSqlFormatter(); - jsonFormatter = args.debuggerService.getjsonFormatter(); + formatter = args.debuggerService.getFormatter(); coldboxKeys = args.profiler.coldbox.keyArray(); coldboxKeys.sort( "textnocase" ); @@ -43,7 +42,7 @@
- #jsonFormatter.formatJSON( args.profiler.coldbox[ thisItem ] )# + #formatter.prettyJson( args.profiler.coldbox[ thisItem ] )# #args.profiler.coldbox[ thisItem ]# diff --git a/views/main/panels/requestTracker/httpRequestPanel.cfm b/views/main/panels/requestTracker/httpRequestPanel.cfm index b58b78b..bdbb2eb 100644 --- a/views/main/panels/requestTracker/httpRequestPanel.cfm +++ b/views/main/panels/requestTracker/httpRequestPanel.cfm @@ -2,8 +2,7 @@ - sqlFormatter = args.debuggerService.getSqlFormatter(); - jsonFormatter = args.debuggerService.getjsonFormatter(); + formatter = args.debuggerService.getFormatter();
-
#jsonFormatter.formatJSON( args.profiler.requestData.content )#
+
#formatter.prettyJson( args.profiler.requestData.content )#
#args.profiler.requestData.content# @@ -105,7 +104,7 @@
-
#jsonFormatter.formatJSON( args.profiler.formData )#
+
#formatter.prettyJson( args.profiler.formData )#
@@ -145,7 +144,7 @@ - #jsonFormatter.formatJSON( getToken( thisCookie, 2, "=" ) )# + #formatter.prettyJson( getToken( thisCookie, 2, "=" ) )# #getToken( thisCookie, 2, "=" )# diff --git a/views/main/panels/requestTracker/luceeSqlPanel.cfm b/views/main/panels/requestTracker/luceeSqlPanel.cfm index c48ec9a..a6e63dc 100755 --- a/views/main/panels/requestTracker/luceeSqlPanel.cfm +++ b/views/main/panels/requestTracker/luceeSqlPanel.cfm @@ -2,8 +2,7 @@ - sqlFormatter = args.debuggerService.getSqlFormatter(); - jsonFormatter = args.debuggerService.getjsonFormatter(); + formatter = args.debuggerService.getFormatter(); appPath = getSetting( "ApplicationPath" ); totalExecutionTime = numberFormat( args.profiler.cfQueries.totalExecutionTime / 1000000 ); @@ -167,7 +166,7 @@ > - +
#withoutDumbWhitespace#
@@ -252,8 +251,7 @@ args : { sqlData : args.profiler.cfQueries.all, debuggerService : args.debuggerService, - sqlFormatter : sqlFormatter, - jsonFormatter : jsonFormatter, + formatter : formatter, appPath : appPath }, prePostExempt : true @@ -271,8 +269,7 @@ args : { sqlData : args.profiler.cfQueries.all.sort( ( a, b ) => a.executionTime < b.executionTime ? 1 : -1 ), debuggerService : args.debuggerService, - sqlFormatter : sqlFormatter, - jsonFormatter : jsonFormatter, + formatter : formatter, appPath : appPath }, prePostExempt : true diff --git a/views/main/panels/requestTracker/luceeSqlTable.cfm b/views/main/panels/requestTracker/luceeSqlTable.cfm index 236d557..ee00890 100644 --- a/views/main/panels/requestTracker/luceeSqlTable.cfm +++ b/views/main/panels/requestTracker/luceeSqlTable.cfm @@ -77,7 +77,7 @@ > - +
#withoutDumbWhitespace#
diff --git a/views/main/panels/requestTracker/qbPanel.cfm b/views/main/panels/requestTracker/qbPanel.cfm index 3bf30d6..9901c22 100755 --- a/views/main/panels/requestTracker/qbPanel.cfm +++ b/views/main/panels/requestTracker/qbPanel.cfm @@ -2,8 +2,7 @@ - sqlFormatter = args.debuggerService.getSqlFormatter(); - jsonFormatter = args.debuggerService.getjsonFormatter(); + formatter = args.debuggerService.getFormatter(); isQuickInstalled = controller.getModuleService().isModuleRegistered( "quick" ); isQBInstalled = controller.getModuleService().isModuleRegistered( "qb" ); totalEntities = args.profiler.keyExists( "quick" ) ? args.profiler.quick.total : 0; @@ -159,7 +158,7 @@ > - +
#withoutDumbWhitespace#
@@ -229,7 +228,7 @@ > -
#jsonFormatter.formatJSON( json : q.params, spaceAfterColon : true )#
+
#formatter.prettyJson( json : q.params, spaceAfterColon : true )#
@@ -255,8 +254,7 @@ args : { sqlData : args.profiler.qbQueries.all, debuggerService : args.debuggerService, - sqlFormatter : sqlFormatter, - jsonFormatter : jsonFormatter, + formatter : formatter, appPath : appPath }, prePostExempt : true @@ -277,8 +275,7 @@ return a.executionTime < b.executionTime ? 1 : -1; } ), debuggerService : args.debuggerService, - sqlFormatter : sqlFormatter, - jsonFormatter : jsonFormatter, + formatter : formatter, appPath : appPath }, prePostExempt : true diff --git a/views/main/panels/requestTracker/qbSqlTable.cfm b/views/main/panels/requestTracker/qbSqlTable.cfm index 3dde4a5..bafb4a7 100644 --- a/views/main/panels/requestTracker/qbSqlTable.cfm +++ b/views/main/panels/requestTracker/qbSqlTable.cfm @@ -63,7 +63,7 @@ > - +
#withoutDumbWhitespace#
@@ -86,7 +86,7 @@ > -
#args.jsonFormatter.formatJSON( json : q.params, spaceAfterColon : true )#
+
#args.formatter.prettyJson( json : q.params, spaceAfterColon : true )#
From 8d966a11d8b76ee3829a5486681d5a2dfce20164 Mon Sep 17 00:00:00 2001 From: lmajano Date: Tue, 20 Jun 2023 21:01:30 +0000 Subject: [PATCH 24/45] Apply cfformat changes --- models/DebuggerService.cfc | 2 +- models/Formatter.cfc | 74 +++++++++++++++++++++++++++----------- 2 files changed, 55 insertions(+), 21 deletions(-) diff --git a/models/DebuggerService.cfc b/models/DebuggerService.cfc index 1e9bddf..49257b7 100755 --- a/models/DebuggerService.cfc +++ b/models/DebuggerService.cfc @@ -20,7 +20,7 @@ component property name="asyncManager" inject="coldbox:asyncManager"; property name="interceptorService" inject="coldbox:interceptorService"; property name="timerService" inject="provider:Timer@cbdebugger"; - property name="formatter" inject="provider:Formatter@cbdebugger"; + property name="formatter" inject="provider:Formatter@cbdebugger"; /** * -------------------------------------------------------------------------- diff --git a/models/Formatter.cfc b/models/Formatter.cfc index f4142ee..4f40935 100644 --- a/models/Formatter.cfc +++ b/models/Formatter.cfc @@ -5,40 +5,70 @@ component singleton { variables.NEW_LINE = chr( 13 ) & chr( 10 ); - variables.TAB = chr( 9 ); + variables.TAB = chr( 9 ); /** * Format an incoming sql string to a pretty version * * @target The target sql to prettify + * * @return The prettified sql */ - function prettySql( string target = "" ) { + function prettySql( string target = "" ){ var keywords = [ - "SELECT","FROM","WHERE","GROUP BY","HAVING","ORDER BY", - "INSERT INTO","UPDATE","DELETE","CREATE TABLE","ALTER TABLE","DROP TABLE", - "UNION" - ]; - var indentedKeywords = [ "JOIN", "LEFT JOIN", "INNER JOIN", "OUTER JOIN", "FULL JOIN" ]; - var indent = " "; + "SELECT", + "FROM", + "WHERE", + "GROUP BY", + "HAVING", + "ORDER BY", + "INSERT INTO", + "UPDATE", + "DELETE", + "CREATE TABLE", + "ALTER TABLE", + "DROP TABLE", + "UNION" + ]; + var indentedKeywords = [ + "JOIN", + "LEFT JOIN", + "INNER JOIN", + "OUTER JOIN", + "FULL JOIN" + ]; + var indent = " "; return arguments.target - .listToArray( variables.NEW_LINE ) - .map( ( item ) => item.trim() ) - .map( ( item ) => item.reReplace( "(\s)*,(\s)*", ",#variables.NEW_LINE##indent#", "all" ) ) - .map( ( item ) => { - return item.reReplacenocase( "(\s)*(#keywords.toList( '|' )#)(\s)*", "\2#variables.NEW_LINE##indent#", "all" ) - }) - .map( ( item ) => { - return item.reReplacenocase( "(#indentedKeywords.toList( '|' )#)", "#variables.NEW_LINE##indent#\1", "all" ) - }) - .toList( variables.NEW_LINE ); - } + .listToArray( variables.NEW_LINE ) + .map( ( item ) => item.trim() ) + .map( ( item ) => item.reReplace( + "(\s)*,(\s)*", + ",#variables.NEW_LINE##indent#", + "all" + ) ) + .map( ( item ) => { + return item.reReplacenocase( + "(\s)*(#keywords.toList( "|" )#)(\s)*", + "\2#variables.NEW_LINE##indent#", + "all" + ) + } ) + .map( ( item ) => { + return item.reReplacenocase( + "(#indentedKeywords.toList( "|" )#)", + "#variables.NEW_LINE##indent#\1", + "all" + ) + } ) + .toList( variables.NEW_LINE ); + } /** * Format an incoming json string to a pretty version * * @target The target json to prettify + * * @return The prettified json */ string function prettyJson( string target = "" ){ @@ -49,7 +79,11 @@ component singleton { "\1#variables.NEW_LINE#", "all" ) - .reReplace( "(\]|\})#variables.NEW_LINE#", "#variables.NEW_LINE#\1", "all" ) + .reReplace( + "(\]|\})#variables.NEW_LINE#", + "#variables.NEW_LINE#\1", + "all" + ) .listToArray( variables.NEW_LINE ) .map( ( token ) => { if ( token.reFind( "[\}|\)|\]]" ) && padding > 0 ) { From 00b89677d386adcebe8bd6eee9996cdf0c75959e Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Wed, 21 Jun 2023 16:51:40 +0200 Subject: [PATCH 25/45] chore: syntax update --- interceptors/CBOrmCollector.cfc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interceptors/CBOrmCollector.cfc b/interceptors/CBOrmCollector.cfc index 9d6f708..dd7b88b 100644 --- a/interceptors/CBOrmCollector.cfc +++ b/interceptors/CBOrmCollector.cfc @@ -1,5 +1,5 @@ /** - * CBOrm Collector Interecptor + * CBORM Collector Interecptor */ component extends="coldbox.system.Interceptor" { From 90ee9713222b456c272c2f333b37681f32af76b4 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Wed, 21 Jun 2023 16:52:55 +0200 Subject: [PATCH 26/45] feat: :zap: `Timer` can now add timers a-la-carte via the `add()` method --- changelog.md | 1 + models/Timer.cfc | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/changelog.md b/changelog.md index 15bba33..1b1b64e 100644 --- a/changelog.md +++ b/changelog.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- `Timer` can now add timers a-la-carte via the `add()` method - New fast and furious and tiny SQL/JSON Formatter - New `LuceeSqlCollector` you can use to profile all SQL calls in Lucee - New `luceeSql` configuration to control the Lucee SQL calls collector diff --git a/models/Timer.cfc b/models/Timer.cfc index fa77475..b09ed80 100755 --- a/models/Timer.cfc +++ b/models/Timer.cfc @@ -18,6 +18,44 @@ component accessors="true" singleton threadsafe { return this; } + /** + * Add a timer to the stack manually. You will need the label, executionTime and stoppedAt timestamps + * + * @label The label to use as a timer label + * @executionTime The execution time in ms to register + * @startedAt The date time the timer was started + * @stoppedAt The date time the timer was stopped + * @metadata A struct of metadata to store in the execution timer + * @parent An optional parent label + * @type The type of execution timed: request, view-render, layout-render, event, renderer + */ + function add( + required label, + required executionTime, + startedAt = now(), + stoppedat = now(), + struct metadata = {}, + parent = "", + type = "timer" + ){ + getTimers().insert( + arguments.label, + { + "id" : variables.debuggerService.randomUUID(), + "startedAt" : arguments.startedAt, + "startCount" : getTickCount(), + "method" : arguments.label, + "stoppedAt" : arguments.stoppedAt, + "executionTime" : arguments.executionTime, + "metadata" : arguments.metadata, + "parent" : arguments.parent, + "type" : arguments.type, + "times" : 1 + }, + true + ); + } + /** * Start a timer with a tracking label * From c6c527be31d662d07b3cb499c854dfab84439dd2 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Wed, 21 Jun 2023 16:54:01 +0200 Subject: [PATCH 27/45] feat: :sparkles: - New `HyperCollector` so you can now track hyper requests if enabled --- ModuleConfig.cfc | 22 +- changelog.md | 1 + interceptors/HyperCollector.cfc | 117 ++++++++ test-harness/config/Coldbox.cfc | 4 +- test-harness/layouts/Main.cfm | 10 +- test-harness/views/main/index.cfm | 2 +- .../requestTracker/debugTimersPanel.cfm | 7 +- .../main/panels/requestTracker/hyperPanel.cfm | 281 ++++++++++++++++++ .../requestTracker/hyperRequestTable.cfm | 115 +++++++ views/main/partials/profilerReport.cfm | 68 +++-- 10 files changed, 593 insertions(+), 34 deletions(-) create mode 100644 interceptors/HyperCollector.cfc create mode 100755 views/main/panels/requestTracker/hyperPanel.cfm create mode 100644 views/main/panels/requestTracker/hyperRequestTable.cfm diff --git a/ModuleConfig.cfc b/ModuleConfig.cfc index 3ce15bc..7d6b7a2 100644 --- a/ModuleConfig.cfc +++ b/ModuleConfig.cfc @@ -117,8 +117,15 @@ component { acfSql : { enabled : false, expanded : false, logParams : true }, // Lucee SQL Collector luceeSQL : { enabled : false, expanded : false, logParams : true }, - // Async Manager Reporting - async : { enabled : true, expanded : false } + // Async Manager Collector + async : { enabled : true, expanded : false }, + // Hyper Collector + hyper : { + enabled : false, + expanded : false, + logResponseData : false, + logRequestBody : false + } }; // Visualizer Route @@ -286,6 +293,17 @@ component { variables.settings.luceeSQL.enabled = false; } + /******************** Hyper COLLECTOR ************************************/ + + if ( variables.settings.hyper.enabled ) { + param variables.settings.hyper.logResponseData = false; + param variables.settings.hyper.logRequestBody = false; + interceptorService.registerInterceptor( + interceptorClass = "#moduleMapping#.interceptors.HyperCollector", + interceptorName = "HyperCollector@cbdebugger" + ); + } + // Announce debugger loaded interceptorService.announce( "onDebuggerLoad" ); } diff --git a/changelog.md b/changelog.md index 1b1b64e..d4d64b4 100644 --- a/changelog.md +++ b/changelog.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- New `HyperCollector` so you can now track hyper requests if enabled - `Timer` can now add timers a-la-carte via the `add()` method - New fast and furious and tiny SQL/JSON Formatter - New `LuceeSqlCollector` you can use to profile all SQL calls in Lucee diff --git a/interceptors/HyperCollector.cfc b/interceptors/HyperCollector.cfc new file mode 100644 index 0000000..90c2511 --- /dev/null +++ b/interceptors/HyperCollector.cfc @@ -0,0 +1,117 @@ +/** + * Copyright Since 2005 ColdBox Framework by Luis Majano and Ortus Solutions, Corp + * www.ortussolutions.com + * --- + * This interceptor collects information from hyper + */ +component extends="coldbox.system.Interceptor" { + + // DI + property name="debuggerService" inject="debuggerService@cbdebugger"; + property name="timerService" inject="timer@cbdebugger"; + property name="debuggerConfig" inject="coldbox:moduleSettings:cbdebugger"; + + /** + * Configure + */ + function configure(){ + } + + /** + * Listen to when the tracker gets created + */ + function onDebuggerRequestTrackerCreation( event, data, rc, prc ){ + arguments.data.requestTracker[ "hyper" ] = { "grouped" : {}, "all" : structNew( "ordered" ) }; + } + + /** + * Listen when request tracker is being recorded + */ + function onDebuggerProfilerRecording( event, data, rc, prc ){ + var requestTracker = arguments.data.requestTracker; + requestTracker.hyper[ "totalRequests" ] = requestTracker.hyper.all.len(); + requestTracker.hyper[ "totalExecutionTime" ] = requestTracker.hyper.all.reduce( ( total, k, v ) => { + return arguments.total + arguments.v.executionTime + }, 0 ); + } + + /** + * Listen before the request is processed + */ + function onHyperRequest( event, data, rc, prc ){ + // Get the request tracker so we can add our timing goodness! + var requestTracker = variables.debuggerService.getRequestTracker(); + + // Params just in case + param requestTracker.hyper = {}; + param requestTracker.hyper.grouped = {}; + param requestTracker.hyper.all = structNew( "ordered" ); + + // Store the request as started, to track cases where + // the request doesn't finish + requestTracker.hyper.all[ data.request.getRequestId() ] = { + "timestamp" : now(), + "executionTime" : 0, + "status" : "started", + "requestId" : data.request.getRequestId(), + "url" : data.request.getFullUrl(), + "request" : data.request + .getMemento() + .filter( ( key, value ) => key == "body" && debuggerConfig.hyper.logRequestBody || key != "body" ), + "response" : {}, + "caller" : variables.debuggerService.discoverCallingStack( "send" ) + }; + } + + /** + * Listen after the request is processed + */ + function onHyperResponse( event, data, rc, prc ){ + var requestTracker = variables.debuggerService.getRequestTracker(); + var thisRequest = arguments.data.response.getRequest(); + + // Store the request as finished + requestTracker.hyper.all[ thisRequest.getRequestId() ].append( { + "status" : "finished", + "executionTime" : data.response.getExecutionTime(), + "response" : data.response + .getMemento() + .filter( ( key, value ) => key == "data" && debuggerConfig.hyper.logResponseData || key != "data" ) + } ); + + // Grouping + var requestHash = hash( + thisRequest + .getMemento() + .filter( ( key, value ) => key != "requestID" ) + .toString() + ); + if ( !structKeyExists( requestTracker.hyper.grouped, requestHash ) ) { + requestTracker.hyper.grouped[ requestHash ] = { + "url" : thisRequest.getFullUrl(), + "method" : thisRequest.getMethod(), + "count" : 0, + "records" : [] + }; + } + requestTracker.hyper.grouped[ requestHash ].count++; + requestTracker.hyper.grouped[ requestHash ].records.append( thisRequest.getRequestId() ); + + // Store execution timer + variables.timerService.add( + label : "[Hyper Request] #data.response.getStatusCode()# <#thisRequest.getMethod()#>#thisRequest.getFullUrl()#", + executionTime: data.response.getExecutionTime(), + startedAt : data.response.getTimestamp(), + metadata : { + statusCode : data.response.getStatusCode(), + statusText : data.response.getStatusText(), + path : requestTracker.hyper.all[ thisRequest.getRequestId() ].caller.template, + line : requestTracker.hyper.all[ thisRequest.getRequestId() ].caller.line + }, + type: "hyper" + ); + } + + /************************************** PRIVATE METHODS *********************************************/ + +} diff --git a/test-harness/config/Coldbox.cfc b/test-harness/config/Coldbox.cfc index a8ce526..a564302 100644 --- a/test-harness/config/Coldbox.cfc +++ b/test-harness/config/Coldbox.cfc @@ -148,7 +148,9 @@ expanded : false, logParams : true }, - luceeSQL : { enabled : true, expanded : false, logParams : true } + luceeSQL : { enabled : true, expanded : false, logParams : true }, + // Hyper Collector + hyper : { enabled : true, expanded : false, logRequestBody : true, logResponseData : true } } }; diff --git a/test-harness/layouts/Main.cfm b/test-harness/layouts/Main.cfm index 378fb4f..b83fa4c 100644 --- a/test-harness/layouts/Main.cfm +++ b/test-harness/layouts/Main.cfm @@ -120,14 +120,20 @@
+ +
-
+
- + ColdBox Debugger Test Harness + + + +
diff --git a/test-harness/views/main/index.cfm b/test-harness/views/main/index.cfm index 0dc9279..70159ee 100644 --- a/test-harness/views/main/index.cfm +++ b/test-harness/views/main/index.cfm @@ -1,7 +1,7 @@
- + Open Request Tracker diff --git a/views/main/panels/requestTracker/debugTimersPanel.cfm b/views/main/panels/requestTracker/debugTimersPanel.cfm index 546fb1f..167d0d9 100644 --- a/views/main/panels/requestTracker/debugTimersPanel.cfm +++ b/views/main/panels/requestTracker/debugTimersPanel.cfm @@ -56,6 +56,10 @@ + + + + @@ -87,9 +91,8 @@ #thisTimer.method# - + - diff --git a/views/main/panels/requestTracker/hyperPanel.cfm b/views/main/panels/requestTracker/hyperPanel.cfm new file mode 100755 index 0000000..46263b6 --- /dev/null +++ b/views/main/panels/requestTracker/hyperPanel.cfm @@ -0,0 +1,281 @@ + + + + + formatter = args.debuggerService.getFormatter(); + appPath = getSetting( "ApplicationPath" ); + + +
+ +
+   + + + + Hyper + + + + + + + + + + #args.profiler.hyper.totalRequests# + + + + + #numberFormat( args.profiler.hyper.totalExecutionTime )# ms +
+ + +
+ +
+
+ Total Requests: +
+ #args.profiler.hyper.totalRequests# +
+
+ +
+ Total Execution Time: +
+ #args.profiler.hyper.totalExecutionTime# ms +
+
+
+ + +
+ + + + + + +
+ + +
+ No hyper requests detected +
+ + + +
+ + + + + + + + + + + + + + + + + + + +
CountRequest Information
+
+ #args.profiler.hyper.grouped[ requestHash ].count# +
+
+ + + + +
#args.profiler.hyper.grouped[ requestHash ].method#>#args.profiler.hyper.grouped[ requestHash ].url#
+
+
+ + + + + + + + + + + + + + + + + + + + +
StatusTimestampExecution TimeCaller
+
+ + + + + + + + + + + + + + + + #thisRequestRecord.response.statusCode# + #thisRequestRecord.response.statusText# +
+
+ #TimeFormat( thisRequestRecord.timestamp, "hh:MM:SS.l tt" )# + + #numberFormat( thisRequestRecord.executionTime )# ms + +
+ + + + + +
+ + #replaceNoCase( thisRequestRecord.caller.template, appPath, "" )#:#thisRequestRecord.caller.line# + +
+
+
+
+
+ + +
+ #view( + view : "main/panels/requestTracker/hyperRequestTable", + module : "cbdebugger", + args : { + requestData : args.profiler.hyper.all, + debuggerService : args.debuggerService, + formatter : formatter, + appPath : appPath + }, + prePostExempt : true + )# +
+ + + +
+ #view( + view : "main/panels/requestTracker/hyperRequestTable", + module : "cbdebugger", + args : { + requestData : args.profiler.hyper.all + .reduce( ( results, key, value ) => { + return results.append( value ); + }, [] ) + .sort( function( a, b ){ + return a.executionTime < b.executionTime ? 1 : -1; + } ), + debuggerService : args.debuggerService, + formatter : formatter, + appPath : appPath + }, + prePostExempt : true + )# +
+ +
+ +
+
+
diff --git a/views/main/panels/requestTracker/hyperRequestTable.cfm b/views/main/panels/requestTracker/hyperRequestTable.cfm new file mode 100644 index 0000000..a68d4d4 --- /dev/null +++ b/views/main/panels/requestTracker/hyperRequestTable.cfm @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + +
StatusTimestampExecution TimeRequest
+
+ + + + + + + + + + + + + + + + #thisRequest.response.statusCode# + #thisRequest.response.statusText# +
+
+ #TimeFormat( thisRequest.timestamp,"hh:MM:SS.l tt" )# + + #numberFormat( thisRequest.executionTime )# ms + +
+ + + + + + #thisRequest.request.method#>#thisRequest.request.url# + +
+ +
+

Request:

+ + +
#prettyJson#
+
+ +

Response:

+ + +
#prettyJson#
+
+ +
+ + Called From: + + + + + +
+ + #replaceNoCase( thisRequest.caller.template, args.appPath, "" )#:#thisRequest.caller.line# + +
+
+
+
+
diff --git a/views/main/partials/profilerReport.cfm b/views/main/partials/profilerReport.cfm index fc85277..d10cb41 100644 --- a/views/main/partials/profilerReport.cfm +++ b/views/main/partials/profilerReport.cfm @@ -190,8 +190,8 @@ #announce( "beforeProfilerReportPanels", { - profiler : args.profiler, - debuggerConfig : args.debuggerConfig, + profiler : args.profiler, + debuggerConfig : args.debuggerConfig, debuggerService : args.debuggerService } )# @@ -203,8 +203,8 @@ view : "main/panels/requestTracker/exceptionPanel", module : "cbdebugger", args : { - debuggerConfig : args.debuggerConfig, - profiler : args.profiler, + debuggerConfig : args.debuggerConfig, + profiler : args.profiler, debuggerService : args.debuggerService }, prePostExempt : true @@ -219,9 +219,9 @@ view : "main/panels/requestTracker/debugTimersPanel", module : "cbdebugger", args : { - timers : args.profiler.timers, - debuggerConfig : args.debuggerConfig, - executionTime : args.profiler.executionTime, + timers : args.profiler.timers, + debuggerConfig : args.debuggerConfig, + executionTime : args.profiler.executionTime, debuggerService : args.debuggerService }, prePostExempt : true @@ -234,8 +234,8 @@ view : "main/panels/requestTracker/coldboxPanel", module : "cbdebugger", args : { - profiler : args.profiler, - debuggerConfig : args.debuggerConfig, + profiler : args.profiler, + debuggerConfig : args.debuggerConfig, debuggerService : args.debuggerService }, prePostExempt : true @@ -248,8 +248,8 @@ view : "main/panels/requestTracker/httpRequestPanel", module : "cbdebugger", args : { - profiler : args.profiler, - debuggerConfig : args.debuggerConfig, + profiler : args.profiler, + debuggerConfig : args.debuggerConfig, debuggerService : args.debuggerService }, prePostExempt : true @@ -263,9 +263,9 @@ view : "main/panels/requestTracker/tracersPanel", module : "cbdebugger", args : { - profiler : args.profiler, - tracers : args.profiler.tracers, - debuggerConfig : args.debuggerConfig, + profiler : args.profiler, + tracers : args.profiler.tracers, + debuggerConfig : args.debuggerConfig, debuggerService : args.debuggerService }, prePostExempt : true @@ -281,8 +281,8 @@ view : "main/panels/requestTracker/coldboxCollectionsPanel", module : "cbdebugger", args : { - profiler : args.profiler, - debuggerConfig : args.debuggerConfig, + profiler : args.profiler, + debuggerConfig : args.debuggerConfig, debuggerService : args.debuggerService }, prePostExempt : true @@ -297,8 +297,8 @@ view : "main/panels/requestTracker/acfSqlPanel", module : "cbdebugger", args : { - profiler : args.profiler, - debuggerConfig : args.debuggerConfig, + profiler : args.profiler, + debuggerConfig : args.debuggerConfig, debuggerService : args.debuggerService }, prePostExempt : true @@ -313,8 +313,8 @@ view : "main/panels/requestTracker/luceeSqlPanel", module : "cbdebugger", args : { - profiler : args.profiler, - debuggerConfig : args.debuggerConfig, + profiler : args.profiler, + debuggerConfig : args.debuggerConfig, debuggerService : args.debuggerService }, prePostExempt : true @@ -329,8 +329,8 @@ view : "main/panels/requestTracker/cbormPanel", module : "cbdebugger", args : { - profiler : args.profiler, - debuggerConfig : args.debuggerConfig, + profiler : args.profiler, + debuggerConfig : args.debuggerConfig, debuggerService : args.debuggerService }, prePostExempt : true @@ -345,8 +345,24 @@ view : "main/panels/requestTracker/qbPanel", module : "cbdebugger", args : { - profiler : args.profiler, - debuggerConfig : args.debuggerConfig, + profiler : args.profiler, + debuggerConfig : args.debuggerConfig, + debuggerService : args.debuggerService + }, + prePostExempt : true + )# +
+ + + + + + #view( + view : "main/panels/requestTracker/hyperPanel", + module : "cbdebugger", + args : { + profiler : args.profiler, + debuggerConfig : args.debuggerConfig, debuggerService : args.debuggerService }, prePostExempt : true @@ -355,8 +371,8 @@ #announce( "afterProfilerReportPanels", { - profiler : args.profiler, - debuggerConfig : args.debuggerConfig, + profiler : args.profiler, + debuggerConfig : args.debuggerConfig, debuggerService : args.debuggerService } )# From 7506289955142d3fac1bef32fe93d4136b763fe5 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Wed, 21 Jun 2023 17:28:08 +0200 Subject: [PATCH 28/45] feat: :art: - The request panel dock is now a real dock and the only one presented, the rest are only show in the visualizer - The `requestTracker.expanded` option is now removed, it's always expanded for visualizer and contracted for the dock --- ModuleConfig.cfc | 2 -- changelog.md | 5 +++ handlers/Main.cfc | 38 +++++++++++++++++++++++ interceptors/RequestCollector.cfc | 8 ++--- test-harness/config/Coldbox.cfc | 2 +- views/main/panels/modulesPanel.cfm | 1 - views/main/panels/requestTrackerPanel.cfm | 5 +-- 7 files changed, 51 insertions(+), 10 deletions(-) diff --git a/ModuleConfig.cfc b/ModuleConfig.cfc index 7d6b7a2..481a602 100644 --- a/ModuleConfig.cfc +++ b/ModuleConfig.cfc @@ -51,8 +51,6 @@ component { cacheName : "template", // Track all cbdebugger events, by default this is off, turn on, when actually profiling yourself :) How Meta! trackDebuggerEvents : false, - // Expand by default the tracker panel or not - expanded : false, // Slow request threshold in milliseconds, if execution time is above it, we mark those transactions as red slowExecutionThreshold : 1000, // How many tracking profilers to keep in stack diff --git a/changelog.md b/changelog.md index d4d64b4..163ed70 100644 --- a/changelog.md +++ b/changelog.md @@ -19,6 +19,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Changed the `instance` argument to `any` in the `debuggerService.openInEditorURL` to allow for a flat representational string of the URL to open in the editor. - Ability to download a heap dump snapshot from the visualizer +### Changed + +- The request panel dock is now a real dock and the only one presented, the rest are only show in the visualizer +- The `requestTracker.expanded` option is now removed, it's always expanded for visualizer and contracted for the dock + ### Improved - Updated test harness UI to make it easier to create debugging events diff --git a/handlers/Main.cfc b/handlers/Main.cfc index fed94c9..e275071 100644 --- a/handlers/Main.cfc +++ b/handlers/Main.cfc @@ -46,6 +46,44 @@ component extends="coldbox.system.RestHandler" { return renderDebugger( argumentCollection = arguments ); } + function renderRequestPanelDock( event, rc, prc ){ + // Return the debugger layout+view + // We pass in all the variables needed, to avoid prc/rc conflicts + try { + return layout( + layout : "Main", + module : "cbdebugger", + view : "main/panels/requestTrackerPanel", + viewModule: "cbdebugger", + args : { + // Get the current profiler for the current request. Basically the first in the stack + currentProfiler : variables.debuggerService.getCurrentProfiler(), + // Module Config + debuggerConfig : variables.debuggerConfig, + // Service pointer + debuggerService : variables.debuggerService, + // When debugging starts + debugStartTime : getTickCount(), + // Env struct + environment : variables.debuggerService.getEnvironment(), + // Manifest Root + manifestRoot : event.getModuleRoot( "cbDebugger" ) & "/includes", + // Module Root + moduleRoot : event.getModuleRoot( "cbDebugger" ), + // All Module Settings + moduleSettings : getSetting( "modules" ), + // Profilers storage to display + profilers : variables.debuggerService.getProfilerStorage(), + // Url build base + urlBase : event.buildLink( "" ) + } + ); + } catch ( any e ) { + writeDump( var = e, top = 5 ); + abort; + } + } + /** * This action renders out the debugger back to the caller as HTML widget */ diff --git a/interceptors/RequestCollector.cfc b/interceptors/RequestCollector.cfc index ce7d97b..318a331 100755 --- a/interceptors/RequestCollector.cfc +++ b/interceptors/RequestCollector.cfc @@ -82,12 +82,12 @@ component extends="coldbox.system.Interceptor" { // Record the profiler with the last tickcount variables.debuggerService.recordProfiler( event: arguments.event, executionTime: getTickCount() ); - // Determine if we can render the debugger at the bottom of the request + // Determine if we can render the request panel at the bottom of the request if ( - // Is the debugger turned on - variables.debuggerService.getDebugMode() AND // Can we show the end of request dock variables.debuggerConfig.requestPanelDock AND + // Is the debugger turned on + variables.debuggerService.getDebugMode() AND // Has it not been disabled by the user programmatically arguments.event.getPrivateValue( "cbox_debugger_show", true ) AND // Don't render in ajax calls @@ -102,7 +102,7 @@ component extends="coldbox.system.Interceptor" { !findNoCase( "MockController", getMetadata( controller ).name ) ) { // render out the debugger to the buffer output - arguments.buffer.append( runEvent( "cbdebugger:main.renderDebugger" ) ); + arguments.buffer.append( runEvent( "cbdebugger:main.renderRequestPanelDock" ) ); } } diff --git a/test-harness/config/Coldbox.cfc b/test-harness/config/Coldbox.cfc index a564302..27798b8 100644 --- a/test-harness/config/Coldbox.cfc +++ b/test-harness/config/Coldbox.cfc @@ -80,7 +80,7 @@ cacheName : "template", trackDebuggerEvents : false, // Expand by default the tracker panel or not - expanded : true, + expanded : false, // Slow request threshold in milliseconds, if execution time is above it, we mark those transactions as red slowExecutionThreshold : 1000, // How many tracking profilers to keep in stack: Default is to monitor the last 20 requests diff --git a/views/main/panels/modulesPanel.cfm b/views/main/panels/modulesPanel.cfm index 7b4d730..0c347ab 100755 --- a/views/main/panels/modulesPanel.cfm +++ b/views/main/panels/modulesPanel.cfm @@ -1,4 +1,3 @@ - totalTimes = args.moduleSettings.reduce( function( total, key, thisModuleConfig ){ if( !isNull( arguments.thisModuleConfig.registrationTime ) ){ diff --git a/views/main/panels/requestTrackerPanel.cfm b/views/main/panels/requestTrackerPanel.cfm index 8a45f0d..1543edc 100755 --- a/views/main/panels/requestTrackerPanel.cfm +++ b/views/main/panels/requestTrackerPanel.cfm @@ -1,9 +1,10 @@ - + +
diff --git a/layouts/Monitor.cfm b/layouts/Visualizer.cfm similarity index 100% rename from layouts/Monitor.cfm rename to layouts/Visualizer.cfm diff --git a/resources/assets/sass/cbdebugger.scss b/resources/assets/sass/cbdebugger.scss index 4b3282b..c3f5362 100644 --- a/resources/assets/sass/cbdebugger.scss +++ b/resources/assets/sass/cbdebugger.scss @@ -1,4 +1,16 @@ [x-cloak] { display: none !important; } +.cbd-dock{ + position: fixed; + bottom: 0; + left: 0; + width: 100%; + overflow-y: auto; + max-height: 100%; + + .cbd-contentView{ + border-radius: 0px !important; + } +} .cbd-debugger{ font-family: Verdana,Arial,sans-serif; font-size: 11px; @@ -160,8 +172,6 @@ background: #327A9F; padding:5px 5px; cursor: pointer; - margin-bottom: 2px; - border-radius: 5px; &:hover{ background: #D7EBF9; diff --git a/views/main/panels/requestTrackerPanel.cfm b/views/main/panels/requestTrackerPanel.cfm index 1543edc..ddc4c73 100755 --- a/views/main/panels/requestTrackerPanel.cfm +++ b/views/main/panels/requestTrackerPanel.cfm @@ -21,12 +21,14 @@
- ColdBox Request Tracker + + ColdBox Request Tracker + From 6d873642eb556b4f73938139bab97669af355a50 Mon Sep 17 00:00:00 2001 From: lmajano Date: Wed, 21 Jun 2023 15:56:41 +0000 Subject: [PATCH 30/45] Apply cfformat changes --- handlers/Main.cfc | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/handlers/Main.cfc b/handlers/Main.cfc index df6c22f..f01c1fb 100644 --- a/handlers/Main.cfc +++ b/handlers/Main.cfc @@ -57,25 +57,25 @@ component extends="coldbox.system.RestHandler" { viewModule: "cbdebugger", args : { // Get the current profiler for the current request. Basically the first in the stack - currentProfiler : variables.debuggerService.getCurrentProfiler(), + currentProfiler : variables.debuggerService.getCurrentProfiler(), // Module Config - debuggerConfig : variables.debuggerConfig, + debuggerConfig : variables.debuggerConfig, // Service pointer - debuggerService : variables.debuggerService, + debuggerService : variables.debuggerService, // When debugging starts - debugStartTime : getTickCount(), + debugStartTime : getTickCount(), // Env struct - environment : variables.debuggerService.getEnvironment(), + environment : variables.debuggerService.getEnvironment(), // Manifest Root - manifestRoot : event.getModuleRoot( "cbDebugger" ) & "/includes", + manifestRoot : event.getModuleRoot( "cbDebugger" ) & "/includes", // Module Root - moduleRoot : event.getModuleRoot( "cbDebugger" ), + moduleRoot : event.getModuleRoot( "cbDebugger" ), // All Module Settings - moduleSettings : getSetting( "modules" ), + moduleSettings : getSetting( "modules" ), // Profilers storage to display - profilers : variables.debuggerService.getProfilerStorage(), + profilers : variables.debuggerService.getProfilerStorage(), // Url build base - urlBase : event.buildLink( "" ) + urlBase : event.buildLink( "" ) } ); } catch ( any e ) { From 3c08dfed7c9b2f4553cc4a67c0c97dfe35943c8d Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Thu, 22 Jun 2023 07:34:42 +0200 Subject: [PATCH 31/45] acf issues --- test-harness/handlers/Main.cfc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test-harness/handlers/Main.cfc b/test-harness/handlers/Main.cfc index 7a075d2..17a551e 100644 --- a/test-harness/handlers/Main.cfc +++ b/test-harness/handlers/Main.cfc @@ -118,7 +118,7 @@ component { "When" = now() } ) .setBody( { - title : "Hello World", + title : "Hello World" } ) .send(); event.setView( "main/hyperData" ); @@ -135,7 +135,7 @@ component { "When" = now() } ) .setBody( { - title : "Hello World", + title : "Hello World" } ) .send(); event.setView( "main/hyperData" ); From ff090a6254eb136474ad3c17492d9840698fd56b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Jul 2023 01:53:05 +0000 Subject: [PATCH 32/45] Bump word-wrap from 1.2.3 to 1.2.4 Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.4. - [Release notes](https://github.com/jonschlinkert/word-wrap/releases) - [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.4) --- updated-dependencies: - dependency-name: word-wrap dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 080dfb7..2d0e10f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7034,9 +7034,9 @@ "dev": true }, "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", + "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -12124,9 +12124,9 @@ "dev": true }, "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", + "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", "dev": true }, "wrappy": { From 0b0cc1686d80c1a116391d39c77778f6a4ac5882 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Oct 2023 20:49:39 +0000 Subject: [PATCH 33/45] Bump postcss from 8.4.14 to 8.4.31 Bumps [postcss](https://github.com/postcss/postcss) from 8.4.14 to 8.4.31. - [Release notes](https://github.com/postcss/postcss/releases) - [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/postcss/postcss/compare/8.4.14...8.4.31) --- updated-dependencies: - dependency-name: postcss dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2d0e10f..1842bcf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4875,10 +4875,16 @@ "dev": true }, "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -5198,9 +5204,9 @@ } }, "node_modules/postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "dev": true, "funding": [ { @@ -5210,10 +5216,14 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -10654,9 +10664,9 @@ "dev": true }, "nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", "dev": true }, "natural-compare": { @@ -10887,12 +10897,12 @@ } }, "postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "dev": true, "requires": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } From b0763cbb4a3e4e7e28b43a8c0806a238e8d5ed26 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Oct 2023 04:43:14 +0000 Subject: [PATCH 34/45] Bump @babel/traverse from 7.18.5 to 7.23.2 Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.18.5 to 7.23.2. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse) --- updated-dependencies: - dependency-name: "@babel/traverse" dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 289 +++++++++++++++++++++++++--------------------- 1 file changed, 155 insertions(+), 134 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2d0e10f..c356ea8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,12 +40,13 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, "dependencies": { - "@babel/highlight": "^7.16.7" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" @@ -118,13 +119,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.2.tgz", - "integrity": "sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dev": true, "dependencies": { - "@babel/types": "^7.18.2", - "@jridgewell/gen-mapping": "^0.3.0", + "@babel/types": "^7.23.0", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" }, "engines": { @@ -245,9 +247,9 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.2.tgz", - "integrity": "sha512-14GQKWkX9oJzPiQQ7/J36FTXcD4kSp8egKjO9nINlSKiHITRA9q/R74qu8S9xlc/b/yjsJItQUeeh3xnGN0voQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "dev": true, "engines": { "node": ">=6.9.0" @@ -266,25 +268,25 @@ } }, "node_modules/@babel/helper-function-name": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz", - "integrity": "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "dependencies": { - "@babel/template": "^7.16.7", - "@babel/types": "^7.17.0" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", - "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dev": true, "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -409,21 +411,30 @@ } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", - "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true, "engines": { "node": ">=6.9.0" @@ -468,13 +479,13 @@ } }, "node_modules/@babel/highlight": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.12.tgz", - "integrity": "sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { @@ -482,9 +493,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.18.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.5.tgz", - "integrity": "sha512-YZWVaglMiplo7v8f1oMQ5ZPQr0vn7HPeZXxXWsxXJRjGVrzUFn9OxFQl1sb5wzfootjA/yChhW84BV+383FSOw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -1591,33 +1602,33 @@ } }, "node_modules/@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.18.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.5.tgz", - "integrity": "sha512-aKXj1KT66sBj0vVzk6rEeAO6Z9aiiQ68wfDgge3nHhA/my6xMM/7HGQUNumKZaoa2qUPQ5whJG9aAifsxUKfLA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.18.2", - "@babel/helper-environment-visitor": "^7.18.2", - "@babel/helper-function-name": "^7.17.9", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.18.5", - "@babel/types": "^7.18.4", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -1626,12 +1637,13 @@ } }, "node_modules/@babel/types": { - "version": "7.18.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.4.tgz", - "integrity": "sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -1716,9 +1728,9 @@ } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.8.tgz", - "integrity": "sha512-YK5G9LaddzGbcucK4c8h5tWFmMPBvRZ/uyWmN1/SbBdIvqGUdWGkJ5BAaccgs6XbzVLsqbPJrBSFwKv3kT9i7w==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", "dev": true, "engines": { "node": ">=6.0.0" @@ -1764,13 +1776,13 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.14", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", - "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@nodelib/fs.scandir": { @@ -7081,12 +7093,13 @@ } }, "@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, "requires": { - "@babel/highlight": "^7.16.7" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" } }, "@babel/compat-data": { @@ -7138,13 +7151,14 @@ } }, "@babel/generator": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.2.tgz", - "integrity": "sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dev": true, "requires": { - "@babel/types": "^7.18.2", - "@jridgewell/gen-mapping": "^0.3.0", + "@babel/types": "^7.23.0", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" }, "dependencies": { @@ -7234,9 +7248,9 @@ } }, "@babel/helper-environment-visitor": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.2.tgz", - "integrity": "sha512-14GQKWkX9oJzPiQQ7/J36FTXcD4kSp8egKjO9nINlSKiHITRA9q/R74qu8S9xlc/b/yjsJItQUeeh3xnGN0voQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "dev": true }, "@babel/helper-explode-assignable-expression": { @@ -7249,22 +7263,22 @@ } }, "@babel/helper-function-name": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz", - "integrity": "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "requires": { - "@babel/template": "^7.16.7", - "@babel/types": "^7.17.0" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" } }, "@babel/helper-hoist-variables": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", - "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dev": true, "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.22.5" } }, "@babel/helper-member-expression-to-functions": { @@ -7359,18 +7373,24 @@ } }, "@babel/helper-split-export-declaration": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", - "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.22.5" } }, + "@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "dev": true + }, "@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true }, "@babel/helper-validator-option": { @@ -7403,20 +7423,20 @@ } }, "@babel/highlight": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.12.tgz", - "integrity": "sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" } }, "@babel/parser": { - "version": "7.18.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.5.tgz", - "integrity": "sha512-YZWVaglMiplo7v8f1oMQ5ZPQr0vn7HPeZXxXWsxXJRjGVrzUFn9OxFQl1sb5wzfootjA/yChhW84BV+383FSOw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "dev": true }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { @@ -8154,41 +8174,42 @@ } }, "@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dev": true, "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" } }, "@babel/traverse": { - "version": "7.18.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.5.tgz", - "integrity": "sha512-aKXj1KT66sBj0vVzk6rEeAO6Z9aiiQ68wfDgge3nHhA/my6xMM/7HGQUNumKZaoa2qUPQ5whJG9aAifsxUKfLA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.18.2", - "@babel/helper-environment-visitor": "^7.18.2", - "@babel/helper-function-name": "^7.17.9", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.18.5", - "@babel/types": "^7.18.4", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.18.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.4.tgz", - "integrity": "sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.16.7", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" } }, @@ -8254,9 +8275,9 @@ } }, "@jridgewell/resolve-uri": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.8.tgz", - "integrity": "sha512-YK5G9LaddzGbcucK4c8h5tWFmMPBvRZ/uyWmN1/SbBdIvqGUdWGkJ5BAaccgs6XbzVLsqbPJrBSFwKv3kT9i7w==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", "dev": true }, "@jridgewell/set-array": { @@ -8295,13 +8316,13 @@ "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.14", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", - "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", "dev": true, "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "@nodelib/fs.scandir": { From 382d21b27520905eaae76525b0523df49fee0188 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Fri, 20 Oct 2023 12:20:39 +0200 Subject: [PATCH 35/45] ui fix for the dock to stand out --- resources/assets/sass/cbdebugger.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/assets/sass/cbdebugger.scss b/resources/assets/sass/cbdebugger.scss index c3f5362..0418f04 100644 --- a/resources/assets/sass/cbdebugger.scss +++ b/resources/assets/sass/cbdebugger.scss @@ -6,6 +6,7 @@ width: 100%; overflow-y: auto; max-height: 100%; + z-index: 1000; .cbd-contentView{ border-radius: 0px !important; From efcbf6670fc3d4133ea6b3a216dbc6f982587766 Mon Sep 17 00:00:00 2001 From: Michael Born <8106227+michaelborn@users.noreply.github.com> Date: Thu, 21 Dec 2023 15:18:58 -0500 Subject: [PATCH 36/45] Fix un-paramed values in request.cbDebugger If request.cbDebugger is already an empty struct, then none of these required keys will be created. --- models/DebuggerService.cfc | 49 +++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/models/DebuggerService.cfc b/models/DebuggerService.cfc index 49257b7..0ee43b3 100755 --- a/models/DebuggerService.cfc +++ b/models/DebuggerService.cfc @@ -190,32 +190,31 @@ component */ struct function createRequestTracker( required event ){ // Init the request debugger tracking - param request.cbDebugger = { - "coldbox" : {}, - "exception" : {}, - "executionTime" : 0, - "endFreeMemory" : 0, - "formData" : serializeJSON( form ?: {} ), - "fullUrl" : arguments.event.getFullUrl(), - "httpHost" : cgi.HTTP_HOST, - "httpReferer" : cgi.HTTP_REFERER, - "id" : variables.uuid.randomUUID().toString(), - "inetHost" : discoverInetHost(), - "ip" : getRealIP(), - "localIp" : getServerIp(), - "queryString" : cgi.QUERY_STRING, - "requestData" : getHTTPRequestData( + param request.cbDebugger = {}; + param request.cbDebugger.coldbox = {}; + param request.cbDebugger.exception = {}; + param request.cbDebugger.executionTime = 0; + param request.cbDebugger.endFreeMemory = 0; + param request.cbDebugger.formData = serializeJSON( form ?: {} ); + param request.cbDebugger.fullUrl = arguments.event.getFullUrl(); + param request.cbDebugger.httpHost = cgi.HTTP_HOST; + param request.cbDebugger.httpReferer = cgi.HTTP_REFERER; + param request.cbDebugger.id = variables.uuid.randomUUID().toString(); + param request.cbDebugger.inetHost = discoverInetHost(); + param request.cbDebugger.ip = getRealIP(); + param request.cbDebugger.localIp = getServerIp(); + param request.cbDebugger.queryString = cgi.QUERY_STRING; + param request.cbDebugger.requestData = getHTTPRequestData( variables.debuggerConfig.requestTracker.httpRequest.profileHTTPBody - ), - "response" : { "statusCode" : 0, "contentType" : "" }, - "startCount" : getTickCount(), - "startFreeMemory" : variables.jvmRuntime.freeMemory(), - "threadInfo" : getCurrentThread().toString(), - "timers" : [], - "timestamp" : now(), - "tracers" : [], - "userAgent" : cgi.HTTP_USER_AGENT - }; + ); + param request.cbDebugger.response = { "statusCode" : 0, "contentType" : "" }; + param request.cbDebugger.startCount = getTickCount(); + param request.cbDebugger.startFreeMemory = variables.jvmRuntime.freeMemory(); + param request.cbDebugger.threadInfo = getCurrentThread().toString(); + param request.cbDebugger.timers = []; + param request.cbDebugger.timestamp = now(); + param request.cbDebugger.tracers = []; + param request.cbDebugger.userAgent = cgi.HTTP_USER_AGENT; // Event before recording variables.interceptorService.announce( From 98817b9770820b0102c1cd5386f9d01afd914807 Mon Sep 17 00:00:00 2001 From: lmajano Date: Mon, 25 Dec 2023 15:08:38 +0000 Subject: [PATCH 37/45] Apply cfformat changes --- models/DebuggerService.cfc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/models/DebuggerService.cfc b/models/DebuggerService.cfc index 0ee43b3..0870b62 100755 --- a/models/DebuggerService.cfc +++ b/models/DebuggerService.cfc @@ -190,7 +190,7 @@ component */ struct function createRequestTracker( required event ){ // Init the request debugger tracking - param request.cbDebugger = {}; + param request.cbDebugger = {}; param request.cbDebugger.coldbox = {}; param request.cbDebugger.exception = {}; param request.cbDebugger.executionTime = 0; @@ -205,7 +205,7 @@ component param request.cbDebugger.localIp = getServerIp(); param request.cbDebugger.queryString = cgi.QUERY_STRING; param request.cbDebugger.requestData = getHTTPRequestData( - variables.debuggerConfig.requestTracker.httpRequest.profileHTTPBody + variables.debuggerConfig.requestTracker.httpRequest.profileHTTPBody ); param request.cbDebugger.response = { "statusCode" : 0, "contentType" : "" }; param request.cbDebugger.startCount = getTickCount(); From 78b195fa5f406d47625c1a8262922b9b4fd25a77 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Wed, 10 Jan 2024 15:00:58 +0100 Subject: [PATCH 38/45] default temp directory for generating heap dumps --- handlers/Main.cfc | 2 +- models/JVMUtil.cfc | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/handlers/Main.cfc b/handlers/Main.cfc index f01c1fb..36e61d7 100644 --- a/handlers/Main.cfc +++ b/handlers/Main.cfc @@ -139,7 +139,7 @@ component extends="coldbox.system.RestHandler" { */ function heapDump( event, rc, prc ){ event.sendFile( - file : getInstance( "JVMUtil@cbdebugger" ).generateHeapDump( getTempDirectory() ), + file : getInstance( "JVMUtil@cbdebugger" ).generateHeapDump(), deleteFile: true ); } diff --git a/models/JVMUtil.cfc b/models/JVMUtil.cfc index e7aabce..d1cc24a 100644 --- a/models/JVMUtil.cfc +++ b/models/JVMUtil.cfc @@ -23,13 +23,13 @@ component singleton { * Generate a heap dump and store it at the given directory path * The generated heap dump will be named with the following pattern:
cbdebugger-heapdump-mmm-dd-yyyy_HHnnss_l.hprof
* - * @directoryPath The directory path to store the heap dump, must be absolute + * @directoryPath The directory path to store the heap dump, must be absolute. Defaults to the temporary directory * * @return The absolute path to the generated heap dump */ - string function generateHeapDump( required directoryPath ){ + string function generateHeapDump( directoryPath ){ // Create it if it doesn't exist - if ( !directoryExists( arguments.directoryPath ) ) { + if ( !directoryExists( arguments.directoryPath = getTempDirectory() ) ) { directoryCreate( arguments.directoryPath ); } From 6d027d0aa661ee78849f20a4d6262f6423c9489a Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Wed, 10 Jan 2024 15:38:00 +0100 Subject: [PATCH 39/45] more keywords and nicer sql printing --- models/Formatter.cfc | 44 ++++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/models/Formatter.cfc b/models/Formatter.cfc index 4f40935..e919402 100644 --- a/models/Formatter.cfc +++ b/models/Formatter.cfc @@ -16,44 +16,60 @@ component singleton { */ function prettySql( string target = "" ){ var keywords = [ - "SELECT", + "ALTER TABLE", + "CREATE TABLE", + "DELETE", + "DROP TABLE", "FROM", - "WHERE", "GROUP BY", "HAVING", - "ORDER BY", "INSERT INTO", + "LIMIT", + "ORDER BY", + "OFFSET", + "SELECT", + "UNION", "UPDATE", - "DELETE", - "CREATE TABLE", - "ALTER TABLE", - "DROP TABLE", - "UNION" + "WHERE" ]; var indentedKeywords = [ + "FULL JOIN", + "INNER JOIN", "JOIN", "LEFT JOIN", - "INNER JOIN", - "OUTER JOIN", - "FULL JOIN" + "OUTER JOIN" ]; var indent = " "; return arguments.target .listToArray( variables.NEW_LINE ) .map( ( item ) => item.trim() ) + // comma spacing .map( ( item ) => item.reReplace( - "(\s)*,(\s)*", + "\s*(?![^()]*\))(,)\s*", ",#variables.NEW_LINE##indent#", "all" ) ) + // Parenthesis spacing + .map( ( item ) => item.reReplace( + "\((\w)", + "( \1", + "all" + ) ) + .map( ( item ) => item.reReplace( + "(\w)\)", + "\1 )", + "all" + ) ) + // Keyword spacing .map( ( item ) => { return item.reReplacenocase( - "(\s)*(#keywords.toList( "|" )#)(\s)*", - "\2#variables.NEW_LINE##indent#", + "(\s)*(#keywords.toList( "|" )#)(\s)+", + "#variables.NEW_LINE#\2#variables.NEW_LINE##indent#", "all" ) } ) + // Indented keyword spacing .map( ( item ) => { return item.reReplacenocase( "(#indentedKeywords.toList( "|" )#)", From b939144ea4f4af31c3555686864eb3dff32af42f Mon Sep 17 00:00:00 2001 From: lmajano Date: Wed, 10 Jan 2024 14:38:41 +0000 Subject: [PATCH 40/45] Apply cfformat changes --- handlers/Main.cfc | 5 +---- models/Formatter.cfc | 12 ++---------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/handlers/Main.cfc b/handlers/Main.cfc index 36e61d7..7704619 100644 --- a/handlers/Main.cfc +++ b/handlers/Main.cfc @@ -138,10 +138,7 @@ component extends="coldbox.system.RestHandler" { * Download a heapdump snapshot */ function heapDump( event, rc, prc ){ - event.sendFile( - file : getInstance( "JVMUtil@cbdebugger" ).generateHeapDump(), - deleteFile: true - ); + event.sendFile( file: getInstance( "JVMUtil@cbdebugger" ).generateHeapDump(), deleteFile: true ); } /** diff --git a/models/Formatter.cfc b/models/Formatter.cfc index e919402..edc9924 100644 --- a/models/Formatter.cfc +++ b/models/Formatter.cfc @@ -51,16 +51,8 @@ component singleton { "all" ) ) // Parenthesis spacing - .map( ( item ) => item.reReplace( - "\((\w)", - "( \1", - "all" - ) ) - .map( ( item ) => item.reReplace( - "(\w)\)", - "\1 )", - "all" - ) ) + .map( ( item ) => item.reReplace( "\((\w)", "( \1", "all" ) ) + .map( ( item ) => item.reReplace( "(\w)\)", "\1 )", "all" ) ) // Keyword spacing .map( ( item ) => { return item.reReplacenocase( From ba7291eadca7a4d1d7911088f1daa9ee949e7069 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Wed, 10 Jan 2024 19:07:24 +0100 Subject: [PATCH 41/45] - `TimerDelegate` now has a `addCBTimer()` method --- changelog.md | 7 ++++++- models/TimerDelegate.cfc | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 163ed70..2898d79 100644 --- a/changelog.md +++ b/changelog.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - New `HyperCollector` so you can now track hyper requests if enabled - `Timer` can now add timers a-la-carte via the `add()` method +- `TimerDelegate` now has a `addCBTimer()` method - New fast and furious and tiny SQL/JSON Formatter - New `LuceeSqlCollector` you can use to profile all SQL calls in Lucee - New `luceeSql` configuration to control the Lucee SQL calls collector @@ -52,7 +53,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - ColdBox 7 support -- New `TimerDelegate` that can be used to add timer functions to any model +- New `TimerDelegate` that can be used to add timer functions to any model: + - `startCBTimer()` + - `stopCBTimer()` + - `cbTimeIt()` + - `addCBTimer()` - Timer service rewritten to support nesting and included metadata - Ability to open views and layouts from the execution timers in any Code Editor - New `WireBoxCollector` which is only used if enabled. This greatly accelerates the performance of the request collector since before they where in the same collector. diff --git a/models/TimerDelegate.cfc b/models/TimerDelegate.cfc index fec6352..bd30a65 100644 --- a/models/TimerDelegate.cfc +++ b/models/TimerDelegate.cfc @@ -44,4 +44,27 @@ component accessors="true" singleton threadsafe { return variables.timer.timeIt( argumentCollection = arguments ); } + /** + * Add a timer to the stack manually. You will need the label, executionTime and stoppedAt timestamps + * + * @label The label to use as a timer label + * @executionTime The execution time in ms to register + * @startedAt The date time the timer was started + * @stoppedAt The date time the timer was stopped + * @metadata A struct of metadata to store in the execution timer + * @parent An optional parent label + * @type The type of execution timed: request, view-render, layout-render, event, renderer + */ + function addCBTimer( + required label, + required executionTime, + startedAt = now(), + stoppedat = now(), + struct metadata = {}, + parent = "", + type = "timer" + ){ + return variables.timer.add( argumentCollection = arguments ); + } + } From 86b18e9407aa0ab25fca868869046ed477028ba5 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Wed, 10 Jan 2024 21:14:30 +0100 Subject: [PATCH 42/45] adding ortus hibernate extension --- server-lucee@5.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server-lucee@5.json b/server-lucee@5.json index 752d969..59eefe2 100644 --- a/server-lucee@5.json +++ b/server-lucee@5.json @@ -19,5 +19,8 @@ "openBrowser":"false", "cfconfig":{ "file":".cfconfig.json" + }, + "env":{ + "lucee-extensions":"D062D72F-F8A2-46F0-8CBC91325B2F067B" } } From 3ed39273a061217cf62601e9d720d415109be265 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Wed, 10 Jan 2024 21:22:28 +0100 Subject: [PATCH 43/45] updated readme to point to the docs --- box.json | 2 +- readme.md | 530 ++---------------------------------------------------- 2 files changed, 17 insertions(+), 515 deletions(-) diff --git a/box.json b/box.json index 523c7f1..9c9ecfa 100644 --- a/box.json +++ b/box.json @@ -7,7 +7,7 @@ "type":"modules", "homepage":"https://github.com/coldbox-modules/cbdebugger", "bugs":"https://ortussolutions.atlassian.net/browse/CBDEBUGGER", - "documentation":"https://github.com/coldbox-modules/cbdebugger", + "documentation":"https://cbdebugger.ortusbooks.com/", "repository":{ "type":"git", "url":"https://github.com/coldbox-modules/cbdebugger" diff --git a/readme.md b/readme.md index 6aea7ac..1a0d09d 100644 --- a/readme.md +++ b/readme.md @@ -4,9 +4,6 @@

Latest Stable Version - - Build Status - License @@ -38,21 +35,21 @@ Request Tracker Collapsed The ColdBox debugger is a light-weigth performance monitor and profiler for your ColdBox applications. It tracks your requests, whether Ajax, traditional or REST, it's environment, execution and much more. Here is a listing of some of the capabilities you get with the ColdBox Debugger: -- Track all incoming requests to your applications in memory or offloaded cache +- Track all incoming requests to your applications - Track exceptions and execution environment -- Track incoming http requests, parameters, body and much more +- Track incoming HTTP requests, parameters, body, and much more - Track final request collections -- Track Hibernate and `cborm` queries, criteria queries and session stats -- Track `qb` and `quick` queries, entities and stats -- Tap into LogBox via our Tracer messages and discover logging on a per request basis -- Profile execution and results of **ANY** model object -- Profile execution of **ANY** ColdBox interception point +- Track Hibernate and cborm queries, criteria queries, and session stats +- Track qb and quick queries, entities, and stats +- Tap into LogBox via our Tracer messages and discover logging on a per-request basis +- Profile execution and results of ANY model object +- Profile execution of ANY ColdBox interception point - Custom Timer helpers for adding timing methods and annotations anywhere in your code - Profile your production or development apps with ease - Track ColdBox modules and lifecycles -- Highly configurable -- Highly extensible +- Track Hyper HTTP/S calls - Track Adobe ColdFusion Queries (ColdFusion 2018+) +- Track Lucee Queries ## License @@ -60,6 +57,7 @@ Apache License, Version 2.0. ## Important Links +- Docs: https://cbdebugger.ortusbooks.com/ - Source: https://github.com/coldbox-modules/cbdebugger - ForgeBox: https://www.forgebox.io/view/cbdebugger - Community: https://community.ortussolutions.com/c/box-modules/cbdebugger/38 @@ -74,518 +72,22 @@ Apache License, Version 2.0. ## Optional Requirements -### cborm Collector - -- Hibernate extension (on Lucee) -- `orm` package on ACF 2021 - -### Adobe SQL Collector - -- `cbdebugger` package on ACF 2021 - - Check `Database Activity` on the debugger page or cfconfig setting (`debuggingShowDatabase : true`) +https://cbdebugger.ortusbooks.com/essentials/installation#optional-requirements # Instructions -Just drop into your **modules** folder or use CommandBox to install - -`box install cbdebugger` - -This will activate the debugger in your application and render out at the end of a request or by visiting the debugger request tracker visualizer at `/cbdebugger`. +https://cbdebugger.ortusbooks.com/essentials/installation ## Settings The debugger is highly configurable and we have tons of settings to assist you in your development adventures and also in your performance tuning. Please note that the more collectors you activate, the **slower** your application can become. By default we have pre-selected defaults which add neglible performance to your applications. -Open your `config/coldbox.cfc` configuration object and add into the `moduleSettings` the `cbDebugger` key with the following options: - -```js -moduleSettings = { - // Debugger Settings - cbDebugger = { - // Master switch to enable/disable request tracking into storage facilities. - enabled : true, - // Turn the debugger UI on/off by default. You can always enable it via the URL using your debug password - // Please note that this is not the same as the master switch above - // The debug mode can be false and the debugger will still collect request tracking - debugMode : true, - // The URL password to use to activate it on demand - debugPassword : "cb:null", - // This flag enables/disables the end of request debugger panel docked to the bottom of the page. - // If you disable it, then the only way to visualize the debugger is via the `/cbdebugger` endpoint - requestPanelDock : true, - // Request Tracker Options - requestTracker : { - // Track all cbdebugger events, by default this is off, turn on, when actually profiling yourself :) How Meta! - trackDebuggerEvents : false, - // Store the request profilers in heap memory or in cachebox, default is memory. Options are: memory, cachebox - storage : "memory", - // Which cache region to store the profilers in if storage == cachebox - cacheName : "template", - // Expand by default the tracker panel or not - expanded : true, - // Slow request threshold in milliseconds, if execution time is above it, we mark those transactions as red - slowExecutionThreshold : 1000, - // How many tracking profilers to keep in stack: Default is to monitor the last 20 requests - maxProfilers : 50, - // If enabled, the debugger will monitor the creation time of CFC objects via WireBox - profileWireBoxObjectCreation : false, - // Profile model objects annotated with the `profile` annotation - profileObjects : false, - // If enabled, will trace the results of any methods that are being profiled - traceObjectResults : false, - // Profile Custom or Core interception points - profileInterceptions : false, - // By default all interception events are excluded, you must include what you want to profile - includedInterceptions : [], - // Control the execution timers - executionTimers : { - expanded : true, - // Slow transaction timers in milliseconds, if execution time of the timer is above it, we mark it - slowTimerThreshold : 250 - }, - // Control the coldbox info reporting - coldboxInfo : { expanded : false }, - // Control the http request reporting - httpRequest : { - expanded : false, - // If enabled, we will profile HTTP Body content, disabled by default as it contains lots of data - profileHTTPBody : false - } - }, - // ColdBox Tracer Appender Messages - tracers : { enabled : true, expanded : false }, - // Request Collections Reporting - collections : { - // Enable tracking - enabled : false, - // Expanded panel or not - expanded : false, - // How many rows to dump for object collections - maxQueryRows : 50, - // Max number to use when dumping objects via the top argument - maxDumpTop: 5 - }, - // CacheBox Reporting - cachebox : { enabled : false, expanded : false }, - // Modules Reporting - modules : { enabled : false, expanded : false }, - // Quick and QB Reporting - qb : { - enabled : true, - expanded : false, - // Log the binding parameters - logParams : true - }, - // cborm Reporting - cborm : { - enabled : false, - expanded : false, - // Log the binding parameters (requires CBORM 3.2.0+) - logParams : true - }, - // Adobe ColdFusion SQL Collector - acfSql : { - enabled : true, - expanded : false, - // Log the binding parameters - logParams : true - }, - // Lucee SQL Collector - luceeSql : { - enabled : true, - expanded : false, - // Log the binding parameters - logParams : true - }, - // Async Manager Reporting - async : { - enabled : true, - expanded : false - } - } -} -``` - -## WireBox Mappings - -The module will also register the following model objects for you: - -- `debuggerService@cbdebugger` -- `timer@cbdebugger` - -The `DebuggerService` can be used a-la-carte for your debugging purposes. - -The `Timer` object will allow you to time code execution and send the results to the debugger panel. - -## Helper Mixins - -This module will also register a few methods in all your handlers/interceptors/layouts and views. You can use them for turning the debugger panel on/off, timing code execution and much more. - -```js - /** - * Method to turn on the rendering of the debug panel on a request - */ - any function showDebugger() - - /** - * Method to turn off the rendering of the debug panel on a request - */ - any function hideDebugger() - - /** - * See if the debugger will be rendering or not - */ - boolean function isDebuggerRendering() - - /** - * Start a timer with a tracking label - * - * @label The tracking label to register - * - * @return A unique tracking hash you must use to stop the timer - */ - function startCBTimer( required label ) - - /** - * End a code timer with a tracking hash. If the tracking hash is not tracked we ignore it - * - * @labelHash The timer label hash to stop - */ - function stopCBTimer( required labelHash ) - - /** - * Time the execution of the passed closure that we will execution for you - * - * @label The label to use as a timer label - * @closure The target to execute and time - */ - function cbTimeIt( required label, required closure ) - - /** - * Shortcut to get a reference to the ColdBox Debugger Service - */ - function getCBDebugger() - - /** - * Push a new tracer into the debugger. This comes from LogBox, so we follow - * the same patterns - * - * @message The message to trace - * @severity The severity of the message - * @category The tracking category the message came from - * @timestamp The timestamp of the message - * @extraInfo Extra info to store in the tracer - */ - DebuggerService function cbTracer( - required message, - severity = "info", - category = "", - timestamp = now(), - extraInfo = "" - ) -``` - -## Timer Delegate - -We have included a ColdBox 7 Timer delegate: `TimerDelegate@cbDebguger` that can add timing capabilities to any CFC - -```js -component delegates="TimerDelegate@cbDebguger"{ - -... - startCBTimer(); - stopCBTimer(); - timeIt(); -... - -} - -``` - -## Debugger Events - -The debugger also announces several events that you can listen to and extend the debugging and profiling capabilities: - -```js -// Before the debugger panel is rendered -"beforeDebuggerPanel", -// After the last debugger panel is rendered -"afterDebuggerPanel", -// Before any individual profiler report panels are rendered -"beforeProfilerReportPanels", -// After any individual profiler report panels are rendered -"afterProfilerReportPanels", -// When the request tracker has been created and placed in request scope -"onDebuggerRequestTrackerCreation", -// Before the request tracker is saved in the profiler, last chance to influence the recording -"onDebuggerProfilerRecording" -``` - -## Profiling Objects - -The ColdBox debugger allows you to profile the execution of ANY method in ANY CFC via our AOP pointcuts. All you need to do is add the `profile` annotation to a method or component declaration in your model/orm objects. Once you do, the debugger will track the execution of those methods in the debug timers panel for you. First thing to do is make sure the setting is turned on: - -```js -requestTracker : { - // Profile model objects annotated with the `profile` annotation - profileObjects : true, - // If enabled, will trace the results of any methods that are being profiled - traceObjectResults : false, -} -``` - -The `traceObjectResults` if `true` will track the actual results of the method calls into your debugger timer panel. Careful, as we will serialize anything you send to us. Then add the `profile` annotation to any method or cfc. - -```js -/** - * Profile all methods in this component - */ -component profile{ - -} - -// Add the profile to this method to track it -function saveAllObjects() profile{ - -} -``` - -Profiling objects is great because you can just annotate and forget. Nothing to turn off in production. - -## WireBox Object Creation Profiling - -There will be cases where you need to test the performance of the creation of certain objects in WireBox. You can do so by activating the `profileWireBoxObjectCreation` setting in the `requestTracker`. Once enabled, you will see the profiling of all objects created by WireBox in the debug timers. - -## Profiling Interceptions - -

- -

- -

-Debug Timers -

- -In an event-driven framework like ColdBox, there are tons of events that fire within traditional request/response transactions. You can activate our tracker and we will trace and profile interception calls. Activate it via the settings first: - -```js -// Profile Custom or Core interception points -profileInterceptions : true, -// By default all interception events are excluded, you must include what you want to profile -includedInterceptions : [ "onUserSave", "ORMPostLoad" ], -``` - -Once activated, you can add a collection of interception points to profile in your application. We will track them for you and even if they are ORM calls we will tell you which entity initiated the call. - -## HTTP Request Tracking - -

- -

-

- HTTP Visualizer -

- -The debugger will track all incoming http calls into your application. It will show you all the relevant method, query string, form params, headers, and even the HTTP Body (if enabled). By default, the HTTP Body is ignored as it can be big and tracking it on every request can reduce performance. However, you can easily turn it on and inspect the incoming packets. - -```js -requestTracker = { - // Control the http request reporting - httpRequest : { - expanded : false, - // If enabled, we will profile HTTP Body content, disabled by default as it contains lots of data - profileHTTPBody : true - } -} -``` - -## ColdBox Tracers - -

- -

- -

- ColdBox Tracers -

- -The debugger also ships with a LogBox appender we call the ColdBox Tracer. This tracer will absorb the usage of log `info(), fatal(), error(), warn(), debug()` calls within your application and group them to the request that they initiated from. You can then visualize and inspect them in your debugger. All you have to do is activate it and enjoy! - -```js -// ColdBox Tracer Appender Messages -tracers : { enabled : true, expanded : false }, -``` - -Please note that by default the tracer appender will log any logging level from `fatal` to `debug` to your request tracker and will track anything sent to it. So also note that this can have an impact on performance if you are sending tons of complex objects to the `extraInfo` argument. With much power, comes much responsibility! - -## Hibernate + cborm - -

- -

-

- Grouped cborm calls -

- -We have a dedicated panel in the debugger that will track all criteria queries and `executeQuery()` calls from within your application. It will show you a grouped or a timeline visualizer of all these sql calls. All you have to do is activate it: - -```js -// cborm Reporting -cborm : { - enabled : true, - expanded : false, - // Log the binding parameters (requires CBORM 3.2.0+) - logParams : true -} -``` - -You can also enable `logParams` and we will track the original executable parameters of the query so you can debug the actual values of these executions. We will also track from WHERE in the application the sql execution came from and you can even open the file to that specific line number using our code editor integrations by clicking our **open in editor** buttons. - -> **Note**: CBDebugger's `cborm.logParams` setting requires CBORM 3.2.0 or higher. - -The grouped view you see above will give you an aggregate look of all the sql calls made during the request and their frequency of execution. It will also give you a mini report of those specific sql groups with data about where the query originated from in your source code and the binding parameters, if activated. - -

- -

-

- Timeline cborm calls -

- -The timeline view gives you a track of all the sql requests made via cborm from start to finish in your request. - -## qb/Quick - -

- -

-

- qb/quick calls -

- -We have also created a `qb` and `quick` panel which will track all SQL calls made via `qb` or via `quick` during your request. We offer the same grouped or timeline visualizer for all these sql calls and even the capability to track from where the calls where made from and open them in your favorite editor to the line number. All you have to do is activate it: - -```js -// Quick and QB Reporting -qb : { - enabled : true, - expanded : false, - // Log the binding parameters - logParams : true -}, -``` - -Also remember that you can activate the binding parameters to the sql calls. - -## Adobe ColdFusion SQL Tracking - -We have also created an `ACF Sql` panel which will track all SQL calls made during your request. We offer the same grouped or timeline visualizer for all these sql calls and even the capability to track from where the calls where made from and open them in your favorite editor to the line number. All you have to do is activate it: - -```js -// Adobe ColdFusion SQL Collector -acfSql : { - enabled : true, - expanded : false, - logParams : true -}, -``` - -**Note:** This feature works with `ColdFusion 2018+` and requires the `Database Activity` box to be checked in the ACF `Debugging & Logging` page. If using ColdFusion 2021, you will need the `CF debugger` module installed as well. You can use the ACF CLI package manager, or the CommandBox command of `cfpm install debugger`. If it is not installed, install it and then restart the server before using this module. - -## Lucee SQL Tracking - -We have also created a `Lucee Sql` panel which will track all SQL calls made during your request. We offer the same grouped or timeline visualizer for all these sql calls and even the capability to track from where the calls where made from and open them in your favorite editor to the line number. All you have to do is activate it: - -```js -luceeSql : { - enabled : true, - expanded : false, - logParams : true -}, -``` - -> **IMPORTANT** Please note that to use this feature the engine must have two debugging settings enabled - -```json -"debuggingDBEnabled":"true", -"debuggingEnabled":"true", -``` - -You can easily add those to your `.cfconfig.json` or enable it under the `Debugging` panel in the Lucee Admin. - - -## Modules Panel - -

- -

-

- Modules Tracker -

- -If enabled, we will track also the loaded modules in your application: - -```js -// Modules Reporting -modules : { enabled : true, expanded : false }, -``` - -From the panel you will be able to analyze the registration and activation of all your application modules. You can even reload, unload and execute life-cycle commands against them. - -## CacheBox Monitor - -

- -

-

- CacheBox Monitor -

- -You can also enable the CacheBox monitor and get complete insight into all your registered application caches. - -```js -// CacheBox Reporting -cachebox : { enabled : true, expanded : false }, -``` - -## Debugger Visualizer - -

- -

-

- Debugger Visualizer -

- -A part from debugging the incoming request and presenting the debugger at the end of the request, you can also navigate to `/cbdebugger` and visualize the Debugger request tracker. This panel will monitor ALL incoming requests to your application: rest, soap, ajax, etc. - -You can execute several commands from this visualizer: - -- Clear all request history -- Reinit ColdBox -- Shutdown the debugger visualizer -- Refresh the requests -- Auto refresh the requests - -You can then select a specific request and open the request report with all the tracked information. - -Please note that the request tracker in the debugger has a configurable capacity for requests. By default we track the last 25 requests into the application. You can either increase it or reduce it to your hearts content. Just note that the more you track, the more memory it consumes unless you offload it to an external cache. - -```js -// How many tracking profilers to keep in stack: Default is to monitor the last 20 requests -maxProfilers : 25, -``` - -## Storing Profilers Off-Heap - -You can tell the debugger to store the profilers and instrumentation data off-heap by using the `storage` setting and connecting it to a distributed cache like Redis, Couchbase, Mongo, Elastic, etc. All you need to do is change the `storage` to `cachebox` and update the `cacheName` to point to the distributed cache name you have configured in your `config/Cachebox.cfc`. +You can find how to configure the debugger here: +https://cbdebugger.ortusbooks.com/essentials/configuration -```js -storage : "cachebox", -cacheName : "couchbase" -``` +## Usage -With that configuration, all the profiler data and instrumentation will be sent to the distributed cache. +https://cbdebugger.ortusbooks.com/essentials/request-tracker ******************************************************************************** Copyright Since 2005 ColdBox Framework by Luis Majano and Ortus Solutions, Corp From 1dff5736a222870aa8ff36423cf585c596cb4305 Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Wed, 10 Jan 2024 21:23:38 +0100 Subject: [PATCH 44/45] node build process updates --- .github/workflows/release.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bd3231a..7fafac0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -34,7 +34,7 @@ jobs: - name: Setup nodejs uses: actions/setup-node@v2 with: - node-version: 16.x + node-version: 18.x - name: Setup CommandBox uses: Ortus-Solutions/setup-commandbox@v2.0.1 @@ -63,7 +63,6 @@ jobs: - name: Build ${{ env.MODULE_ID }} run: | - npm i npm@latest -g npm install npm run prod rm -Rf node_modules From fef0d415b8cd18f6598cbcfc39dcce7eba6f4e5b Mon Sep 17 00:00:00 2001 From: Luis Majano Date: Wed, 10 Jan 2024 22:23:22 +0100 Subject: [PATCH 45/45] updated build scripts to latest versions --- .github/workflows/pr.yml | 2 +- .github/workflows/release.yml | 18 +++++++++--------- .github/workflows/snapshot.yml | 4 ++-- .github/workflows/tests.yml | 8 ++++---- build/release.boxr | 11 ----------- 5 files changed, 16 insertions(+), 27 deletions(-) diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index d78c2d7..a48c550 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - uses: Ortus-Solutions/commandbox-action@v1.0.2 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7fafac0..dc09e6a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -29,10 +29,10 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup nodejs - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: node-version: 18.x @@ -72,7 +72,7 @@ jobs: box task run taskfile=build/Build target=run :version=${{ env.VERSION }} :projectName=${{ env.MODULE_ID }} :buildID=${{ github.run_number }} :branch=${{ env.BRANCH }} - name: Commit Changelog To Master - uses: EndBug/add-and-commit@v9.1.1 + uses: EndBug/add-and-commit@v9.1.3 if: env.SNAPSHOT == 'false' with: author_name: Github Actions @@ -81,7 +81,7 @@ jobs: add: changelog.md - name: Tag Version - uses: rickstaa/action-create-tag@v1.6.1 + uses: rickstaa/action-create-tag@v1.7.2 if: env.SNAPSHOT == 'false' with: tag: "v${{ env.VERSION }}" @@ -90,7 +90,7 @@ jobs: - name: Upload Build Artifacts if: success() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ${{ env.MODULE_ID }} path: | @@ -126,7 +126,7 @@ jobs: box forgebox publish --force - name: Create Github Release - uses: taiki-e/create-gh-release-action@v1.6.2 + uses: taiki-e/create-gh-release-action@v1.8.0 continue-on-error: true if: env.SNAPSHOT == 'false' with: @@ -146,7 +146,7 @@ jobs: steps: # Checkout development - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: development @@ -156,7 +156,7 @@ jobs: forgeboxAPIKey: ${{ secrets.FORGEBOX_TOKEN }} - name: Download build artifacts - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: ${{ env.MODULE_ID }} path: .tmp @@ -173,7 +173,7 @@ jobs: # Commit it back to development - name: Commit Version Bump - uses: EndBug/add-and-commit@v9.1.1 + uses: EndBug/add-and-commit@v9.1.3 with: author_name: Github Actions author_email: info@ortussolutions.com diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index 45d7dd1..37e3183 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -20,7 +20,7 @@ jobs: name: Code Auto-Formatting runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Auto-format uses: Ortus-Solutions/commandbox-action@v1.0.2 @@ -28,7 +28,7 @@ jobs: cmd: run-script format - name: Commit Format Changes - uses: stefanzweifel/git-auto-commit-action@v4 + uses: stefanzweifel/git-auto-commit-action@v5 with: commit_message: Apply cfformat changes diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9271bb2..0258607 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -36,11 +36,11 @@ jobs: experimental: true steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Java - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: "temurin" java-version: "11" @@ -95,7 +95,7 @@ jobs: - name: Upload Test Results to Artifacts if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: test-results-${{ matrix.cfengine }}-${{ matrix.coldboxVersion }} path: | @@ -108,7 +108,7 @@ jobs: - name: Upload Debug Logs To Artifacts if: ${{ failure() }} - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: Failure Debugging Info - ${{ matrix.cfengine }} - ${{ matrix.coldboxVersion }} path: | diff --git a/build/release.boxr b/build/release.boxr index e216f22..a63f2cc 100755 --- a/build/release.boxr +++ b/build/release.boxr @@ -7,19 +7,8 @@ # Merge development into it for release !git merge --no-ff development -# Tag the master repo with the version from box.json -!git tag v`box package show version` - # Push all branches back out to github !git push origin --all -# Push all tags -!git push origin --tags - # Check development again !git checkout -f development - -# Bump to prepare for a new release, do minor, change if needed and don't tag -bump --minor --!tagVersion -!git commit -a -m "version bump" -!git push origin development \ No newline at end of file