应用背景
为了规范统一所有微服务应用中的log4j2配置, 默认所有应用在启动时读取统一URL指向的log4j2.yml文件,lo4j2.yml文件中预留了应用名等占位符, 需要从Spring上下文环境中解析占位符。
log4j2配置占位符解析
解析时机
-
初始化log4j2上下文时对其中的占位符进行解析。
-
日志打印格式中配置的占位符输出日志时解析。
解析原理
主要根据占位符的前缀寻找合适的Lookup解析相关变量。
官方已经提供的lookup:
Context Map Lookup
从log4j2的ThreadContext中解析占位变量。前缀为"ctx:"
Date Lookup
根据当前时间或者日志事件时间按照配置格式解析占位符,前缀为"date:"
Environment Lookup
从系统变量解析占位符,前缀为“env:”
Java Lookup
java环境信息,前缀为"java:". 如"java:vm"解析为"Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode)"
Jndi Lookup
JVM Input Arguments Lookup (JMX)
Log4j Configuration Location Lookup
Main Arguments Lookup (Application)
Map Lookup
Marker Lookup
Structured Data Lookup
System Properties Lookup
Web Lookup
增加一个SpringEnvrionmentLookup
@Plugin(name = "spring", category = StrLookup.CATEGORY)
public class SpringEnvrionmentLookup extends AbstractLookup {
/**
* Looks up the value of the spring environment variable.
*
* @param event The current LogEvent (is ignored by this StrLookup).
* @param key the key to be looked up, may be null
* @return The value of the spring environment variable.
*/
@Override
public String lookup(final LogEvent event, final String key) {
if (SpringContext.getEnvironment() != null) {
return SpringContext.getEnvironment().getProperty(key);
}
return null;
}
}
初始化SpringContext
- 利用Springboot的事件机制,监听ApplicationEnvironmentPreparedEvent,即当Spring的Environment准备好时,将Spring的Environment引用赋值给类SpringContext里的静态变量。
public class SpringContextEnvironmentApplicationListener implements SmartApplicationListener {
private int order = Ordered.HIGHEST_PRECEDENCE + 10;
private static Class<?>[] EVENT_TYPES = {ApplicationEnvironmentPreparedEvent.class};
private static Class<?>[] SOURCE_TYPES = {SpringApplication.class,
ApplicationContext.class};
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return isAssignableFrom(eventType, EVENT_TYPES);
}
@Override
public boolean supportsSourceType(Class<?> sourceType) {
return isAssignableFrom(sourceType, SOURCE_TYPES);
}
private boolean isAssignableFrom(Class<?> type, Class<?>... supportedTypes) {
for (Class<?> supportedType : supportedTypes) {
if (supportedType.isAssignableFrom(type)) {
return true;
}
}
return false;
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
SpringContext.setEnvironment(((ApplicationEnvironmentPreparedEvent) event).getEnvironment());
}
}
@Override
public int getOrder() {
return order;
}
}
使用方法
...
fileName: /var/log/apps/${spring:spring.application.name}/info.log
filePattern: /var/log/apps/${spring:spring.application.name}/info.%d{yyyy-MM-dd}.log.tar.gz
PatternLayout:
Pattern: '[%d]\t%p\t[${spring:spring.application.name}]\t--\t%m%n'
...