У меня есть Весеннее пакетное задание, которое отвечает за обработку входящих файлов клиента. Одним из требований является то, что ведение журнала выполняется для разделения файлов журналов на выполнение задания (по клиенту).Весна сбрасывает мою конфигурацию регистрации - как мне обойти это?
В основном приложении я обрабатываю аргументы командной строки, а затем динамически создаю свой FileAppender.
Мой logback.xml:
<configuration>
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="Console" />
</root>
</configuration>
Мой код добавления Appender:
private static void setupFileAppender() {
String logDir = fetchLogDir();
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
String datePortion = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
FileAppender<ILoggingEvent> fileAppender = new FileAppender<>();
fileAppender.setContext(loggerContext);
fileAppender.setName("File");
fileAppender.setFile(logDir + baseFileName + "-" + datePortion + ".log");
fileAppender.setAppend(true);
PatternLayoutEncoder encoder = new PatternLayoutEncoder();
encoder.setContext(loggerContext);
encoder.setPattern("%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{35} - %msg%n");
encoder.start();
fileAppender.setEncoder(encoder);
fileAppender.start();
Logger rootLogger = loggerContext.getLogger("root");
rootLogger.addAppender(fileAppender);
log.info("Logging configured.");
}
Любые заявления журнала, выполненные из моей основной (или звонки из него) в файл журнала, как и ожидалось. Я могу развернуться в режиме отладки и увидеть, что у меня есть два приложения в корневом журнале - «Консоль» и «Файл» из двух конфигураций. Однако, как только я запускаю команду SpringApplication.run
, FileAppender
исчезает.
Я прошел через метод SpringApplicaton.run(...)
, и я обнаружил, что Spring сбрасывает мою конфигурацию ведения журнала и перезагружает ее из файла logback.xml.
От SpringApplication:
try {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, args);
for (SpringApplicationRunListener runListener : runListeners) {
runListener.environmentPrepared(environment);
}
...
От EventPublishingRunListener
:
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
publishEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args,
environment));
}
private void publishEvent(SpringApplicationEvent event) {
this.multicaster.multicastEvent(event);
}
Пару звонков позже, то LoggingApplicationListener
:
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationStartedEvent) {
onApplicationStartedEvent((ApplicationStartedEvent) event);
}
else if (event instanceof ApplicationEnvironmentPreparedEvent) {
onApplicationPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
}
}
private void onApplicationPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
if (this.loggingSystem == null) {
this.loggingSystem = LoggingSystem.get(event.getSpringApplication()
.getClassLoader());
}
initialize(event.getEnvironment(), event.getSpringApplication().getClassLoader());
}
protected void initialize(ConfigurableEnvironment environment, ClassLoader classLoader) {
if (System.getProperty(PID_KEY) == null) {
System.setProperty(PID_KEY, new ApplicationPid().toString());
}
initializeEarlyLoggingLevel(environment);
initializeSystem(environment, this.loggingSystem);
initializeFinalLoggingLevels(environment, this.loggingSystem);
}
private void initializeSystem(ConfigurableEnvironment environment,
LoggingSystem system) {
LogFile logFile = LogFile.get(environment);
String logConfig = environment.getProperty(CONFIG_PROPERTY);
if (StringUtils.hasLength(logConfig)) {
try {
ResourceUtils.getURL(logConfig).openStream().close();
system.initialize(logConfig, logFile);
}
catch (Exception ex) {
this.logger.warn("Logging environment value '" + logConfig
+ "' cannot be opened and will be ignored "
+ "(using default location instead)");
system.initialize(null, logFile);
}
}
else {
system.initialize(null, logFile);
}
}
В LogbackLoggingSystem
(и AbstractLoggingSystem
):
@Override
public void initialize(String configLocation, LogFile logFile) {
getLogger(null).getLoggerContext().getTurboFilterList().remove(FILTER);
super.initialize(configLocation, logFile);
}
@Override
public void initialize(String configLocation, LogFile logFile) {
if (StringUtils.hasLength(configLocation)) {
// Load a specific configuration
configLocation = SystemPropertyUtils.resolvePlaceholders(configLocation);
loadConfiguration(configLocation, logFile);
}
else {
String selfInitializationConfig = getSelfInitializationConfig();
if (selfInitializationConfig == null) {
// No self initialization has occurred, use defaults
loadDefaults(logFile);
}
else if (logFile != null) {
// Self initialization has occurred but the file has changed, reload
loadConfiguration(selfInitializationConfig, logFile);
}
else {
reinitialize();
}
}
}
Последнее еще ударил выше, и reinitialize()
называется:
@Override
protected void reinitialize() {
getLoggerContext().reset();
loadConfiguration(getSelfInitializationConfig(), null);
}
Вызов для сброса от контекста является то, что сбрасывает все. Дело в том, что копание в методе loadConfiguration
также вызывает метод сброса в контексте ведения журнала.
Любые идеи о том, как обойти пружину, сбросив мою конфигурацию регистрации?
FYI, я использую версию Spring версии 4.1.4.RELEASE.
Этот вопрос не связан с весной или весной, все это связано с Spring Boot. –