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