Available in versions: Dev (3.20) | Latest (3.19) | 3.18 | 3.17 | 3.16 | 3.15 | 3.14 | 3.13 | 3.12 | 3.11 | 3.10
Example: Logging abbreviated bind values
Applies to ✅ Open Source Edition ✅ Express Edition ✅ Professional Edition ✅ Enterprise Edition
When implementing a logger, one needs to carefully assess how much information should really be disclosed on what logger level. In log4j and similar frameworks, we distinguish between FATAL
, ERROR
, WARN
, INFO
, DEBUG
, and TRACE
. In DEBUG
level, jOOQ's internal default logger logs all executed statements including inlined bind values as such:
Executing query : select * from "BOOK" where "BOOK"."TITLE" like ? -> with bind values : select * from "BOOK" where "BOOK"."TITLE" like 'How I stopped worrying%'
But textual or binary bind values can get quite long, quickly filling your log files with irrelevant information. It would be good to be able to abbreviate such long values (and possibly add a remark to the logged statement). Instead of patching jOOQ's internals, we can just transform the SQL statements in the logger implementation, cleanly separating concerns. This can be done with the following VisitListener
:
// This listener is inserted into a Configuration through a VisitListenerProvider that creates a // new listener instance for every rendering lifecycle public class BindValueAbbreviator extends DefaultVisitListener { private boolean anyAbbreviations = false; @Override public void visitStart(VisitContext context) { // Transform only when rendering values if (context.renderContext() != null) { QueryPart part = context.queryPart(); // Consider only bind variables, leave other QueryParts untouched if (part instanceof Param<?>) { Param<?> param = (Param<?>) part; Object value = param.getValue(); // If the bind value is a String (or Clob) of a given length, abbreviate it // e.g. using commons-lang's StringUtils.abbreviate() if (value instanceof String && ((String) value).length() > maxLength) { anyAbbreviations = true; // ... and replace it in the current rendering context (not in the Query) context.queryPart(val(abbreviate((String) value, maxLength))); } // If the bind value is a byte[] (or Blob) of a given length, abbreviate it // e.g. by removing bytes from the array else if (value instanceof byte[] && ((byte[]) value).length > maxLength) { anyAbbreviations = true; // ... and replace it in the current rendering context (not in the Query) context.queryPart(val(Arrays.copyOf((byte[]) value, maxLength))); } } } } @Override public void visitEnd(VisitContext context) { // If any abbreviations were performed before... if (anyAbbreviations) { // ... and if this is the top-level QueryPart, then append a SQL comment to indicate the abbreviation if (context.queryPartsLength() == 1) { context.renderContext().sql(" -- Bind values may have been abbreviated"); } } } }
If maxLength were set to 5, the above listener would produce the following log output:
Executing query : select * from "BOOK" where "BOOK"."TITLE" like ? -> with bind values : select * from "BOOK" where "BOOK"."TITLE" like 'Ho...' -- Bind values may have been abbreviated
The above VisitListener
is in place since jOOQ 3.3 in the org.jooq.tools.LoggerListener
.
Feedback
Do you have any feedback about this page? We'd love to hear it!