I have previously complained about JDK logging. Thanks to Niall’s comment in my original entry, however, I solved problem #2 in my original complaint, and making my original solution to problem #1 acceptable now.
So for those who wish to use JDK logging and want a nice wrapper class, here is a wrapper that works well for me:
/**
* Poritions of this code are fall under the following license:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hostedqa.utils;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
/**
* @author <a href="mailto:plightbo@gmail.com">Patrick Lightbody</a>
*
* Portions of the class have been borrowed from commons-logging,
* which was created by:
*
* @author <a href="mailto:sanders@apache.org">Scott Sanders</a>
* @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public class Log {
private Logger logger;
public Log(Class clazz) {
logger = Logger.getLogger(clazz.getName());
}
public void severe(String msg, Exception e) {
_log(Level.SEVERE, msg, e);
}
public void severe(String msg, String... args) {
_log(Level.SEVERE, msg, null, args);
}
public void severe(String msg, Exception e, String... args) {
_log(Level.SEVERE, msg, e, args);
}
public void warn(String msg, Exception e) {
_log(Level.WARNING, msg, e);
}
public void warn(String msg, String... args) {
_log(Level.WARNING, msg, null, args);
}
public void warn(String msg, Exception e, String... args) {
_log(Level.WARNING, msg, e, args);
}
public void info(String msg, Exception e) {
_log(Level.INFO, msg, e);
}
public void info(String msg, String... args) {
_log(Level.INFO, msg, null, args);
}
public void info(String msg, Exception e, String... args) {
_log(Level.INFO, msg, e, args);
}
public void fine(String msg, Exception e) {
_log(Level.FINE, msg, e);
}
public void fine(String msg, String... args) {
_log(Level.FINE, msg, null, args);
}
public void fine(String msg, Exception e, String... args) {
_log(Level.FINE, msg, e, args);
}
private void _log(Level level, String msg, Exception e, String... args) {
if (logger.isLoggable(level)) {
// Hack (?) to get the stack trace.
Throwable dummyException = new Throwable();
StackTraceElement locations[] = dummyException.getStackTrace();
// Caller will be the third element
String cname = "unknown";
String method = "unknown";
if (locations != null && locations.length > 2) {
StackTraceElement caller = locations[2];
cname = caller.getClassName();
method = caller.getMethodName();
}
LogRecord lr = new LogRecord(level, msg);
lr.setThrown(e);
lr.setParameters(args);
lr.setSourceClassName(cname);
lr.setSourceMethodName(method);
logger.log(lr);
}
}
public Logger getLogger() {
return logger;
}
}
on Aug 23rd, 2006 at 10:42 am
Sure, that works, but that seems very expensive, since an exception has to be created for every log message. IIRC, exceptions are expensive things to create.
on Aug 23rd, 2006 at 2:51 pm
Hi Patrick,
Isn’t it possible to use the following method for finding the right stack trace element:
e.getStackTraceElement(e.getStackTrace().length - 1)
This eliminates the necessity to create a new dummy exception object so it should have a less overhead.
Regards,
Behi
on Aug 23rd, 2006 at 5:46 pm
A few comments on the “expense of creating an exception”…
1) Many log statements never get past the “guard” condition so maybe its not such an issue
2) You already have the class name and therefore only need to create the Throwable to determine the method name - your implementation could make including the method name configurable to save the expense.
3) If you don’t supply the class/method the JDK uses the same mechanism (creating an exception) to do the same thing.
Another possible issue why using the class your implementation was constrcuted with is the comment in the following javadoc which indicates that frames may be omitted:
http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Throwable.html#getStackTrace()
Unfortuntatly Behi’s suggestion won’t work since 1) there isn’t always an exception and 2) it may not have been produced by the class logging it.
Couple of other issues to consider are making it Serializable and also the method signatures would be better being Throwables rather than Exceptions
Following your original post and the discussion on the struts dev list I also created an implementation here:
http://issues.apache.org/struts/browse/WW-1413
on Aug 23rd, 2006 at 8:54 pm
I think that this post only confirms your original complaint: if there is a need to wrap the API in your own adapter class, then the API isn’t usable - or, to be less dramatic, comfortable. I’ve never felt the need to wrap Log4J and I don’t think I will soon.