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