001/** 002 * Logback: the reliable, generic, fast and flexible logging framework. Copyright (C) 1999-2015, QOS.ch. All rights reserved. 003 * <p> 004 * 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 005 * Foundation 006 * <p> 007 * or (per the licensee's choosing) 008 * <p> 009 * under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. 010 */ 011package ch.qos.logback.classic.util; 012 013import ch.qos.logback.classic.ClassicConstants; 014import ch.qos.logback.classic.LoggerContext; 015import ch.qos.logback.classic.spi.Configurator; 016import ch.qos.logback.classic.spi.ConfiguratorRank; 017import ch.qos.logback.core.LogbackException; 018import ch.qos.logback.core.joran.spi.JoranException; 019import ch.qos.logback.core.spi.ContextAware; 020import ch.qos.logback.core.spi.ContextAwareImpl; 021import ch.qos.logback.core.util.CoreVersionUtil; 022import ch.qos.logback.core.util.Loader; 023import ch.qos.logback.core.util.StatusListenerConfigHelper; 024import ch.qos.logback.core.util.VersionUtil; 025 026import java.util.Comparator; 027import java.util.List; 028 029// contributors 030// Ted Graham, Matt Fowles, see also http://jira.qos.ch/browse/LBCORE-32 031 032/** 033 * This class contains logback's logic for automatic configuration 034 * 035 * @author Ceki Gulcu 036 */ 037public class ContextInitializer { 038 039 /** 040 * @deprecated Please use ClassicConstants.AUTOCONFIG_FILE instead 041 */ 042 final public static String AUTOCONFIG_FILE = ClassicConstants.AUTOCONFIG_FILE; 043 /** 044 * @deprecated Please use ClassicConstants.TEST_AUTOCONFIG_FILE instead 045 */ 046 final public static String TEST_AUTOCONFIG_FILE = ClassicConstants.TEST_AUTOCONFIG_FILE; 047 /** 048 * @deprecated Please use ClassicConstants.CONFIG_FILE_PROPERTY instead 049 */ 050 final public static String CONFIG_FILE_PROPERTY = ClassicConstants.CONFIG_FILE_PROPERTY; 051 052 String[] INTERNAL_CONFIGURATOR_CLASSNAME_LIST = {"ch.qos.logback.classic.util.DefaultJoranConfigurator", "ch.qos.logback.classic.BasicConfigurator"}; 053 054 final LoggerContext loggerContext; 055 056 final ContextAware contextAware; 057 058 public ContextInitializer(LoggerContext loggerContext) { 059 this.loggerContext = loggerContext; 060 this.contextAware = new ContextAwareImpl(loggerContext, this); 061 } 062 063 public void autoConfig() throws JoranException { 064 autoConfig(Configurator.class.getClassLoader()); 065 } 066 067 068 public void autoConfig(ClassLoader classLoader) throws JoranException { 069 070 // see https://github.com/qos-ch/logback/issues/715 071 classLoader = Loader.systemClassloaderIfNull(classLoader); 072 073 checkVersions(); 074 075 StatusListenerConfigHelper.installIfAsked(loggerContext); 076 077 078 // invoke custom configurators 079 List<Configurator> configuratorList = ClassicEnvUtil.loadFromServiceLoader(Configurator.class, classLoader); 080 configuratorList.sort(rankComparator); 081 if (configuratorList.isEmpty()) { 082 contextAware.addInfo("No custom configurators were discovered as a service."); 083 } else { 084 printConfiguratorOrder(configuratorList); 085 } 086 087 for (Configurator c : configuratorList) { 088 if (invokeConfigure(c) == Configurator.ExecutionStatus.DO_NOT_INVOKE_NEXT_IF_ANY) 089 return; 090 } 091 092 // invoke internal configurators 093 for (String configuratorClassName : INTERNAL_CONFIGURATOR_CLASSNAME_LIST) { 094 contextAware.addInfo("Trying to configure with "+configuratorClassName); 095 Configurator c = instantiateConfiguratorByClassName(configuratorClassName, classLoader); 096 if(c == null) 097 continue; 098 if (invokeConfigure(c) == Configurator.ExecutionStatus.DO_NOT_INVOKE_NEXT_IF_ANY) 099 return; 100 } 101 } 102 103 private void checkVersions() { 104 try { 105 String coreVersion = CoreVersionUtil.getCoreVersionBySelfDeclaredProperties(); 106 String classicVersion = ClassicVersionUtil.getVersionBySelfDeclaredProperties(); 107 VersionUtil.checkForVersionEquality(loggerContext, coreVersion, classicVersion, "logback-core", "logback-classic"); 108 } catch(NoClassDefFoundError e) { 109 contextAware.addWarn("Missing ch.logback.core.util.VersionUtil class on classpath. The version of logback-core is probably older than 1.5.26."); 110 } catch (NoSuchMethodError e) { 111 contextAware.addWarn(e.toString()); 112 contextAware.addWarn("The version of logback-core is probably older than 1.5.26."); 113 } 114 } 115 116 private Configurator instantiateConfiguratorByClassName(String configuratorClassName, ClassLoader classLoader) { 117 try { 118 Class<?> classObj = classLoader.loadClass(configuratorClassName); 119 return (Configurator) classObj.getConstructor().newInstance(); 120 } catch (ReflectiveOperationException e) { 121 contextAware.addInfo("Instantiation failure: " + e.toString()); 122 return null; 123 } 124 } 125 126 /** 127 * 128 * @param configurator 129 * @return ExecutionStatus 130 */ 131 private Configurator.ExecutionStatus invokeConfigure(Configurator configurator) { 132 try { 133 long start = System.currentTimeMillis(); 134 contextAware.addInfo("Constructed configurator of type " + configurator.getClass()); 135 configurator.setContext(loggerContext); 136 Configurator.ExecutionStatus status = configurator.configure(loggerContext); 137 printDuration(start, configurator, status); 138 return status; 139 140 } catch (Exception e) { 141 throw new LogbackException(String.format("Failed to initialize or to run Configurator: %s", 142 configurator != null ? configurator.getClass().getCanonicalName() : "null"), e); 143 } 144 } 145 146 private void printConfiguratorOrder(List<Configurator> configuratorList) { 147 contextAware.addInfo("Here is a list of configurators discovered as a service, by rank: "); 148 for(Configurator c: configuratorList) { 149 contextAware.addInfo(" "+c.getClass().getName()); 150 } 151 contextAware.addInfo("They will be invoked in order until ExecutionStatus.DO_NOT_INVOKE_NEXT_IF_ANY is returned."); 152 } 153 154 private void printDuration(long start, Configurator configurator, Configurator.ExecutionStatus executionStatus) { 155 long end = System.currentTimeMillis(); 156 long diff = end - start; 157 contextAware.addInfo( configurator.getClass().getName()+".configure() call lasted "+diff + " milliseconds. ExecutionStatus="+executionStatus); 158 } 159 160 private Configurator.ExecutionStatus attemptConfigurationUsingJoranUsingReflexion(ClassLoader classLoader) { 161 162 try { 163 Class<?> djcClass = classLoader.loadClass("ch.qos.logback.classic.util.DefaultJoranConfigurator"); 164 Configurator c = (Configurator) djcClass.newInstance(); 165 c.setContext(loggerContext); 166 return c.configure(loggerContext); 167 } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { 168 contextAware.addError("unexpected exception while instantiating DefaultJoranConfigurator", e); 169 return Configurator.ExecutionStatus.INVOKE_NEXT_IF_ANY; 170 } 171 172 } 173 174 Comparator<Configurator> rankComparator = new Comparator<Configurator>() { 175 @Override 176 public int compare(Configurator c1, Configurator c2) { 177 178 ConfiguratorRank r1 = c1.getClass().getAnnotation(ConfiguratorRank.class); 179 ConfiguratorRank r2 = c2.getClass().getAnnotation(ConfiguratorRank.class); 180 181 int value1 = r1 == null ? ConfiguratorRank.DEFAULT : r1.value(); 182 int value2 = r2 == null ? ConfiguratorRank.DEFAULT : r2.value(); 183 184 int result = compareRankValue(value1, value2); 185 // reverse the result for high to low sort 186 return (-result); 187 } 188 }; 189 190 private int compareRankValue(int value1, int value2) { 191 if(value1 > value2) 192 return 1; 193 else if (value1 == value2) 194 return 0; 195 else return -1; 196 197 } 198}