001/* 002 * Copyright 2012-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.boot.logging; 018 019import java.util.Comparator; 020import java.util.EnumMap; 021import java.util.HashMap; 022import java.util.LinkedHashSet; 023import java.util.Map; 024import java.util.Set; 025 026import org.springframework.core.env.Environment; 027import org.springframework.core.io.ClassPathResource; 028import org.springframework.util.ClassUtils; 029import org.springframework.util.StringUtils; 030import org.springframework.util.SystemPropertyUtils; 031 032/** 033 * Abstract base class for {@link LoggingSystem} implementations. 034 * 035 * @author Phillip Webb 036 * @author Dave Syer 037 */ 038public abstract class AbstractLoggingSystem extends LoggingSystem { 039 040 protected static final Comparator<LoggerConfiguration> CONFIGURATION_COMPARATOR = new LoggerConfigurationComparator( 041 ROOT_LOGGER_NAME); 042 043 private final ClassLoader classLoader; 044 045 public AbstractLoggingSystem(ClassLoader classLoader) { 046 this.classLoader = classLoader; 047 } 048 049 @Override 050 public void beforeInitialize() { 051 } 052 053 @Override 054 public void initialize(LoggingInitializationContext initializationContext, 055 String configLocation, LogFile logFile) { 056 if (StringUtils.hasLength(configLocation)) { 057 initializeWithSpecificConfig(initializationContext, configLocation, logFile); 058 return; 059 } 060 initializeWithConventions(initializationContext, logFile); 061 } 062 063 private void initializeWithSpecificConfig( 064 LoggingInitializationContext initializationContext, String configLocation, 065 LogFile logFile) { 066 configLocation = SystemPropertyUtils.resolvePlaceholders(configLocation); 067 loadConfiguration(initializationContext, configLocation, logFile); 068 } 069 070 private void initializeWithConventions( 071 LoggingInitializationContext initializationContext, LogFile logFile) { 072 String config = getSelfInitializationConfig(); 073 if (config != null && logFile == null) { 074 // self initialization has occurred, reinitialize in case of property changes 075 reinitialize(initializationContext); 076 return; 077 } 078 if (config == null) { 079 config = getSpringInitializationConfig(); 080 } 081 if (config != null) { 082 loadConfiguration(initializationContext, config, logFile); 083 return; 084 } 085 loadDefaults(initializationContext, logFile); 086 } 087 088 /** 089 * Return any self initialization config that has been applied. By default this method 090 * checks {@link #getStandardConfigLocations()} and assumes that any file that exists 091 * will have been applied. 092 * @return the self initialization config or {@code null} 093 */ 094 protected String getSelfInitializationConfig() { 095 return findConfig(getStandardConfigLocations()); 096 } 097 098 /** 099 * Return any spring specific initialization config that should be applied. By default 100 * this method checks {@link #getSpringConfigLocations()}. 101 * @return the spring initialization config or {@code null} 102 */ 103 protected String getSpringInitializationConfig() { 104 return findConfig(getSpringConfigLocations()); 105 } 106 107 private String findConfig(String[] locations) { 108 for (String location : locations) { 109 ClassPathResource resource = new ClassPathResource(location, 110 this.classLoader); 111 if (resource.exists()) { 112 return "classpath:" + location; 113 } 114 } 115 return null; 116 } 117 118 /** 119 * Return the standard config locations for this system. 120 * @return the standard config locations 121 * @see #getSelfInitializationConfig() 122 */ 123 protected abstract String[] getStandardConfigLocations(); 124 125 /** 126 * Return the spring config locations for this system. By default this method returns 127 * a set of locations based on {@link #getStandardConfigLocations()}. 128 * @return the spring config locations 129 * @see #getSpringInitializationConfig() 130 */ 131 protected String[] getSpringConfigLocations() { 132 String[] locations = getStandardConfigLocations(); 133 for (int i = 0; i < locations.length; i++) { 134 String extension = StringUtils.getFilenameExtension(locations[i]); 135 locations[i] = locations[i].substring(0, 136 locations[i].length() - extension.length() - 1) + "-spring." 137 + extension; 138 } 139 return locations; 140 } 141 142 /** 143 * Load sensible defaults for the logging system. 144 * @param initializationContext the logging initialization context 145 * @param logFile the file to load or {@code null} if no log file is to be written 146 */ 147 protected abstract void loadDefaults( 148 LoggingInitializationContext initializationContext, LogFile logFile); 149 150 /** 151 * Load a specific configuration. 152 * @param initializationContext the logging initialization context 153 * @param location the location of the configuration to load (never {@code null}) 154 * @param logFile the file to load or {@code null} if no log file is to be written 155 */ 156 protected abstract void loadConfiguration( 157 LoggingInitializationContext initializationContext, String location, 158 LogFile logFile); 159 160 /** 161 * Reinitialize the logging system if required. Called when 162 * {@link #getSelfInitializationConfig()} is used and the log file hasn't changed. May 163 * be used to reload configuration (for example to pick up additional System 164 * properties). 165 * @param initializationContext the logging initialization context 166 */ 167 protected void reinitialize(LoggingInitializationContext initializationContext) { 168 } 169 170 protected final ClassLoader getClassLoader() { 171 return this.classLoader; 172 } 173 174 protected final String getPackagedConfigFile(String fileName) { 175 String defaultPath = ClassUtils.getPackageName(getClass()); 176 defaultPath = defaultPath.replace('.', '/'); 177 defaultPath = defaultPath + "/" + fileName; 178 defaultPath = "classpath:" + defaultPath; 179 return defaultPath; 180 } 181 182 protected final void applySystemProperties(Environment environment, LogFile logFile) { 183 new LoggingSystemProperties(environment).apply(logFile); 184 } 185 186 /** 187 * Maintains a mapping between native levels and {@link LogLevel}. 188 * 189 * @param <T> the native level type 190 */ 191 protected static class LogLevels<T> { 192 193 private final Map<LogLevel, T> systemToNative; 194 195 private final Map<T, LogLevel> nativeToSystem; 196 197 public LogLevels() { 198 this.systemToNative = new EnumMap<>(LogLevel.class); 199 this.nativeToSystem = new HashMap<>(); 200 } 201 202 public void map(LogLevel system, T nativeLevel) { 203 if (!this.systemToNative.containsKey(system)) { 204 this.systemToNative.put(system, nativeLevel); 205 } 206 if (!this.nativeToSystem.containsKey(nativeLevel)) { 207 this.nativeToSystem.put(nativeLevel, system); 208 } 209 } 210 211 public LogLevel convertNativeToSystem(T level) { 212 return this.nativeToSystem.get(level); 213 } 214 215 public T convertSystemToNative(LogLevel level) { 216 return this.systemToNative.get(level); 217 } 218 219 public Set<LogLevel> getSupported() { 220 return new LinkedHashSet<>(this.nativeToSystem.values()); 221 } 222 223 } 224 225}