View Javadoc
1   /*
2    * #%L
3    * Slf4jLogFactory.java - mongodb-async-driver - Allanbank Consulting, Inc.
4    * %%
5    * Copyright (C) 2011 - 2014 Allanbank Consulting, Inc.
6    * %%
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   * 
11   *      http://www.apache.org/licenses/LICENSE-2.0
12   * 
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   * #L%
19   */
20  package com.allanbank.mongodb.util.log;
21  
22  import java.lang.reflect.InvocationTargetException;
23  import java.lang.reflect.Method;
24  import java.util.logging.Level;
25  import java.util.logging.Logger;
26  
27  /**
28   * Slf4jLogFactory provides factory to create {@link Slf4jLog} instances.
29   * 
30   * @api.no This class is <b>NOT</b> part of the drivers API. This class may be
31   *         mutated in incompatible ways between any two releases of the driver.
32   * @copyright 2014, Allanbank Consulting, Inc., All Rights Reserved
33   */
34  public class Slf4jLogFactory extends LogFactory {
35      /** The <code>LocationAwareLogger</code> class. */
36      private final Class<?> myLocationAwareLoggerClass;
37  
38      /**
39       * The <code>getLogger(Class)</code> method from the
40       * <code>LoggerFactory</code> interface.
41       */
42      private final Method myLogFactoryMethod;
43  
44      /**
45       * The <code>log(Marker, String, int, String, Object[])</code> method from
46       * the <code>LocationAwareLogger</code> interface.
47       */
48      private final Method myLogMethod;
49  
50      /**
51       * Creates a new Slf4jLogFactory.
52       * 
53       * @throws RuntimeException
54       *             On a failure to find the SLF4J Logger.
55       */
56      public Slf4jLogFactory() throws RuntimeException {
57          Class<?> logFactoryClass;
58          try {
59              logFactoryClass = Class.forName("org.slf4j.LoggerFactory");
60          }
61          catch (final ClassNotFoundException e) {
62              // Don't log. SLF4J is not on the classpath to use.
63              throw new RuntimeException(e);
64          }
65  
66          try {
67              myLogFactoryMethod = logFactoryClass.getMethod("getLogger",
68                      Class.class);
69  
70              myLocationAwareLoggerClass = Class
71                      .forName("org.slf4j.spi.LocationAwareLogger");
72              final Class<?> markerClass = Class.forName("org.slf4j.Marker");
73              myLogMethod = myLocationAwareLoggerClass.getMethod("log",
74                      markerClass, String.class, int.class, String.class,
75                      Object[].class, Throwable.class);
76          }
77          catch (final ClassNotFoundException e) {
78              Logger.getLogger(Slf4jLogFactory.class.getName()).log(
79                      Level.WARNING,
80                      "Failed bootstrap the SLF4J logger: " + e.getMessage(), e);
81              throw new RuntimeException(e);
82          }
83          catch (final NoSuchMethodException e) {
84              Logger.getLogger(Slf4jLogFactory.class.getName()).log(
85                      Level.WARNING,
86                      "Failed bootstrap the SLF4J logger: " + e.getMessage(), e);
87              throw new RuntimeException(e);
88          }
89      }
90  
91      /**
92       * {@inheritDoc}
93       * <p>
94       * Overridden to return a {@link Slf4jLog} instance if SLF4J LoggerFactory
95       * returns a LocationAwareLogger instance. Otherwise a {@link JulLog} is
96       * returned.
97       * </p>
98       */
99      @Override
100     protected Log doGetLog(final Class<?> clazz) {
101         Log log = null;
102         try {
103             final Object logger = myLogFactoryMethod.invoke(null, clazz);
104             if (myLocationAwareLoggerClass.isInstance(logger)) {
105                 log = new Slf4jLog(myLogMethod, logger);
106             }
107         }
108         catch (final IllegalAccessException e) {
109             // Fall through.
110         }
111         catch (final InvocationTargetException e) {
112             // Fall through.
113         }
114         catch (final RuntimeException e) {
115             // Fall through.
116         }
117 
118         // Fall back to JUL logging.
119         if (log == null) {
120             Logger.getLogger(Slf4jLogFactory.class.getName()).warning(
121                     "Falling back to the JUL logger.");
122             log = new JulLog(clazz);
123         }
124 
125         return log;
126     }
127 }