Virtual Surreality
It’s too real to be true


Kiva - loans that change lives

November 26, 2006

How much wood would a woodchuck chuck?

Filed under: Coding — Josh Graham @ 3:48 am

Imagine, if you will, a core application’s code base that stretches back ten years, has around 3,500 classes, and 15,000 compiler warnings.

In its germination, the Java industry had confused ideas about interoperability, no standard collections, no O/R mapping frameworks, application servers (lightweight or otherwise), and no sensible OO patterns of enterprise architecture to be found lazing around in better bookstores.

Logging was a matter of System.out.println(). A couple of years later, someone decided to add a static logging class who Log.println() at least allowed directing the logs to named files, but no log levels were envisioned. As the code base grew, production support and new developers relied on log contents to help profile execution. This became so useful and popular, that at first service entry points and then nigh on every method logged its entry and exit, along with timings. Any logging levels that had been differentiated were made redundant because log entries were so voluminous that it was probably a Bad Idea to remove any of them lest the application logic no longer be trackable. Years later still, a few minor sporadic attempts to integrate Log4J and then Commons Logging were made. The homespun Log class was marked deprecated to discourage developers from using it, and hope they would instead move to Commons Logging.

Good intentions, all, but now facing a situation that the logging generates some 2GB every hour in a multi-day batch run, generating the method profiling logs account for a tidy fraction of the execution time, and code which struggles under complicated business logic implementation is made even more difficult to comprehend with cross-cutting complication like the multiple logging mechanisms sprinkled throughout.

Recently, a small discussion has started up looking at ways to deal with this. Options include: Remove the deprecated annotation on the in-house Log class - at least that reduces compiler warnings; Ask each developer to manually the logging for a class whenever it is modified - it might take a year but at least it gets done, but then the developers are too busy nutting out how to add the latest business functionality, the logging issue is a back-of-the-mind thing; Have the in-house Log class delegate to Commons Logging - but there was effectively only One Log before and knowing which method was logging was handled by visual inspection of the method profiling logs; Global, clever search-and-replace scripts to brute-force the code change.

Which option would you choose? Heavylifting is easier with a long plank than raw biceps. All of those options have merit in different circumstances, and in this one all of them can be used in degrees to get the best outcome for the developers, IT, and the business.

So, start with making the in-house Log class behaving more like Commons Logging. First of all, we’ll rename it from “Log” to “LegacyLog” to help with moving to org.apache.commons.logging.Log. It currently has a pattern of usage like this:

package legacy.code;
import legacy.common.util.logging.LegacyLog;
public class Order {
    public Order() {
        LegacyLog.initialise("Order");
        LegacyLog.println("Order class constructed");
    }
    public void place() {
        Profile.entry("Order.place");
        doOrderPlacement();
        Profile.exit("Order.place");
        return;
    }
}

The Profile class happens to use the Log class to log the entry to the method and the exit, with the exit including the number of milliseconds the method was running.

So, the string sent to Log.initialise is the unqualified class name. We want to transform it into something like this:

    Log log = LogFactory.getLog(Order.class);

We could do a global search-and-replace to take the string, strip the double-quote marks, make it capitalised, and append a “.class” to it - or even just change them all to LegacyLog.initialise(this.getClass()); if we don’t entirely trust the content of the string anyway.

As LegacyLog is used in a static context, it’s rather hard to track that information when methods call other methods that initialise the stack. Let’s do something like this to store a Log for each class in LegacyLog’s static state:

    private static Map<Integer,Class> logsForClasses = new HashMap<Integer,Class>(1000);
    int hash = hash(classToLog);
    if (!logsForClasses.containsKey(hash)) {
        Log log = LogFactory.getLog(classToLog);
        logsForClasses.put(hash, log);
    }
    private static int hash(Class clazz)
    {
        return clazz.hashCode();
    }

How to get the classToLog? We only get unqualified class names in the argument to LegacyLog.initialise and we don’t entirely trust it. We could walk the stack, or use the sun.reflect.Reflection class to find our caller:

    static Class getCallerClass(int skip) {
        // I trust Reflection is more efficient than creating a Throwable and walking the stack trace...
        Class caller = null;
        // break out of this class first (always at least 2 deep in stack)
        int i = 2;
        caller = Reflection.getCallerClass(i);
        while (hash(LegacyLog.class) == hash(caller)) {
            i++;
            caller = Reflection.getCallerClass(i);
        }
        if (skip > 0) {
            caller = Reflection.getCallerClass(i + skip);
        }
        return caller;
    }
    static Class getCallerClass() {
        return getCallerClass(0);
    }

My comment about efficiency is that I hope Reflection.getCallerClass is using native internal JVM methods to pluck out the caller rather than me doing it myself with the expensive new Throwable().getStackTrace() technique. GNU’s version uses something called VMWalker, and based on my performance tests, I think it is (but you never know with Sun).

With that, we can now log out a message using the logger, selected by Log4J, of the calling class:

    /**
     * Legacy method
     * Equivalent of getLog().info(message)
     */
    public static void print(String message) {
        getLog().info(message);
    }
    /**
     * Migrating method.
     * If you’re using this directly, you might as well go the whole way.
     */
    public static Log getLog() {
        return logsForClasses.get(hash(getCallerClass()));
    }

The INFO log level has been used for legacy messages. This is to allow a reasonable default of WARN to be used for production runs and balance that against to much (ill-considered) log data. INFO is the lowest level that should be used in production, and this implementation suggests that it should only be switched on when necessary. DEBUG and TRACE are for development use and should not be on in production. This allows development-level log messages to be included in the code but not come close to being used in production runs.

log4j.rootLogger=WARN, A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
# Print the date in ISO 8601 format
#log4j.appender.A1.layout.ConversionPattern=%d [%t] %-5p %c [%F:%L] - %m%n
log4j.appender.A1.layout.ConversionPattern=%d [%t] %-5p %c - %m%n
# Print only messages of level DEBUG or above in the package legacy.common.util.logging
log4j.logger.legacy.common.util.logging=DEBUG

As a not-insignificant aside, the layout patterns %F and %L don’t work - it reports the LegacyLog location, not the caller. It’s quite expensive anyway (creating a Throwable every log, and walking the stack adding about 200% to the logging execution time) and should be reserved for TRACE log levels (DEBUG if really necessary). Short of altering the LocationInfo class in Log4J (or chosen logger) to pop up the stack one more level (to skip LegacyLog), if the developer wants location information, they’ll have to not use the LegacyLog class and the journey will be complete.

In the full code, logged exceptions are show as ERROR, because although the old messy “log-and-rethrow” pattern is used, it is using code written back when a cause wasn’t passed on a rethrow, so the logged exception was the easy way to find out what was going on. Changing that behaviour is another exercise.

With this, the deprecation can be removed. Gradual improvement, as required, is fully supported and explicit changes to make legacy log messages more visible (and hopefully meaningful) are encouraged. Even global search-and-replace is made easier. The old LegacyLog.initialise can be replaced as described earlier, and with a few tweaks, the print method and its brethren can be inlined.

However much more “smelly” that is, it is a further avenue of pursuit. Looking at how Chainsaw can help clean up the originating logging source as well as be used as a harness for automated tests of logging systems is also of further interest. The omitted, but very long (I’ve got logs created for around 2500 classes) performance test may show that something like the GNU Trove collections out-perform the Java ones (http://trove4j.sourceforge.net/overview.shtml), but I’m yet to give them a whirl.

Anyway, the source will be here for a first start.

1 Comment »

  1. Blogger - pfeh. The generic types were dropped because I didn’t type &lt; … well I’ll put the link to source up in the morning and it’ll show you what it should be.

    Comment by Joshua Graham — March 2, 2007 @ 12:00 am

RSS feed for comments on this post. TrackBack URL

Leave a comment

Powered by WordPress

payday loan daily payday cheap long term payday loans cash loans till payday service no fax payday loans asp direct lender payday loans payday loans denver nd news story payday loans outlawing payday loans north dakota cash advance payday loans software califronia payday loans no fax payday loan payday loanonline payday loans no fax payday loans uk poor credit loan construction to south carolina cash advance payday loans payday loans located in stone mountain georgia easy no fax payday loans online payday loans no pay day fax gardena california payday loans payday loans with payback in installments fast cash payday loans in advance kansas city payday loans and cash advance loans payday loans with payments cash loans net payday till payday advance cash til payday loans in atlanta montana payday loan 500 payday loan online payday no fax payday loans payday loans no job credit check payday loans quick cash instant payday loan fast c payday cash loan payday cash loans bad credit payday loans no fax utah cash advance payday loans online payday loans project payday no teletrack payday loans instant payday loan payday loan fraud washington state faxless payday loans cash advance payday loan payday loans online no fax payday loan payday advance loans low fee payday loans geneva roth payday loans payday lenders ten dollar payday loan bad credit payday loans payday candy bar payday loan lenders default payday loan bad credit debt consolidation internet payday loan student no fax payday loans online cash advance loan sonic cash payday loan with no faxing or employment verification savings account payday loans no telecheck payday loans payday loan walpole instant payday loans i need a payday loan immediately payday cash advance legitimate payday loans payday loan with no credit check or no faxing payday max fast cash payday loan cheap payday loans free payday loan payday ok bad credit payday loan payday loans for bad credit sonic payday cash till payday military payday loans payday loan software payday loans online cash advance loan personal payday loans no credit check no faxing no paper consolidation debt loan payday cheap payday loan cash fast loan online payday tendollar payday loan payday loans national cash advance bad credit payday loan payday cash loan online payday loans payday loan p no fax payday loans savings account payday loans uk payday loan no fax payday select faxless payday loan same day payday loans check advance paycheck payday cash loans charlesto personal loans payday loans 1500dollarstoday com easy online payday loans payday cheques easy payday loans low cost payday loans fast cash advances payday loans payday loan relief help state law free payday loans can you tell the payday loans to stop call you at work borrow money now cash advance simple payday loan preferred missouri cash advance and payday loans cheapest payday loans fastbucks instant online payday loans fast cash advance online payday loan new mexico victims of payday loans payday loan manual easy no teletrack or telecheck payday loans no teletrack payday loan payday loans no credit check payday loan by western union i need money now easy payday loan borrow fast advance cash loan online payday payday loans gold coast i want a no teletrack payday loan easy no fax payday loans payday loans no credit check payday loan approved loan online payday payday loans no fax payday loans online payday advance fast where can i buy payday loan forms cash advances advance cash online payday loans pre payday no bank account xtra cash payday loan online cash payday loan online payday loans online sonic payday loan payday paycheck loan quick no fax payday loans online payday loan payday loan canada no fax no bank payday advance loans payday loons without fax free same day payday loans online direct payday lenders no credit checks or faxing online instant fax payday loans online instant no fax payday loans texas cso payday payday advances how to obtain multiple faxless payday loans advance cash payday loans online loan canadian payday loans cheat at payday freecell western union sent payday loan fast payday loan advance cash payday loans online cash advance loan title loan florida auto and payday loans online payday cash advance instant loans payday loans payday loan online cashadvancesusa com low interest payday loans payday cash loans fast usa only payday loans online no faxing up to 241500 genovone roth payday loans canada student loans payday advance mo payday loan payday loan online bad credit cash advance payday loan cash advance loan illinois quick advance advance cash loan payday no requirement payday loan fast payday loans best payday loans payday loan business no fax payday loans online b cash advance b loan completely instant loan payday payday loans with no faxing and instant approval payday loan softwear low rate payday loan payday loan qualifications no bank account payday loan oklahoma fast cash advance payday loan payday scam calls cash day fast loan pay payday quick cash advance payday loan online loans advance cash loan payday payday loan industry statistics no fax or verification payday loans payday loan no fax search long term payday loans magnum low cost payday loan payday loan franchise payday loans no fax no teletrak how to get out of payday loans no income doc payday loans attorney for payday loans nc indian wells payday loan payday cash loan savings account payda military loans online payday loans cash a1paydayad guaranteed payday loan payday loan service new jersey online payday loans savings account payday loan instant payday loans online cash deposit direct fax loan payday cash apply fastest payday loans online litchfield payday loan fast loans bad credit online approval payday quick payday loans online one hour payday loans emerengency no fax payday loans no fax payday advance no credit check bad credit faxless payday loans quick payday loans fast online payday loans criminal prosecution default payday loan louisiana genove payday loans washington cash advance payday loans software attorney for payday loans texas cash advance payday loans software payday loan in florissant missouri direct payday loans quick payday loan low fee payday loan njfastcash personal loans online payday loan payda payday loan cash advance bz credit no fax payday loans faxless payday advance no fax cash zip payday loans miami payday loan cash advance payday loans bad credit payday cash loan scams direct lender payday advance online instant payday loans completely online no teletrack or no fax payday loans texas payday loan stories about westbury ventures payday loans cash advance las vegas payday loans paycheck advance online short term payday loans 500 payday cash advance utah payday loan companies payday loan pay back in 1 week cash advance or payday loan direct payday loan payday loans advance pay day loans online cash advance quick almost instant cash advance payday loans payday loan online refinance home loans loan until payday payday loans in new jersey payday loans auto title bad credit loans andnot payday loan savings account no fax payday loans payday cash advance loans online low interest payday loan payday loans cash advance online payday loans military loans delaware cash advance and payday loans cash advance now payday loan california cash advance cash advance payday loans online cash advance payday colorado advance cash ga in loan payday california cash advance payday loan pay advance payday loans online paycheck advance p advance cash loan payday through union western wired money payday payday payday advance loan payday loans no fax or credit check faxless payday loans no checking account no faxing and no credit check payday loans cash advance loan illinois payday loans online cas no fax cash in 1 hour payday loans emergency advance payday hold personal check cash loans i want a no teletrack and a no telecheck payday loan payday loans fast new improved payday cash advance loans chicago payday loans payday cash loans no faxing all online bad credit loans for military payday loans militar payday loan salt lake city payday loan bad credit knox payday loan payday one cash payday loans online payday loans with no faxing or credit check banks issue payday loans payday loan in chicago illinois