0
votes

How do I tune my debug logging level statements for performance? I ask because my spring batch job can call roughly 50 of these logger.debug statements (doing more or less the same) a couple million times per job.

Query:

private final String updateIsUserFl = "update users "
+ "set flag = 'Y' "
+ "where name = ? and id = ? ";

Query Execution:

myJdbcTemplate.update(updateIsUserFl, name, id);

Logging Statements:

String debugQuery = updateIsUserFl.toString();
logger.debug(replace(debugQuery, "?", name, 1));
logger.debug(replace(debugQuery, "?", Integer.toString(id), 1)); 

Specific Questions:

  1. So, basically, I want to print out the exact query passed in to my JdbcTemplate. Is there a better / less costly way than StringUtils.replace? Hopefully a little less heavy-handed as well (for maintainability sake).

  2. Is calling toString on updateUserFl the right / efficient way to copy a final string object to do string manipulation?

  3. Would wrapping this in an if logger.IsDebugEnabled check help or is slf4j already doing this for me?

  4. Can I use logback / {} (in some way I can't think of) to help?

  5. Is the log4j2, Java 8 (lambdas) an option I should consider? See: Avoid Log4j/Slf4j debug enabled checks

2
Just a very generic hint, as I don't know much about spring: in general, the JVM works nicely with lambdas, so chances are that some expression that uses lambdas has better performance than another, non-lambda solution. So if possible, you might want to look into that. - GhostCat

2 Answers

3
votes

This will work with org.springframework.jdbc-3.0.6.RELEASE.jar. TRACE level will do the thing .

I'm using log4j-1.2.15 along with slf4j (1.6.4) and properties file to configure the log4j:

log4j.logger.org.springframework.jdbc.core = TRACE

This displays both the SQL statement and bound parameters like this:

Executing prepared SQL statement [select HEADLINE_TEXT, NEWS_DATE_TIME from MY_TABLE where PRODUCT_KEY = ? and NEWS_DATE_TIME between ? and ? order by NEWS_DATE_TIME]
Setting SQL statement parameter value: column index 1, parameter value [aaa], value class [java.lang.String], SQL type unknown
Setting SQL statement parameter value: column index 2, parameter value [Thu Oct 11 08:00:00 CEST 2012], value class [java.util.Date], SQL type unknown
Setting SQL statement parameter value: column index 3, parameter value [Thu Oct 11 08:00:10 CEST 2012], value class [java.util.Date], SQL type unknown

SQL type we can ignore it here

For just an SQL (i.e. if you're not interested in bound parameter values) DEBUG should be enough.

0
votes

First of all, you could leverage the existing Spring logging mechanism to see your queries and parameters as @Mr. Noob pointed out.

If you want to optimise your own logging, there're a couple of things to consider:

  1. Calling updateIsUserFl.toString() is redundant. updateIsUserFl is already a String that contains your query. When you call replace() on a String, it returns a new String instead of changing the existing one (Strings are immutable in Java).
  2. Check logging level before constructing log messages. There's no need to do all those operations if the message won't eventually make it to the log. Log4j does the same check but only after you have already spent resources on building your log message.
  3. replace() is not a good choice here (it uses regular expressions). It's better to add the parameter values to the end of the SQL-statement. It will be enough for analysis.

So, finally, you could do that:

if (logger.isDebugEnabled()) {
    logger.debug(String.format("%s; name=%s, id=%d", updateIsUserFl, name, id));
}

And yes, Java 8 and Log4j2 is an option worth considering. It will allow you to use lazily executed lambdas instead of level checks. It's also generally faster and less memory-consuming.