Predictable SQL is only reassuring if you can look at it. @SqlLog shows every statement a repository runs, inlined parameters make the output executable, and metrics expose what the caches are doing.
A query misbehaves in one corner of the application. You want to see the exact SQL that corner runs, reproduce it in a database client, and confirm the fix, without turning on firehose logging for the whole system.
@SqlLog works at the repository or method level, so the logging follows the code you are investigating rather than the whole datasource. It lives in storm-foundation and needs no Spring AOP:
// Log every statement this repository executes @SqlLog interface UserRepository : EntityRepository<User, Int> { fun findByEmail(email: String): User? = find(User_.email eq email) fun findActiveUsers(): List<User> = findAll(User_.active eq true) }
By default the log shows the statement as sent, placeholders included. For debugging, inlineParameters = true substitutes the bound values, producing SQL you can paste into a client to inspect the result set or check the plan with EXPLAIN:
// For debugging: inline the bound values into the logged SQL @SqlLog(inlineParameters = true) interface UserRepository : EntityRepository<User, Int> { fun findByEmail(email: String): User? = find(User_.email eq email) }
-- inlineParameters = false (default): the statement as sent SELECT u.id, u.email FROM "user" u WHERE u.email = ? -- inlineParameters = true: paste it straight into your database client SELECT u.id, u.email FROM "user" u WHERE u.email = 'alice@example.com'
Log level and logger name are configurable per annotation, so the output can route to its own appender. Inlined values are for debugging, not production logs; keep the default for statements that carry sensitive data.
Two companions complete the picture. In tests, SqlCapture turns statement counts and shapes into assertions, so what you observed while debugging becomes a regression test. And at runtime, Storm exposes metrics for the template cache, entity cache, and dirty checking over JMX, which answer the quieter questions: are cached plans being reused, and how much work is dirty checking saving. See Metrics.
The reference documentation covers the mechanics in depth: