[hibernate-dev] Obtaining loggers

Gunnar Morling gunnar at hibernate.org
Wed May 22 03:51:03 EDT 2013


2013/5/21 Sanne Grinovero <sanne at hibernate.org>

> Have you seen how Search does it?
>
>     private static final Log log = LoggerFactory.make();
>
> The implementation of LoggerFactory#make is:
>
>    public static Log make() {
>         Throwable t = new Throwable();
>         StackTraceElement directCaller = t.getStackTrace()[1];
>         return Logger.getMessageLogger( Log.class,
> directCaller.getClassName() );
>     }
>
> We introduced this a while back after having spotted some copy/paste
> mistakes which had lead to have the wrong logger; however there is a
> catch:
> each class initialization triggers a stacktrace initialization. Sure
> it's an initialization cost only, but still I wonder how large the
> cost is, adding up all classes: maybe we should just replace it with a
> checkstyle rule to verify its correctness.
>

An alternative implementation of LoggerFactory could be this (based on [1]):

    public final class LoggerFactory {

        private static CallerProvider callerProvider = new CallerProvider();

        public static Log make() {
            return Logger.getMessageLogger( Log.class,
callerProvider.getCallerClass().getCanonicalName()
);
        }

        private static class CallerProvider extends SecurityManager {
            public Class<?> getCallerClass() {
                return getClassContext()[2];
        }
    }

SecurityManager#getClassContext() is a native method, so one doesn't know
how it is implemented, but I guess it's faster than initializing a stack
trace, while still allowing for the concise LoggerFactory.make(); usage.

Btw. another copy-and-paste safe pattern enabled by Java 7 is this
(suggested in "The Well-Grounded Java Developer"):

    Logger logger = Logger.getMessageLogger(
        Log.class, MethodHandles.lookup().lookupClass().getCanonicalName()
);

This can't be pushed into a factory class, though, making more verbose than
the factory approach.

--Gunnar

[1]
http://beust.com/weblog/2011/07/15/accessing-the-class-object-in-a-static-context/


>
> Also, each module needs to have its own copy of the LoggerFactory to
> hardwire the correct Log.class interface, so you could still import
> the LoggerFactory from an alien module by mistake, but that's likely
> spotted by the typesafety of it as you wouldn't have the expected
> logger methods.
>
> Sanne
>
>
> On 21 May 2013 22:24, Steve Ebersole <steve at hibernate.org> wrote:
> > Forgot...  So really this just allows more conciseness in obtaining the
> > logger.  So from:
> >
> > private static final CoreMessageLogger LOG = Logger.getMessageLogger(
> > CoreMessageLogger.class, CollectionLoadContext.class.getName() );
> >
> > to:
> >
> > private static final CoreMessageLogger LOG = CoreLogging.messageLogger(
> > CollectionLoadContext.class );
> >
> >
> > On 05/21/2013 04:21 PM, Steve Ebersole wrote:
> >> I was getting tired of statements in the source code to get logger
> >> instances that spread across sometimes 4 lines because of JBoss
> >> Logging's verbose means of acquiring a message logger.  So I created a
> >> more concise form for this for hibernate-core, hibernate-entitymanager
> >> and hibernate-envers.  I mainly limited it to these projects because
> >> they have lots of these calls, whereas the others do not.  Feel free
> >> to copy the approach to the other projects if someone wants.
> >>
> >> Essentially each of those projects define a class with 4 static
> >> methods.  Taking the hibernate-core one as an example:
> >>
> >>
> >> import org.jboss.logging.Logger;
> >>
> >> /**
> >>  * Quite sad, really, when you need helpers for generating loggers...
> >>  *
> >>  * @author Steve Ebersole
> >>  */
> >> public class CoreLogging {
> >>     /**
> >>      * Disallow instantiation
> >>      */
> >>     private CoreLogging() {
> >>     }
> >>
> >>     public static CoreMessageLogger messageLogger(Class
> >> classNeedingLogging) {
> >>         return messageLogger( classNeedingLogging.getName() );
> >>     }
> >>
> >>     public static CoreMessageLogger messageLogger(String loggerName) {
> >>         return Logger.getMessageLogger( CoreMessageLogger.class,
> >> loggerName );
> >>     }
> >>
> >>     public static Logger logger(Class classNeedingLogging) {
> >>         return Logger.getLogger( classNeedingLogging );
> >>     }
> >>
> >>     public static Logger logger(String loggerName) {
> >>         return Logger.getLogger( loggerName );
> >>     }
> >> }
> >>
> >> I just plan on replacing these calls as opportunities arise, rather
> >> than all in one fell swoop.
> >
> > _______________________________________________
> > hibernate-dev mailing list
> > hibernate-dev at lists.jboss.org
> > https://lists.jboss.org/mailman/listinfo/hibernate-dev
> _______________________________________________
> hibernate-dev mailing list
> hibernate-dev at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/hibernate-dev
>


More information about the hibernate-dev mailing list