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