Showing posts with label Programming. Show all posts
Showing posts with label Programming. Show all posts

Thursday, April 15

How to pick a log level

While I, in no way, feel that I am the expert in this area this is how I select which log level I use for a message.  The number of applications that fail to have a coherent strategy for this is mind boggling.  Logging should not be a second thought or something that doesn't matter.  Especially when fixing a bug is extremely time sensitive, the more information you can concisely pack into a log message the better.  So here are the guidelines I use for selecting the log level I am going to use.


  1. Debug - Messages necessary for debugging a piece of functionality.  A value of some sort should always be appended to the message as there is very little that can be gleaned from the state of the application if you don't know some values.  If there is only one concatenation, I am not concerned with enclosing it in isDebugEnabled, but if there are more than one, if you have an object that calls toString() or if you have multiple log statements, it should be enclosed in isDebugEnabled.
  2.  Info - Informational messages, can be anywhere but these should be used very infrequently.  These should not be concatenated so there is no real reason to use isInfoEnabled.  An example of an info message would be to notify a user who is watching the log that a long running process has finished or something like that.
  3. Warn - Use these whenever the application is in danger of getting into a state that could cause an issue.  For instance, if a call to the database returns 2 values when it should have only returned one but it is still valid to just take the top one, it would be prudent to log a warning to say what is happening so, if it ends up causing a problem we can see it in the log.  Also, warnings are typically the default level used in production applications by default.  That means that, from warn on, you can usually count on the message getting logged even in production.  When choosing if I'm going to append information from the state of the application, I try to be very careful to take the impact of that decision into consideration.
  4. Error - This should be self explanatory.  I will stop short of saying this should be in every exception handling block, but it should be in most.  At the very least it provides a way for us to know when an exception occurs where it is normally swallowed.  I will say that we should NEVER, EVER swallow exceptions.  By swallowing, I mean: try { ... } catch (Exception e) {//no code to handle the exception}.  A log message is the very least we can do.  In addition, the method log.error(String message, Throwable t) is the only one to use here.  Do not append the output of e.getMessage() as the really useful information is in the stack trace and should be captured.
  5. Fatal - I don't think there is much reason to do this in web applications, but if we do find a place, this is for problems that will probably take the server down.  Losing connectivity to the database would be an example of a fatal exception where we would need to restart the machine.
There are two caveats to this list.  Some loggers include a trace level.  I feel this is unnecessary and, if it is actually done, should probably be done by injection with AOP.  The idea of cluttering up the code with "entering this method... ", exiting this method..." makes me shudder.  If I wanted to read through 25 lines of log messages in order to get to the real code.... well... I don't want to do that.


The second caveat is some applications have a monitoring tool like Nagios that looks for errors and sends out an alert.  If this is the case in your system, you probably either want to be discrete with your use of error, monitor fatal instead of error or implement your own log level for bugs that are serious enough to set off a pager at 3 am.  I think, in most cases, I personally like the 2nd option because most applications have no need for Fatal and, when you do get one it is cause for serious concern.

So that's my method.  Perhaps some of you out there have others.  Remember, sharing is a good thing. :)
Reblog this post [with Zemanta]

Thursday, March 18

Joel Spolsky expounds on the virtues of distributed version control

Not one day after I decided to unsubscribe from joelonsoftware... one of the first blogs I started reading regularly, he came up with a beauty right after announcing he was "retired" from blogging.  You can read his thoughts here

By the way, am I the only one who thinks Joel's new puppy looks a little like Joel?

I'm no fan of geek-worship.  There are a bunch of geeks out there who seriously worship other geeks and there are whole churches following the likes of Joel Spolsky and Matt Raible around.  The point is, I don't think that just because Joel Spolsky or Matt Raible say something that it becomes an indisputable law... and I don't think the fact that Joel Spolsky says distributed version control is here to stay means it is.

However, I have to say I agree with him.  Distributed version control has moved from the fringe to one that is more and more accepted by the corporate world.  The thing I don't agree with is, I don't think the world thinks in versions without thinking of change sets.  I don't think it is such a major paradigm shift of "thinking in versions" vs "thinking in changesets". 

Even if you "think in versions", you are only doing so because you are interested in the changes that come with that version.  Shifting your thinking to "Joe's version" or "Mike's version" is really not that different.  Also, ignoring change sets is not really something people on teams can do forever because eventually everyone's change set becomes a released product and all the change sets end up merged together anyway.  The sooner you can do that and debug the issues, the better.

What a change to a distributed system does is change the workflow.  Take an example where two developers, Joe and Mary, are working on web services.  Joe is working on the producer, Mary is working on the consumer.  Since the producer does not yet exist in source control, Mary has nothing to test against but her unit tests.  That works while she's developing functionality, but eventually she will need to test the integration.  Lets say Joe isn't done with the producer yet, but he has enough done that Mary could do some stub testing.  Joe checks his code into source control.  At that point, if a build was done for QA, there would be broken functionality in the build.  No one has really tested that this code works with a consumer, and admittedly, it doesn't actually do anything yet but provide Mary a way to test her code.

In a distributed world, Joe and Mary can easily work together by taking changes from each other and then, when the final product is complete and working, they can commit the changes to the build branch without releasing anything that is not working.

That, in my mind, is the benefit in the corporate world where large development teams have individuals concurrently working on small, inter-related pieces of functionality.

While I can't say I would rather switch to programming in C++ than go back to the world of centralized version control, the virtues of it are a good addition to any development team.  As we speak, my team is experimenting with distributed version control using Bazaar.  The details of that will follow here at some point when our experiment is complete.
Reblog this post [with Zemanta]