View Javadoc
1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework. Copyright (C) 1999-2015, QOS.ch. All rights reserved.
3    * <p>
4    * This program and the accompanying materials are dual-licensed under either the terms of the Eclipse Public License v1.0 as published by the Eclipse
5    * Foundation
6    * <p>
7    * or (per the licensee's choosing)
8    * <p>
9    * under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation.
10   */
11  package ch.qos.logback.classic.util;
12  
13  import ch.qos.logback.classic.ClassicConstants;
14  import ch.qos.logback.classic.LoggerContext;
15  import ch.qos.logback.classic.spi.Configurator;
16  import ch.qos.logback.classic.spi.ConfiguratorRank;
17  import ch.qos.logback.core.CoreConstants;
18  import ch.qos.logback.core.LogbackException;
19  import ch.qos.logback.core.joran.spi.JoranException;
20  import ch.qos.logback.core.spi.ContextAware;
21  import ch.qos.logback.core.spi.ContextAwareImpl;
22  import ch.qos.logback.core.status.InfoStatus;
23  import ch.qos.logback.core.util.EnvUtil;
24  import ch.qos.logback.core.util.Loader;
25  import ch.qos.logback.core.util.StatusListenerConfigHelper;
26  
27  import java.util.Comparator;
28  import java.util.List;
29  
30  // contributors
31  // Ted Graham, Matt Fowles, see also http://jira.qos.ch/browse/LBCORE-32
32  
33  /**
34   * This class contains logback's logic for automatic configuration
35   *
36   * @author Ceki Gulcu
37   */
38  public class ContextInitializer {
39  
40      /**
41       *  @deprecated Please use ClassicConstants.AUTOCONFIG_FILE instead
42       */
43      final public static String AUTOCONFIG_FILE = ClassicConstants.AUTOCONFIG_FILE;
44      /**
45       * @deprecated Please use ClassicConstants.TEST_AUTOCONFIG_FILE instead
46       */
47      final public static String TEST_AUTOCONFIG_FILE = ClassicConstants.TEST_AUTOCONFIG_FILE;
48      /**
49       * @deprecated Please use ClassicConstants.CONFIG_FILE_PROPERTY instead
50       */
51      final public static String CONFIG_FILE_PROPERTY = ClassicConstants.CONFIG_FILE_PROPERTY;
52  
53      String[] INTERNAL_CONFIGURATOR_CLASSNAME_LIST = {"ch.qos.logback.classic.joran.SerializedModelConfigurator",
54              "ch.qos.logback.classic.util.DefaultJoranConfigurator", "ch.qos.logback.classic.BasicConfigurator"};
55  
56      final LoggerContext loggerContext;
57  
58      final ContextAware contextAware;
59  
60      public ContextInitializer(LoggerContext loggerContext) {
61          this.loggerContext = loggerContext;
62          this.contextAware = new ContextAwareImpl(loggerContext, this);
63      }
64  
65      public void autoConfig() throws JoranException {
66          autoConfig(Configurator.class.getClassLoader());
67      }
68  
69  
70      public void autoConfig(ClassLoader classLoader) throws JoranException {
71  
72          // see https://github.com/qos-ch/logback/issues/715
73          classLoader = Loader.systemClassloaderIfNull(classLoader);
74  
75          String versionStr = EnvUtil.logbackVersion();
76          if (versionStr == null) {
77              versionStr = CoreConstants.NA;
78          }
79          loggerContext.getStatusManager().add(new InfoStatus(CoreConstants.LOGBACK_CLASSIC_VERSION_MESSAGE + versionStr, loggerContext));
80          StatusListenerConfigHelper.installIfAsked(loggerContext);
81  
82  
83          // invoke custom configurators
84          List<Configurator> configuratorList = ClassicEnvUtil.loadFromServiceLoader(Configurator.class, classLoader);
85          configuratorList.sort(rankComparator);
86          if (configuratorList.isEmpty()) {
87              contextAware.addInfo("No custom configurators were discovered as a service.");
88          } else {
89              printConfiguratorOrder(configuratorList);
90          }
91  
92          for (Configurator c : configuratorList) {
93              if (invokeConfigure(c) == Configurator.ExecutionStatus.DO_NOT_INVOKE_NEXT_IF_ANY)
94                  return;
95          }
96  
97          // invoke internal configurators
98          for (String configuratorClassName : INTERNAL_CONFIGURATOR_CLASSNAME_LIST) {
99              contextAware.addInfo("Trying to configure with "+configuratorClassName);
100             Configurator c = instantiateConfiguratorByClassName(configuratorClassName, classLoader);
101             if(c == null)
102                 continue;
103             if (invokeConfigure(c) == Configurator.ExecutionStatus.DO_NOT_INVOKE_NEXT_IF_ANY)
104                 return;
105         }
106     }
107 
108     private Configurator instantiateConfiguratorByClassName(String configuratorClassName, ClassLoader classLoader) {
109         try {
110             Class<?> classObj = classLoader.loadClass(configuratorClassName);
111             return (Configurator) classObj.getConstructor().newInstance();
112         } catch (ReflectiveOperationException  e) {
113             contextAware.addInfo("Instantiation failure: " + e.toString());
114             return null;
115         }
116     }
117 
118     /**
119      *
120      * @param configurator
121      * @return ExecutionStatus
122      */
123     private Configurator.ExecutionStatus invokeConfigure(Configurator configurator) {
124         try {
125             long start = System.currentTimeMillis();
126             contextAware.addInfo("Constructed configurator of type " + configurator.getClass());
127             configurator.setContext(loggerContext);
128             Configurator.ExecutionStatus status = configurator.configure(loggerContext);
129             printDuration(start, configurator, status);
130             return status;
131 
132         } catch (Exception e) {
133             throw new LogbackException(String.format("Failed to initialize or to run Configurator: %s",
134                     configurator != null ? configurator.getClass().getCanonicalName() : "null"), e);
135         }
136     }
137 
138     private void printConfiguratorOrder(List<Configurator> configuratorList) {
139         contextAware.addInfo("Here is a list of configurators discovered as a service, by rank: ");
140         for(Configurator c: configuratorList) {
141             contextAware.addInfo("  "+c.getClass().getName());
142         }
143         contextAware.addInfo("They will be invoked in order until ExecutionStatus.DO_NOT_INVOKE_NEXT_IF_ANY is returned.");
144     }
145 
146     private void printDuration(long start, Configurator configurator, Configurator.ExecutionStatus executionStatus) {
147         long end = System.currentTimeMillis();
148         long diff = end - start;
149         contextAware.addInfo( configurator.getClass().getName()+".configure() call lasted "+diff + " milliseconds. ExecutionStatus="+executionStatus);
150     }
151 
152     private Configurator.ExecutionStatus attemptConfigurationUsingJoranUsingReflexion(ClassLoader classLoader) {
153 
154         try {
155             Class<?> djcClass = classLoader.loadClass("ch.qos.logback.classic.util.DefaultJoranConfigurator");
156             Configurator c = (Configurator) djcClass.newInstance();
157             c.setContext(loggerContext);
158             return c.configure(loggerContext);
159         } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
160             contextAware.addError("unexpected exception while instantiating DefaultJoranConfigurator", e);
161             return Configurator.ExecutionStatus.INVOKE_NEXT_IF_ANY;
162         }
163 
164     }
165 
166     Comparator<Configurator> rankComparator = new Comparator<Configurator>() {
167         @Override
168         public int compare(Configurator c1, Configurator c2) {
169 
170             ConfiguratorRank r1 = c1.getClass().getAnnotation(ConfiguratorRank.class);
171             ConfiguratorRank r2 = c2.getClass().getAnnotation(ConfiguratorRank.class);
172 
173             int value1 = r1 == null ? ConfiguratorRank.DEFAULT : r1.value();
174             int value2 = r2 == null ? ConfiguratorRank.DEFAULT : r2.value();
175 
176             int result = compareRankValue(value1, value2);
177             // reverse the result for high to low sort
178             return (-result);
179         }
180     };
181 
182     private int compareRankValue(int value1, int value2) {
183         if(value1 > value2)
184             return 1;
185         else if (value1 == value2)
186             return 0;
187         else return -1;
188 
189     }
190 }