jdaugherty opened a new pull request, #16631:
URL: https://github.com/apache/grails-core/pull/16631

   A page that is slow because it runs hundreds of queries is easy to miss in a 
log: `logSql` prints every statement, but not which page ran it or how many a 
request added up to. This adds the `sql-tail` command, which shows the pages of 
a running application ranked by the statements they run per request, and for 
each page the statement that repeats most within one request, which is what an 
N+1 looks like.
   
   ```
   grails run-app --sql-tail      # or ./gradlew bootRun 
-Pgrails.gorm.sqlTail.enabled
   grails sql-tail                # in a second terminal
   ```
   
   ```
   sql-tail build/sql-tail/capture.log  312 statements in 14 requests  
(refreshes as statements run; Ctrl-C to stop)
   PAGE        REQUESTS  AVG/REQ    MAX   TOTAL  MOST REPEATED IN ONE REQUEST
   book/show          6     48.0     61     288  44× select ... from author 
a1_0 where a1_0.id=?
   book/index         5      4.2      5      21  5× select ... from book b1_0
   ```
   
   `--statements` ranks the statements, `--page=book/show` shows one page's, 
`--stream` prints each statement as it runs with a header per request, and 
`--all --once` reports a whole run, including an integration test run.
   
   ### Design
   
   - **No cost unless asked.** Capture is on only when 
`grails.gorm.sqlTail.enabled` is set at startup. An application started without 
it carries no statement inspector, no thread and no check per statement. 
`run-app --sql-tail` and `bootRun -Pgrails.gorm.sqlTail.enabled` set it for one 
run; it can also be kept in config for development.
   - **Attribution per page.** `SqlTailStatementInspector`, installed by the 
Hibernate 5 and Hibernate 7 connection source factories, records each statement 
on the request thread. `SqlTailRequestAttribution` reads the controller, action 
and namespace Grails resolved for the request and gives every statement of one 
request the same id, so interceptors, the action and GSP rendering count for 
the same page. Work on other threads is shown under the thread name. An 
inspector the application configured itself through 
`hibernate.session_factory.statement_inspector` keeps running; the capture 
records the statement it returns.
   - **Where it lives.** The writer, record format and settings are in 
`grails-datamapping-core` (Spring Web compile-only and guarded). The command is 
a script command in a new `grails-datamapping-core-cli` companion, so the 
`grails` shell runs it without booting the application; the reader, collapser, 
summary, renderer and runner sit beside it. The capture file is 
`sql-tail/capture.log` under the build directory, resolved as `BuildSettings` 
resolves it, tab separated and truncated per run; the reader resets when the 
application restarts.
   - **Gradle.** The Grails Gradle plugin hands `-Pgrails.gorm.sqlTail.*` 
properties to forked application and test JVMs through a 
`GrailsPropertyArgumentProvider` that the startup progress forwarding now 
shares. No Gradle task is added for the command itself; script commands have no 
Gradle entry point today, and that is left for a separate decision.
   
   ### Documentation
   
   - New reference page `sql-tail`, and the `--sql-tail` flag on the `run-app` 
page.
   - New guide section *Finding Query-Heavy Pages with sql-tail* under *The 
DataSource*, including the shell's limitation with a build directory moved in 
`build.gradle`.
   - What's New entry, and configuration metadata for 
`grails.gorm.sqlTail.enabled` and `grails.gorm.sqlTail.file`.
   
   ### Verification
   
   - `grails-datamapping-core`: full `test` and the new `testCli` phase 
(settings, record, attribution, capture; collapser, summary, reader, renderer, 
runner, and the script compiled and run the way the shell does).
   - `grails-data-hibernate7-core` and `grails-data-hibernate5-core`: full 
suites, including the new inspector specs (no inspector without the flag, 
capture with data source names, every data source to one file, a configured 
inspector by class name and as an instance, an unloadable one reported).
   - `grails-gradle`: `GrailsGradlePluginToolchainSpec` with the new 
fork-settings features.
   - `codeStyle` and `validateDependencyVersions` on the touched modules.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to