Fork me on GitHub

October 30, 2009

Log4J Logging without Log4J

Post moved to http://log2.kares.org/post/59891230405/log4j-logging-without-log4j

As time goes by, ridiculous challenges might arise to a J2EE developer. This one starts with a third party web application that needed to be part of an enterprise application (running on WebLogic). The war was closed source, with business classes obfuscated in a jar inside WEB-INF/lib, and as many out there using LOG4J as it's logging facility (with commons-logging as a cherry on top due to some dependencies).
So far so good, now what if the root logger name is chosen unwisely and it interferes with your application server's logger categories.

At first the solution seemed obvious, the WEB-INF classes and libraries should be loaded first by the servlet container, thus having a separate LOG4J configuration created from the web application's class path. WebLogic 10.3 likes to prefer its own system jars by default, thus an (optional) step for the lucky ones :



That was easy, but what if ... LOG4J's runtime reconfiguration ("watch dog") is involved and You can't or don't want to turn it off. Well than this might just get messy, especially if other applications within the same ear, or the server itself, use LOG4J for logging.

I won't go into any more details here, some things tend to get a little noisy in the Java world.
Anyway, I had no meaningful option left than to get somehow rid of LOG4J from the war, obviously that would break the application wouldn't it ? Sure, but what if one could emulate the org.apache.log4j.Logger API.
The one here wouldn't be me, I do prefer others doing the dirty work, in this case Simple Logging Facade for Java (SLF4J) to the rescue !

The SLF4J distribution contains several jars, here's what we need :
  • slf4j-api.jar - SLF4J's own logging API
  • log4j-over-slf4j.jar - log4j compatible API that delegates to SLF4J
  • jcl-over-slf4j.jar - (optional) commons-logging compatible API that delegates to SLF4J
Don't forget to delete log4j.jar and commons-logging.jar, once the SLF4J jars were added.
Finally, we should pick a SLF4J logging implementation, I've chosen LOGBack here, as I wasn't into rewriting the log4j.properties by hand, thus add these :
  • logback-core.jar
  • logback-classic.jar
Once all those fancy new jars are in place (WEB-INF/lib) and log4j.properties configuration was translated into logback.xml (save it into WEB-INF/classes), restart and bone appetite !

Of course, it wouldn't be a WebLogic if it went smoothly, but don't worry those scary red system console outputs :

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [zip:/weblogic/domains/.../war/WEB-INF/lib/logback-classic-0.9.17.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [zip:/weblogic/domains/.../war/WEB-INF/lib/logback-classic-0.9.17.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.

are caused by a ClassLoader bug reported here, but it's not fatal and SLF4J can live with it.

September 6, 2009

Handling XML/JSON Errors in Rails

Post moved to http://log2.kares.org/post/59891229302/handling-xml-json-errors-in-rails

The first time I run into this, I was just feeling so upset. I wasn't in a "railsy" mood for a while, my colleague posted an incorrectly formatted xml to our staging server and told me he got 500. No way, I said !
Slap - in my face, nothing useful in the logs, it was happening ...

My ruby-ninja sense came up with the following :



Of course it needs to check in a before filter for request.env['EXCEPTION'] to be re-raised if found ...

Few months later, I've put together a plugin to handle XML/JSON parse errors and treat parsing exceptions like other raised errors, an example is more than 1024 words :



Please realize, that even if exceptions are treated equal those related to request parameter parsing probably caused some parameters to be not available in your controller code (you obviously can't access params[:user] when posting an invalid user XML snippet) and thus you should NOT recover from those !

The primary intent of this plugin is to be able to customize the default HTTP 500 status returned by Rails.

UPDATE: Starting Rails 2.3.5 ActiveSupport::JSON::ParseError is gone, you'll have to use the JSON backend's parse error for rescuing (available at ActiveSupport::JSON.parse_error).

UPDATE: As Rails 3.0.0 did not really update the code that handles parameter parsing errors, the plugin has been reviewed to work with 3.0.0 (and is threadsafe).

See the plugin at http://github.com/kares/request_exception_handler.

August 30, 2009

Trimming BLOBs from Rails Log

Post moved to http://log2.kares.org/post/59891226819/trimming-blobs-from-rails-log

If you're using some BLOB data in ActiveRecord (e.g. user pictures stored in DB), then you may have noticed that the Rails logging simply prints the INSERT/UPDATE SQL containing the raw binary content. Now for me (at least in development env) this is pretty useless and besides my terminal seems to be getting crazy out of it.
As usual I thought someone must have done it before and found this post. It's pretty outdated since it targets Rails 1.x, so I decided to make it work with Rails 2.x and here's what I got :



Put this monkey-patch into a file named trim_blob_logging.rb into your RAILS_ROOT/lib directory. Then require 'trim_blob_logging' in environments/development.rb.

Now, instead of being bloated with binary bits, your blob log entries should look similar to this one:


INSERT INTO db_files (data) VALUES(x'ffd8ffe000104a464946000101010048... (14133 bytes)')


As a home work you might further improve your SQL logs with stats (bytes transferred from DB per request), it's all in here done for Rails 1.x.

Thanx http://gurge.com/blog for the inspiration !