Tutorials/Observability

Seeing what Storm does

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.

Series · The Storm way3 min readKotlin

01The task

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.

02Scoped SQL logging

@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:

UserRepository.kt Kotlin · Storm
1
2
3
4
5
6
7
8
9
10
// 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)
}

03Copy-paste executable SQL

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:

UserRepository.kt Kotlin · Storm Show SQL
1
2
3
4
5
6
// 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)
}
generated sql
-- 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.

04Beyond logging

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.

05Keep going

The reference documentation covers the mechanics in depth: