Improve diagnostics when native image fails before logging is set up
Closes gh-40429
This commit is contained in:
parent
335d42ba64
commit
172b3d5336
|
|
@ -74,6 +74,7 @@ import org.springframework.context.aot.AotApplicationContextInitializer;
|
|||
import org.springframework.context.support.AbstractApplicationContext;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.core.NativeDetector;
|
||||
import org.springframework.core.OrderComparator;
|
||||
import org.springframework.core.OrderComparator.OrderSourceProvider;
|
||||
import org.springframework.core.Ordered;
|
||||
|
|
@ -832,7 +833,16 @@ public class SpringApplication {
|
|||
// Continue with normal handling of the original failure
|
||||
}
|
||||
if (logger.isErrorEnabled()) {
|
||||
logger.error("Application run failed", failure);
|
||||
if (NativeDetector.inNativeImage()) {
|
||||
// Depending on how early the failure was, logging may not work in a
|
||||
// native image so we output the stack trace directly to System.out
|
||||
// instead.
|
||||
System.out.println("Application run failed");
|
||||
failure.printStackTrace(System.out);
|
||||
}
|
||||
else {
|
||||
logger.error("Application run failed", failure);
|
||||
}
|
||||
registerLoggedException(failure);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ import org.springframework.boot.context.event.ApplicationStartedEvent;
|
|||
import org.springframework.boot.context.event.ApplicationStartingEvent;
|
||||
import org.springframework.boot.context.event.SpringApplicationEvent;
|
||||
import org.springframework.boot.convert.ApplicationConversionService;
|
||||
import org.springframework.boot.testsupport.classpath.ForkedClassPath;
|
||||
import org.springframework.boot.testsupport.system.CapturedOutput;
|
||||
import org.springframework.boot.testsupport.system.OutputCaptureExtension;
|
||||
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
|
||||
|
|
@ -749,6 +750,53 @@ class SpringApplicationTests {
|
|||
assertThat(output).contains("Application run failed");
|
||||
}
|
||||
|
||||
@Test
|
||||
void failureOnTheJvmLogsApplicationRunFailed(CapturedOutput output) {
|
||||
SpringApplication application = new SpringApplication(ExampleConfig.class);
|
||||
application.setWebApplicationType(WebApplicationType.NONE);
|
||||
ExitCodeListener exitCodeListener = new ExitCodeListener();
|
||||
application.addListeners(exitCodeListener);
|
||||
@SuppressWarnings("unchecked")
|
||||
ApplicationListener<SpringApplicationEvent> listener = mock(ApplicationListener.class);
|
||||
application.addListeners(listener);
|
||||
ExitStatusException failure = new ExitStatusException();
|
||||
willThrow(failure).given(listener).onApplicationEvent(isA(ApplicationReadyEvent.class));
|
||||
assertThatExceptionOfType(RuntimeException.class).isThrownBy(application::run);
|
||||
then(listener).should().onApplicationEvent(isA(ApplicationReadyEvent.class));
|
||||
then(listener).should(never()).onApplicationEvent(isA(ApplicationFailedEvent.class));
|
||||
assertThat(exitCodeListener.getExitCode()).isEqualTo(11);
|
||||
// Leading space only happens when logging
|
||||
assertThat(output).contains(" Application run failed").contains("ExitStatusException");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ForkedClassPath
|
||||
void failureInANativeImageWritesFailureToSystemOut(CapturedOutput output) {
|
||||
System.setProperty("org.graalvm.nativeimage.imagecode", "true");
|
||||
try {
|
||||
SpringApplication application = new SpringApplication(ExampleConfig.class);
|
||||
application.setWebApplicationType(WebApplicationType.NONE);
|
||||
ExitCodeListener exitCodeListener = new ExitCodeListener();
|
||||
application.addListeners(exitCodeListener);
|
||||
@SuppressWarnings("unchecked")
|
||||
ApplicationListener<SpringApplicationEvent> listener = mock(ApplicationListener.class);
|
||||
application.addListeners(listener);
|
||||
ExitStatusException failure = new ExitStatusException();
|
||||
willThrow(failure).given(listener).onApplicationEvent(isA(ApplicationReadyEvent.class));
|
||||
assertThatExceptionOfType(RuntimeException.class).isThrownBy(application::run);
|
||||
then(listener).should().onApplicationEvent(isA(ApplicationReadyEvent.class));
|
||||
then(listener).should(never()).onApplicationEvent(isA(ApplicationFailedEvent.class));
|
||||
assertThat(exitCodeListener.getExitCode()).isEqualTo(11);
|
||||
// Leading space only happens when logging
|
||||
assertThat(output).doesNotContain(" Application run failed")
|
||||
.contains("Application run failed")
|
||||
.contains("ExitStatusException");
|
||||
}
|
||||
finally {
|
||||
System.clearProperty("org.graalvm.nativeimage.imagecode");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void loadSources() {
|
||||
Class<?>[] sources = { ExampleConfig.class, TestCommandLineRunner.class };
|
||||
|
|
|
|||
Loading…
Reference in New Issue