Upgrading to log4j2
10 Feb 2019Logging is a critical part of any application. Without proper logging, teams resort to debugging in Production to diagnoze mysterious issues, Yikes!! I have been there and continue to live in that hell with legacy software which we all have to work with at some point.
Great, now everyone is on board with logging! Let’s fix this debugging in Production issue by adding logging in all our methods after every variable is set. Having all the information will fix everything right? -_____-. Pretty soon we realize that our excessive need for information and logging is bringing our application down. All that I/O is not cheap. Logging as with all of software development is something that has to be tweaked according to our needs as the code base grows. Too little or too much can have serious consequences.
Say we have tweaked our logging needs to log the exact amount of information with all the different levels configurable for different needs. Since we are working on a Java application, we use the widely used log4 framework. Everything goes great till we scale to process 10x the load we tested for. We scramble to make our code handle the load but we still run into mysterious bottlenecks. You got it, its logging again! Log4j-1-x logs synchronously, so as we process enormous loads, all that synchronous I/O eventually catches up and slows the application down. Logging is important but it is not critical enough to be the bottleneck. This brings us to Log4j2 and asynch loggers.
Log4j2 uses asynch loggers which use the LMAX disruptor to log asynchronously and performs ridiculously better than log4j1. Please read this for more information on how and why it is so much faster.
Here are the steps I followed to upgrade from log4j1 to log4j2:
- Add the below entries to your pom. For log4j2 versions greater than 2.8, use disruptor version greater than 3.3:
- Since log4j2 changed the logger package from org.apache.log4j.Logger to org.apache.log4j.logging.Logger, I wanted to write a wrapper around this so I did not have to change thousands of class files next time the package changed:
- Create the below log4j2.xml to configure logging. I have mixed asynch and synch loggers here, but you can just set all loggers to asynch with the following system property:
- Pass in JVM argument to provide path to the log4j2.xml file:
- This was enough to get most of my logging done asynchronously but I still could not get hibernate logging to work. I had to do some additional configuration for the same:
Add the following slf4j dependency:
Pass in JVM argument for the jboss logging provider since Hibernate uses jboss logging: