SpringBoot 中的log 源码分析:
加载配置文件
*/
class JavaLoggingSystemRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints.resources().registerPattern("org/springframework/boot/logging/java/logging.properties");
hints.resources().registerPattern("org/springframework/boot/logging/java/logging-file.properties");
}
}
SimpleFormatter :
public class SimpleFormatter extends Formatter {
private static final String DEFAULT_FORMAT = "[%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%1$tL] - %8$s %4$s [%7$s] --- %3$s: %5$s%6$s%n";
private final String format = getOrUseDefault("LOG_FORMAT", DEFAULT_FORMAT);
private final String pid = getOrUseDefault(LoggingSystemProperties.PID_KEY, "????");
private final Date date = new Date();
@Override
public synchronized String format(LogRecord record) {
this.date.setTime(record.getMillis());
String source = record.getLoggerName();
String message = formatMessage(record);
String throwable = getThrowable(record);
String thread = getThreadName();
return String.format(this.format, this.date, source, record.getLoggerName(),
record.getLevel().getLocalizedName(), message, throwable, thread, this.pid);
}
private String getThrowable(LogRecord record) {
if (record.getThrown() == null) {
return "";
}
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
printWriter.println();
record.getThrown().printStackTrace(printWriter);
printWriter.close();
return stringWriter.toString();
}
private String getThreadName() {
String name = Thread.currentThread().getName();
return (name != null) ? name : "";
}
private static String getOrUseDefault(String key, String defaultValue) {
String value = null;
try {
value = System.getenv(key);
}
catch (Exception ex) {
// ignore
}
if (value == null) {
value = defaultValue;
}
return System.getProperty(key, value);
}
}
public class SpringBootPropertySource implements PropertySource {
private static final String PREFIX = "log4j.";
private final Map<String, String> properties = Collections
.singletonMap(ShutdownCallbackRegistry.SHUTDOWN_HOOK_ENABLED, "false");
@Override
public void forEach(BiConsumer<String, String> action) {
this.properties.forEach(action::accept);
}
@Override
public CharSequence getNormalForm(Iterable<? extends CharSequence> tokens) {
return PREFIX + Util.joinAsCamelCase(tokens);
}
@Override
public int getPriority() {
return -200;
}
@Override
public String getProperty(String key) {
return this.properties.get(key);
}
@Override
public boolean containsProperty(String key) {
return this.properties.containsKey(key);
}
@Override
public Collection<String> getPropertyNames() {
return this.properties.keySet();
}
}
@Plugin(name = "SpringBootConfigurationFactory", category = ConfigurationFactory.CATEGORY)
@Order(0)
public class SpringBootConfigurationFactory extends ConfigurationFactory {
private static final String[] TYPES = { ".springboot" };
@Override
protected String[] getSupportedTypes() {
return TYPES;
}
@Override
public Configuration getConfiguration(LoggerContext loggerContext, ConfigurationSource source) {
if (source == null || source == ConfigurationSource.NULL_SOURCE) {
return null;
}
return new DefaultConfiguration();
}
}
其中logback 的用法如下:
public abstract class AbstractLoggingSystem extends LoggingSystem {
protected static final Comparator<LoggerConfiguration> CONFIGURATION_COMPARATOR = new LoggerConfigurationComparator(
ROOT_LOGGER_NAME);
private final ClassLoader classLoader;
public AbstractLoggingSystem(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@Override
public void beforeInitialize() {
}
@Override
public void initialize(LoggingInitializationContext initializationContext, String configLocation, LogFile logFile) {
if (StringUtils.hasLength(configLocation)) {
initializeWithSpecificConfig(initializationContext, configLocation, logFile);
return;
}
initializeWithConventions(initializationContext, logFile);
}
private void initializeWithSpecificConfig(LoggingInitializationContext initializationContext, String configLocation,
LogFile logFile) {
configLocation = SystemPropertyUtils.resolvePlaceholders(configLocation);
loadConfiguration(initializationContext, configLocation, logFile);
}
private void initializeWithConventions(LoggingInitializationContext initializationContext, LogFile logFile) {
String config = getSelfInitializationConfig();
if (config != null && logFile == null) {
// self initialization has occurred, reinitialize in case of property changes
reinitialize(initializationContext);
return;
}
if (config == null) {
config = getSpringInitializationConfig();
}
if (config != null) {
loadConfiguration(initializationContext, config, logFile);
return;
}
loadDefaults(initializationContext, logFile);
}
/**
* Return any self initialization config that has been applied. By default this method
* checks {@link #getStandardConfigLocations()} and assumes that any file that exists
* will have been applied.
* @return the self initialization config or {@code null}
*/
protected String getSelfInitializationConfig() {
return findConfig(getStandardConfigLocations());
}
/**
* Return any spring specific initialization config that should be applied. By default
* this method checks {@link #getSpringConfigLocations()}.
* @return the spring initialization config or {@code null}
*/
protected String getSpringInitializationConfig() {
return findConfig(getSpringConfigLocations());
}
private String findConfig(String[] locations) {
for (String location : locations) {
ClassPathResource resource = new ClassPathResource(location, this.classLoader);
if (resource.exists()) {
return "classpath:" + location;
}
}
return null;
}
/**
* Return the standard config locations for this system.
* @return the standard config locations
* @see #getSelfInitializationConfig()
*/
protected abstract String[] getStandardConfigLocations();
/**
* Return the spring config locations for this system. By default this method returns
* a set of locations based on {@link #getStandardConfigLocations()}.
* @return the spring config locations
* @see #getSpringInitializationConfig()
*/
protected String[] getSpringConfigLocations() {
String[] locations = getStandardConfigLocations();
for (int i = 0; i < locations.length; i++) {
String extension = StringUtils.getFilenameExtension(locations[i]);
locations[i] = locations[i].substring(0, locations[i].length() - extension.length() - 1) + "-spring."
+ extension;
}
return locations;
}
/**
* Load sensible defaults for the logging system.
* @param initializationContext the logging initialization context
* @param logFile the file to load or {@code null} if no log file is to be written
*/
protected abstract void loadDefaults(LoggingInitializationContext initializationContext, LogFile logFile);
/**
* Load a specific configuration.
* @param initializationContext the logging initialization context
* @param location the location of the configuration to load (never {@code null})
* @param logFile the file to load or {@code null} if no log file is to be written
*/
protected abstract void loadConfiguration(LoggingInitializationContext initializationContext, String location,
LogFile logFile);
/**
* Reinitialize the logging system if required. Called when
* {@link #getSelfInitializationConfig()} is used and the log file hasn't changed. May
* be used to reload configuration (for example to pick up additional System
* properties).
* @param initializationContext the logging initialization context
*/
protected void reinitialize(LoggingInitializationContext initializationContext) {
}
protected final ClassLoader getClassLoader() {
return this.classLoader;
}
protected final String getPackagedConfigFile(String fileName) {
String defaultPath = ClassUtils.getPackageName(getClass());
defaultPath = defaultPath.replace('.', '/');
defaultPath = defaultPath + "/" + fileName;
defaultPath = "classpath:" + defaultPath;
return defaultPath;
}
protected final void applySystemProperties(Environment environment, LogFile logFile) {
new LoggingSystemProperties(environment).apply(logFile);
}
/**
* Maintains a mapping between native levels and {@link LogLevel}.
*
* @param <T> the native level type
*/
protected static class LogLevels<T> {
private final Map<LogLevel, T> systemToNative;
private final Map<T, LogLevel> nativeToSystem;
public LogLevels() {
this.systemToNative = new EnumMap<>(LogLevel.class);
this.nativeToSystem = new HashMap<>();
}
public void map(LogLevel system, T nativeLevel) {
this.systemToNative.putIfAbsent(system, nativeLevel);
this.nativeToSystem.putIfAbsent(nativeLevel, system);
}
public LogLevel convertNativeToSystem(T level) {
return this.nativeToSystem.get(level);
}
public T convertSystemToNative(LogLevel level) {
return this.systemToNative.get(level);
}
public Set<LogLevel> getSupported() {
return new LinkedHashSet<>(this.nativeToSystem.values());
}
}
}
deferedLogs:
public class DeferredLogs implements DeferredLogFactory {
private final Lines lines = new Lines();
private final List<DeferredLog> loggers = new ArrayList<>();
/**
* Create a new {@link DeferredLog} for the given destination.
* @param destination the ultimate log destination
* @return a deferred log instance that will switch to the destination when
* appropriate.
*/
@Override
public Log getLog(Class<?> destination) {
return getLog(() -> LogFactory.getLog(destination));
}
/**
* Create a new {@link DeferredLog} for the given destination.
* @param destination the ultimate log destination
* @return a deferred log instance that will switch to the destination when
* appropriate.
*/
@Override
public Log getLog(Log destination) {
return getLog(() -> destination);
}
/**
* Create a new {@link DeferredLog} for the given destination.
* @param destination the ultimate log destination
* @return a deferred log instance that will switch to the destination when
* appropriate.
*/
@Override
public Log getLog(Supplier<Log> destination) {
synchronized (this.lines) {
DeferredLog logger = new DeferredLog(destination, this.lines);
this.loggers.add(logger);
return logger;
}
}
/**
* Switch over all deferred logs to their supplied destination.
*/
public void switchOverAll() {
synchronized (this.lines) {
for (Line line : this.lines) {
DeferredLog.logTo(line.getDestination(), line.getLevel(), line.getMessage(), line.getThrowable());
}
for (DeferredLog logger : this.loggers) {
logger.switchOver();
}
this.lines.clear();
}
}
}
SprigBoot 中的log 处理:
Java Util Logging
Logging
Log4j2
Logback(默认)