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.CoreConstants; 018import ch.qos.logback.core.LogbackException; 019import ch.qos.logback.core.joran.spi.JoranException; 020import ch.qos.logback.core.spi.ContextAware; 021import ch.qos.logback.core.spi.ContextAwareImpl; 022import ch.qos.logback.core.status.InfoStatus; 023import ch.qos.logback.core.util.EnvUtil; 024import ch.qos.logback.core.util.Loader; 025import ch.qos.logback.core.util.StatusListenerConfigHelper; 026 027import java.util.Comparator; 028import java.util.List; 029 030// contributors 031// Ted Graham, Matt Fowles, see also http://jira.qos.ch/browse/LBCORE-32 032 033/** 034 * This class contains logback's logic for automatic configuration 035 * 036 * @author Ceki Gulcu 037 */ 038public class ContextInitializer { 039 040 /** 041 * @deprecated Please use ClassicConstants.AUTOCONFIG_FILE instead 042 */ 043 final public static String AUTOCONFIG_FILE = ClassicConstants.AUTOCONFIG_FILE; 044 /** 045 * @deprecated Please use ClassicConstants.TEST_AUTOCONFIG_FILE instead 046 */ 047 final public static String TEST_AUTOCONFIG_FILE = ClassicConstants.TEST_AUTOCONFIG_FILE; 048 /** 049 * @deprecated Please use ClassicConstants.CONFIG_FILE_PROPERTY instead 050 */ 051 final public static String CONFIG_FILE_PROPERTY = ClassicConstants.CONFIG_FILE_PROPERTY; 052 053 String[] INTERNAL_CONFIGURATOR_CLASSNAME_LIST = {"ch.qos.logback.classic.joran.SerializedModelConfigurator", 054 "ch.qos.logback.classic.util.DefaultJoranConfigurator", "ch.qos.logback.classic.BasicConfigurator"}; 055 056 final LoggerContext loggerContext; 057 058 final ContextAware contextAware; 059 060 public ContextInitializer(LoggerContext loggerContext) { 061 this.loggerContext = loggerContext; 062 this.contextAware = new ContextAwareImpl(loggerContext, this); 063 } 064 065 public void autoConfig() throws JoranException { 066 autoConfig(Configurator.class.getClassLoader()); 067 } 068 069 070 public void autoConfig(ClassLoader classLoader) throws JoranException { 071 072 // see https://github.com/qos-ch/logback/issues/715 073 classLoader = Loader.systemClassloaderIfNull(classLoader); 074 075 String versionStr = EnvUtil.logbackVersion(); 076 if (versionStr == null) { 077 versionStr = CoreConstants.NA; 078 } 079 loggerContext.getStatusManager().add(new InfoStatus(CoreConstants.LOGBACK_CLASSIC_VERSION_MESSAGE + versionStr, loggerContext)); 080 StatusListenerConfigHelper.installIfAsked(loggerContext); 081 082 083 // invoke custom configurators 084 List<Configurator> configuratorList = ClassicEnvUtil.loadFromServiceLoader(Configurator.class, classLoader); 085 configuratorList.sort(rankComparator); 086 if (configuratorList.isEmpty()) { 087 contextAware.addInfo("No custom configurators were discovered as a service."); 088 } else { 089 printConfiguratorOrder(configuratorList); 090 } 091 092 for (Configurator c : configuratorList) { 093 if (invokeConfigure(c) == Configurator.ExecutionStatus.DO_NOT_INVOKE_NEXT_IF_ANY) 094 return; 095 } 096 097 // invoke internal configurators 098 for (String configuratorClassName : INTERNAL_CONFIGURATOR_CLASSNAME_LIST) { 099 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}