Showing posts with label logging. Show all posts
Showing posts with label logging. Show all posts

Wednesday, November 12, 2008

Grails Logging

Configuring logging in Grails is not as simple one would think. Grails uses Log4J as its logging framework. Log4J configuration is stored in the log4j.properties file. In Grails, this file is generated from Config.groovy source file.

The official Grails Logging documentation says that if you want to have a different logging levels for let's say a specific controller, all controllers and the rest of your application, you should define the logging levels as:

grails.'app.controller.YourOtherController'="off,stdout"
grails.'app.controller'="info,stdout"
grails.app="error,stdout"

Yes, those ticks are required, otherwise you get an error message (No such property: context for class: java.lang.String). Don't ask me why. What is also important is the order. Children need to go first.

So that is what the official documentation and few blogs say.

Grails allows you to configure your production, development and testing environments differently if required. I configured Log4J the way that common properties are grouped and placed outside the environment dependent ones. But no matter how I tweaked it, I could not make it to work. For some reason the parent's or child's definition overrides the other, or causes an error.

But there is a solution to this problem after all. Instead of dot notation, use curly braces. Like in the following example:

environments {
development {
...
log4j {
appender.stdout = ...
rootLogger="error,logfile,stdout"
logger {
grails {
app {
controller="debug"
}
}
}
}
}
production {
...
}
}

// log4j configuration
log4j {
appender.logfile=...
appender.stacktraceLog=...
rootLogger="debug,logfile"
logger {
grails="error"
StackTrace="error,stacktraceLog"
...
}
additivity.StackTrace=false
}

This works. Tested with Grails 1.0.3.

Related articles:

Friday, November 07, 2008

Fatal Error in the logs by Grails

I recently started working on a project using Grails and the following message in the logs appeared consistently and annoyed me quite a lot.

[Fatal Error] :-1:-1: Premature end of file.

So I started digging through the code and searching the web for an answer. And I found it. It is a bug that has been reported to Grails and you can find it at GRAILS-3088. It apparently affects Grails 1.0.3 (which I am using) and it should be fixed in next release, 1.0.4.

The bug is triggered with each request from Firefox 3 and Opera 9.5 and even Firefox 2 if you render the response as "text/xml" using

withFormat { xml { render(contentType:"text/xml"){ ... } } }

The current workaround suggested by Graeme Rocher is to edit Config.groovy file and remove (or comment out) "text/xml" from the Grails MIME types mapping

grails.mime.types = [ html: ['text/html','application/xhtml+xml'],
// xml: ['text/xml', 'application/xml'],
text: 'text-plain',

This works for me. No more annoying messages in the logs. I am not quite sure how or if it affects XML responses. But I do not need those for now, so I will worry about that later, if I need to

Thursday, February 22, 2007

Log4J Logger vs. Category

Logging is the practice of recording sequential data. This is also a low-tech method of debugging and in some cases also the only way as the proper debugging tools may not be always available or applicable. Logging in Java can range from simple System.out.println() statements to usage of sophisticated logging frameworks.

At the time of writing there are several logging frameworks for logging in Java available. There is a popular and probably the most widely used Log4J framework. Younger brother of Log4J is the Java's Logging API that became part of Java SE in version 1.4. See How does the Java logging API stack up against log4j for comparison. The are many other logging frameworks: SimpleLog, jLo, Protomatter Syslog, etc.

There are also several frameworks that enable abstraction from logging frameworks, also known as logging bridges (Apache Commons Logging, log-bridge). These allow switching between logging frameworks. These and many others can be found at Open Source Logging Tools in Java at java-source.net.

Log4J was one of the early logging frameworks that gained popularity and is present in many source code bases. In some cases you could encounter usage of Category class rather than Logger. If you work or worked on projects that are built on top of relatively young frameworks, you may not even know that Category class exists as its natural habitat is in old Java code. I hadn't known that Category class existed until I saw it one day. I saw it in a place where I would usually use Logger class. Since that day I kept reminding myself to look at it and see what's different from Logger class and why would one use it.

So what is the difference between Category and Logger classes? The Java documentation in Category class states

This class has been deprecated and replaced by the Logger subclass. It will be kept around to preserve backward compatibility until mid 2003.

Logger is a subclass of Category, i.e. it extends Category. In other words, a logger is a category. Thus, all operations that can be performed on a category can be performed on a logger. Internally, whenever log4j is asked to produce a Category object, it will instead produce a Logger object. Log4j 1.2 will never produce Category objects but only Logger instances. In order to preserve backward compatibility, methods that previously accepted category objects still continue to accept category objects.

Then the following example shows how Category was used and how Logger should be used.

// Deprecated form:
Category cat = Category.getInstance("foo.bar");

// Preferred form for retrieving loggers:
Logger logger = Logger.getLogger("foo.bar");

And that's it. That's all you have to do to replace Category with Logger (apart from renaming the variable).

The documentation also says

There is absolutely no need for new client code to use or refer to the Category class. Whenever possible, please avoid referring to it or using it.

Why is this important? The plan is that from Log4J version 1.3 Category class will be removed! What can we do to prepare our code for Log4J 1.3? Well Preparing for Log4J version 1.3 has it all spelled out. It's worth to read if you want to understand all implications this upgrade may have. I just shamelessly paste the steps here:

  1. Never refer to the Category class directly, refer to Logger instead.
  2. Do not invoke the deprecated Category.getRoot method. Invoke Logger.getRootLogger method instead.
  3. Do not invoke the deprecated Category.getInstance(String) method. Invoke Logger.getLogger(String) method instead.
  4. Do not invoke the deprecated Category.getInstance(Class) method. Invoke Logger.getLogger(Class) method instead.
  5. Never refer to the Priority class, refer to Level class instead.
  6. Do not invoke the deprecated Category.setPriority(Priority) method. Invoke Logger.setLevel(Level) method instead.
  7. Do not invoke the deprecated Priority.toPriority(int) method. Invoke Level.toLevel(int) method instead. The same holds true for the other variants of the Priority.toPriority method.
  8. Never refer to the deprecated Priority.FATAL, Priority.ERROR, Priority.WARN, Priority.INFO, Priority.DEBUG fields. Refer to the Level.FATAL, Level.ERROR, Level.WARN, Level.INFO, Level.DEBUG fields instead.

  9. If you confiugure appenders programmatically, do not forget to invoke the activateOptions method of an appender after you have instantiated it and set its options.

and as the above mentioned document says

For 99.99% of users, this translates to the following string find-and-replace operations:
  1. Replace the string "Category.getInstance" with the string "Logger.getLogger".
  2. Replace the string "Category.getRoot" with the string "Logger.getRootLogger".
  3. Replace the string "Category" with the string "Logger".
  4. Replace the string "Priority" with the string "Level".

Happy logging!


Creative Commons License This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 2.5 License.