Polish "Add startup time metrics"
See gh-27878
This commit is contained in:
@@ -20,7 +20,7 @@ import io.micrometer.core.instrument.MeterRegistry;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
|
||||
import org.springframework.boot.actuate.metrics.startup.StartupTimeMetrics;
|
||||
import org.springframework.boot.actuate.metrics.startup.StartupTimeMetricsListener;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
@@ -39,12 +39,12 @@ import org.springframework.context.annotation.Configuration;
|
||||
@AutoConfigureAfter({ MetricsAutoConfiguration.class, CompositeMeterRegistryAutoConfiguration.class })
|
||||
@ConditionalOnClass(MeterRegistry.class)
|
||||
@ConditionalOnBean(MeterRegistry.class)
|
||||
public class StartupTimeMetricsAutoConfiguration {
|
||||
public class StartupTimeMetricsListenerAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public StartupTimeMetrics startupTimeMetrics(MeterRegistry meterRegistry) {
|
||||
return new StartupTimeMetrics(meterRegistry);
|
||||
public StartupTimeMetricsListener startupTimeMetrics(MeterRegistry meterRegistry) {
|
||||
return new StartupTimeMetricsListener(meterRegistry);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -75,7 +75,7 @@ org.springframework.boot.actuate.autoconfigure.metrics.mongo.MongoMetricsAutoCon
|
||||
org.springframework.boot.actuate.autoconfigure.metrics.orm.jpa.HibernateMetricsAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.metrics.r2dbc.ConnectionPoolMetricsAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.metrics.redis.LettuceMetricsAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.metrics.startup.StartupTimeMetricsAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.metrics.startup.StartupTimeMetricsListenerAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.metrics.task.TaskExecutorMetricsAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.metrics.web.client.HttpClientMetricsAutoConfiguration,\
|
||||
org.springframework.boot.actuate.autoconfigure.metrics.web.jetty.JettyMetricsAutoConfiguration,\
|
||||
|
||||
@@ -25,7 +25,7 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun;
|
||||
import org.springframework.boot.actuate.metrics.startup.StartupTimeMetrics;
|
||||
import org.springframework.boot.actuate.metrics.startup.StartupTimeMetricsListener;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.boot.context.event.ApplicationStartedEvent;
|
||||
@@ -35,20 +35,20 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link StartupTimeMetricsAutoConfiguration}.
|
||||
* Tests for {@link StartupTimeMetricsListenerAutoConfiguration}.
|
||||
*
|
||||
* @author Chris Bono
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class StartupTimeMetricsAutoConfigurationTests {
|
||||
class StartupTimeMetricsListenerAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().with(MetricsRun.simple())
|
||||
.withConfiguration(AutoConfigurations.of(StartupTimeMetricsAutoConfiguration.class));
|
||||
.withConfiguration(AutoConfigurations.of(StartupTimeMetricsListenerAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void startupTimeMetricsAreRecorded() {
|
||||
this.contextRunner.run((context) -> {
|
||||
assertThat(context).hasSingleBean(StartupTimeMetrics.class);
|
||||
assertThat(context).hasSingleBean(StartupTimeMetricsListener.class);
|
||||
SimpleMeterRegistry registry = context.getBean(SimpleMeterRegistry.class);
|
||||
context.publishEvent(new ApplicationStartedEvent(new SpringApplication(), null,
|
||||
context.getSourceApplicationContext(), Duration.ofMillis(1500)));
|
||||
@@ -80,8 +80,9 @@ class StartupTimeMetricsAutoConfigurationTests {
|
||||
@Test
|
||||
void customStartupTimeMetricsAreRespected() {
|
||||
this.contextRunner
|
||||
.withBean("customStartupTimeMetrics", StartupTimeMetrics.class, () -> mock(StartupTimeMetrics.class))
|
||||
.run((context) -> assertThat(context).hasSingleBean(StartupTimeMetrics.class)
|
||||
.withBean("customStartupTimeMetrics", StartupTimeMetricsListener.class,
|
||||
() -> mock(StartupTimeMetricsListener.class))
|
||||
.run((context) -> assertThat(context).hasSingleBean(StartupTimeMetricsListener.class)
|
||||
.hasBean("customStartupTimeMetrics"));
|
||||
}
|
||||
|
||||
@@ -36,9 +36,10 @@ import org.springframework.context.event.SmartApplicationListener;
|
||||
* {@link ApplicationReadyEvent}.
|
||||
*
|
||||
* @author Chris Bono
|
||||
* @author Phillip Webb
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public class StartupTimeMetrics implements SmartApplicationListener {
|
||||
public class StartupTimeMetricsListener implements SmartApplicationListener {
|
||||
|
||||
/**
|
||||
* The default name to use for the application started time metric.
|
||||
@@ -52,11 +53,11 @@ public class StartupTimeMetrics implements SmartApplicationListener {
|
||||
|
||||
private final MeterRegistry meterRegistry;
|
||||
|
||||
private final String applicationStartedTimeMetricName;
|
||||
private final String startedTimeMetricName;
|
||||
|
||||
private final String applicationReadyTimeMetricName;
|
||||
private final String readyTimeMetricName;
|
||||
|
||||
private final Iterable<Tag> tags;
|
||||
private final Tags tags;
|
||||
|
||||
/**
|
||||
* Create a new instance using default metric names.
|
||||
@@ -64,26 +65,25 @@ public class StartupTimeMetrics implements SmartApplicationListener {
|
||||
* @see #APPLICATION_STARTED_TIME_METRIC_NAME
|
||||
* @see #APPLICATION_READY_TIME_METRIC_NAME
|
||||
*/
|
||||
public StartupTimeMetrics(MeterRegistry meterRegistry) {
|
||||
this(meterRegistry, Collections.emptyList(), APPLICATION_STARTED_TIME_METRIC_NAME,
|
||||
APPLICATION_READY_TIME_METRIC_NAME);
|
||||
public StartupTimeMetricsListener(MeterRegistry meterRegistry) {
|
||||
this(meterRegistry, APPLICATION_STARTED_TIME_METRIC_NAME, APPLICATION_READY_TIME_METRIC_NAME,
|
||||
Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance using the specified options.
|
||||
* @param meterRegistry the registry to use
|
||||
* @param startedTimeMetricName the name to use for the application started time
|
||||
* metric
|
||||
* @param readyTimeMetricName the name to use for the application ready time metric
|
||||
* @param tags the tags to associate to application startup metrics
|
||||
* @param applicationStartedTimeMetricName the name to use for the application started
|
||||
* time metric
|
||||
* @param applicationReadyTimeMetricName the name to use for the application ready
|
||||
* time metric
|
||||
*/
|
||||
public StartupTimeMetrics(MeterRegistry meterRegistry, Iterable<Tag> tags, String applicationStartedTimeMetricName,
|
||||
String applicationReadyTimeMetricName) {
|
||||
public StartupTimeMetricsListener(MeterRegistry meterRegistry, String startedTimeMetricName,
|
||||
String readyTimeMetricName, Iterable<Tag> tags) {
|
||||
this.meterRegistry = meterRegistry;
|
||||
this.tags = (tags != null) ? tags : Collections.emptyList();
|
||||
this.applicationStartedTimeMetricName = applicationStartedTimeMetricName;
|
||||
this.applicationReadyTimeMetricName = applicationReadyTimeMetricName;
|
||||
this.startedTimeMetricName = startedTimeMetricName;
|
||||
this.readyTimeMetricName = readyTimeMetricName;
|
||||
this.tags = Tags.of(tags);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -103,33 +103,27 @@ public class StartupTimeMetrics implements SmartApplicationListener {
|
||||
}
|
||||
|
||||
private void onApplicationStarted(ApplicationStartedEvent event) {
|
||||
if (event.getStartedTime() == null) {
|
||||
return;
|
||||
}
|
||||
registerGauge(this.applicationStartedTimeMetricName, "Time taken (ms) to start the application",
|
||||
event.getStartedTime(), createTagsFrom(event.getSpringApplication()));
|
||||
registerGauge(this.startedTimeMetricName, "Time taken (ms) to start the application", event.getTimeTaken(),
|
||||
event.getSpringApplication());
|
||||
}
|
||||
|
||||
private void onApplicationReady(ApplicationReadyEvent event) {
|
||||
if (event.getReadyTime() == null) {
|
||||
return;
|
||||
}
|
||||
registerGauge(this.applicationReadyTimeMetricName,
|
||||
"Time taken (ms) for the application to be ready to service requests", event.getReadyTime(),
|
||||
createTagsFrom(event.getSpringApplication()));
|
||||
registerGauge(this.readyTimeMetricName, "Time taken (ms) for the application to be ready to service requests",
|
||||
event.getTimeTaken(), event.getSpringApplication());
|
||||
}
|
||||
|
||||
private void registerGauge(String metricName, String description, Duration time, Iterable<Tag> tags) {
|
||||
TimeGauge.builder(metricName, time::toMillis, TimeUnit.MILLISECONDS).tags(tags).description(description)
|
||||
.register(this.meterRegistry);
|
||||
private void registerGauge(String name, String description, Duration timeTaken,
|
||||
SpringApplication springApplication) {
|
||||
if (timeTaken != null) {
|
||||
Iterable<Tag> tags = createTagsFrom(springApplication);
|
||||
TimeGauge.builder(name, timeTaken::toMillis, TimeUnit.MILLISECONDS).tags(tags).description(description)
|
||||
.register(this.meterRegistry);
|
||||
}
|
||||
}
|
||||
|
||||
private Iterable<Tag> createTagsFrom(SpringApplication springApplication) {
|
||||
Class<?> mainClass = springApplication.getMainApplicationClass();
|
||||
if (mainClass == null) {
|
||||
return this.tags;
|
||||
}
|
||||
return Tags.concat(this.tags, "main-application-class", mainClass.getName());
|
||||
return (mainClass != null) ? this.tags.and("main-application-class", mainClass.getName()) : this.tags;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -35,26 +35,26 @@ import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link StartupTimeMetrics}.
|
||||
* Tests for {@link StartupTimeMetricsListener}.
|
||||
*
|
||||
* @author Chris Bono
|
||||
*/
|
||||
class StartupTimeMetricsTests {
|
||||
class StartupTimeMetricsListenerTests {
|
||||
|
||||
private MeterRegistry registry;
|
||||
|
||||
private StartupTimeMetrics metrics;
|
||||
private StartupTimeMetricsListener listener;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
this.registry = new SimpleMeterRegistry();
|
||||
this.metrics = new StartupTimeMetrics(this.registry);
|
||||
this.listener = new StartupTimeMetricsListener(this.registry);
|
||||
}
|
||||
|
||||
@Test
|
||||
void metricsRecordedWithoutCustomTags() {
|
||||
this.metrics.onApplicationEvent(applicationStartedEvent(2000L));
|
||||
this.metrics.onApplicationEvent(applicationReadyEvent(2200L));
|
||||
this.listener.onApplicationEvent(applicationStartedEvent(2000L));
|
||||
this.listener.onApplicationEvent(applicationReadyEvent(2200L));
|
||||
assertMetricExistsWithValue("application.started.time", 2000L);
|
||||
assertMetricExistsWithValue("application.ready.time", 2200L);
|
||||
}
|
||||
@@ -62,9 +62,9 @@ class StartupTimeMetricsTests {
|
||||
@Test
|
||||
void metricsRecordedWithCustomTagsAndMetricNames() {
|
||||
Tags tags = Tags.of("foo", "bar");
|
||||
this.metrics = new StartupTimeMetrics(this.registry, tags, "m1", "m2");
|
||||
this.metrics.onApplicationEvent(applicationStartedEvent(1000L));
|
||||
this.metrics.onApplicationEvent(applicationReadyEvent(1050L));
|
||||
this.listener = new StartupTimeMetricsListener(this.registry, "m1", "m2", tags);
|
||||
this.listener.onApplicationEvent(applicationStartedEvent(1000L));
|
||||
this.listener.onApplicationEvent(applicationReadyEvent(1050L));
|
||||
assertMetricExistsWithCustomTagsAndValue("m1", tags, 1000L);
|
||||
assertMetricExistsWithCustomTagsAndValue("m2", tags, 1050L);
|
||||
}
|
||||
@@ -72,7 +72,7 @@ class StartupTimeMetricsTests {
|
||||
@Test
|
||||
void metricRecordedWithoutMainAppClassTag() {
|
||||
SpringApplication application = mock(SpringApplication.class);
|
||||
this.metrics.onApplicationEvent(new ApplicationStartedEvent(application, null, null, Duration.ofSeconds(2)));
|
||||
this.listener.onApplicationEvent(new ApplicationStartedEvent(application, null, null, Duration.ofSeconds(2)));
|
||||
TimeGauge applicationStartedGague = this.registry.find("application.started.time").timeGauge();
|
||||
assertThat(applicationStartedGague).isNotNull();
|
||||
assertThat(applicationStartedGague.getId().getTags()).isEmpty();
|
||||
@@ -82,8 +82,8 @@ class StartupTimeMetricsTests {
|
||||
void metricRecordedWithoutMainAppClassTagAndAdditionalTags() {
|
||||
SpringApplication application = mock(SpringApplication.class);
|
||||
Tags tags = Tags.of("foo", "bar");
|
||||
this.metrics = new StartupTimeMetrics(this.registry, tags, "started", "ready");
|
||||
this.metrics.onApplicationEvent(new ApplicationReadyEvent(application, null, null, Duration.ofSeconds(2)));
|
||||
this.listener = new StartupTimeMetricsListener(this.registry, "started", "ready", tags);
|
||||
this.listener.onApplicationEvent(new ApplicationReadyEvent(application, null, null, Duration.ofSeconds(2)));
|
||||
TimeGauge applicationReadyGague = this.registry.find("ready").timeGauge();
|
||||
assertThat(applicationReadyGague).isNotNull();
|
||||
assertThat(applicationReadyGague.getId().getTags()).containsExactlyElementsOf(tags);
|
||||
@@ -91,8 +91,8 @@ class StartupTimeMetricsTests {
|
||||
|
||||
@Test
|
||||
void metricsNotRecordedWhenStartupTimeNotAvailable() {
|
||||
this.metrics.onApplicationEvent(applicationStartedEvent(null));
|
||||
this.metrics.onApplicationEvent(applicationReadyEvent(null));
|
||||
this.listener.onApplicationEvent(applicationStartedEvent(null));
|
||||
this.listener.onApplicationEvent(applicationReadyEvent(null));
|
||||
assertThat(this.registry.find("application.started.time").timeGauge()).isNull();
|
||||
assertThat(this.registry.find("application.ready.time").timeGauge()).isNull();
|
||||
}
|
||||
@@ -78,7 +78,6 @@ import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StopWatch;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -286,8 +285,7 @@ public class SpringApplication {
|
||||
* @return a running {@link ApplicationContext}
|
||||
*/
|
||||
public ConfigurableApplicationContext run(String... args) {
|
||||
StopWatch stopWatch = new StopWatch();
|
||||
stopWatch.start();
|
||||
long startTime = System.nanoTime();
|
||||
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
|
||||
ConfigurableApplicationContext context = null;
|
||||
configureHeadlessProperty();
|
||||
@@ -303,23 +301,20 @@ public class SpringApplication {
|
||||
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
|
||||
refreshContext(context);
|
||||
afterRefresh(context, applicationArguments);
|
||||
stopWatch.stop();
|
||||
Duration startedTime = Duration.ofMillis(stopWatch.getTotalTimeMillis());
|
||||
stopWatch.start();
|
||||
Duration timeTakeToStartup = Duration.ofNanos(System.nanoTime() - startTime);
|
||||
if (this.logStartupInfo) {
|
||||
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), startedTime);
|
||||
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakeToStartup);
|
||||
}
|
||||
listeners.started(context, startedTime);
|
||||
listeners.started(context, timeTakeToStartup);
|
||||
callRunners(context, applicationArguments);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
handleRunFailure(context, ex, listeners);
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
|
||||
try {
|
||||
stopWatch.stop();
|
||||
listeners.running(context, Duration.ofMillis(stopWatch.getTotalTimeMillis()));
|
||||
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
|
||||
listeners.ready(context, timeTakenToReady);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
handleRunFailure(context, ex, null);
|
||||
|
||||
@@ -77,13 +77,11 @@ public interface SpringApplicationRunListener {
|
||||
* {@link CommandLineRunner CommandLineRunners} and {@link ApplicationRunner
|
||||
* ApplicationRunners} have not been called.
|
||||
* @param context the application context.
|
||||
* @since 2.0.0
|
||||
* @deprecated since 2.6.0 for removal in 2.8.0 in favour of
|
||||
* {@link #started(ConfigurableApplicationContext, Duration)}
|
||||
* @param timeTaken the time taken to start the application or {@code null} if unknown
|
||||
* @since 2.6.0
|
||||
*/
|
||||
@Deprecated
|
||||
default void started(ConfigurableApplicationContext context) {
|
||||
started(context, null);
|
||||
default void started(ConfigurableApplicationContext context, Duration timeTaken) {
|
||||
started(context);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,12 +89,12 @@ public interface SpringApplicationRunListener {
|
||||
* {@link CommandLineRunner CommandLineRunners} and {@link ApplicationRunner
|
||||
* ApplicationRunners} have not been called.
|
||||
* @param context the application context.
|
||||
* @param startedTime the time taken to start the application or {@code null} if
|
||||
* unknown
|
||||
* @since 2.6.0
|
||||
* @since 2.0.0
|
||||
* @deprecated since 2.6.0 for removal in 2.8.0 in favor of
|
||||
* {@link #started(ConfigurableApplicationContext, Duration)}
|
||||
*/
|
||||
default void started(ConfigurableApplicationContext context, Duration startedTime) {
|
||||
started(context);
|
||||
@Deprecated
|
||||
default void started(ConfigurableApplicationContext context) {
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,26 +102,25 @@ public interface SpringApplicationRunListener {
|
||||
* been refreshed and all {@link CommandLineRunner CommandLineRunners} and
|
||||
* {@link ApplicationRunner ApplicationRunners} have been called.
|
||||
* @param context the application context.
|
||||
* @deprecated since 2.6.0 for removal in 2.8.0 in favour of
|
||||
* {@link #running(ConfigurableApplicationContext, Duration)}
|
||||
* @param timeTaken the time taken for the application to be ready or {@code null} if
|
||||
* unknown
|
||||
* @since 2.6.0
|
||||
*/
|
||||
default void ready(ConfigurableApplicationContext context, Duration timeTaken) {
|
||||
running(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called immediately before the run method finishes, when the application context has
|
||||
* been refreshed and all {@link CommandLineRunner CommandLineRunners} and
|
||||
* {@link ApplicationRunner ApplicationRunners} have been called.
|
||||
* @param context the application context.
|
||||
* @deprecated since 2.6.0 for removal in 2.8.0 in favor of
|
||||
* {@link #ready(ConfigurableApplicationContext, Duration)}
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Deprecated
|
||||
default void running(ConfigurableApplicationContext context) {
|
||||
running(context, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called immediately before the run method finishes, when the application context has
|
||||
* been refreshed and all {@link CommandLineRunner CommandLineRunners} and
|
||||
* {@link ApplicationRunner ApplicationRunners} have been called.
|
||||
* @param context the application context.
|
||||
* @param readyTime the time taken for the application to be ready to service requests
|
||||
* or {@code null} if unknown
|
||||
* @since 2.6.0
|
||||
*/
|
||||
default void running(ConfigurableApplicationContext context, Duration readyTime) {
|
||||
running(context);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -74,12 +74,12 @@ class SpringApplicationRunListeners {
|
||||
doWithListeners("spring.boot.application.context-loaded", (listener) -> listener.contextLoaded(context));
|
||||
}
|
||||
|
||||
void started(ConfigurableApplicationContext context, Duration startupTime) {
|
||||
doWithListeners("spring.boot.application.started", (listener) -> listener.started(context, startupTime));
|
||||
void started(ConfigurableApplicationContext context, Duration timeTaken) {
|
||||
doWithListeners("spring.boot.application.started", (listener) -> listener.started(context, timeTaken));
|
||||
}
|
||||
|
||||
void running(ConfigurableApplicationContext context, Duration startupTime) {
|
||||
doWithListeners("spring.boot.application.running", (listener) -> listener.running(context, startupTime));
|
||||
void ready(ConfigurableApplicationContext context, Duration timeTaken) {
|
||||
doWithListeners("spring.boot.application.running", (listener) -> listener.ready(context, timeTaken));
|
||||
}
|
||||
|
||||
void failed(ConfigurableApplicationContext context, Throwable exception) {
|
||||
|
||||
@@ -56,9 +56,9 @@ class StartupInfoLogger {
|
||||
applicationLog.debug(LogMessage.of(this::getRunningMessage));
|
||||
}
|
||||
|
||||
void logStarted(Log applicationLog, Duration startupTime) {
|
||||
void logStarted(Log applicationLog, Duration timeTakeToStartup) {
|
||||
if (applicationLog.isInfoEnabled()) {
|
||||
applicationLog.info(getStartedMessage(startupTime));
|
||||
applicationLog.info(getStartedMessage(timeTakeToStartup));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,12 +83,12 @@ class StartupInfoLogger {
|
||||
return message;
|
||||
}
|
||||
|
||||
private CharSequence getStartedMessage(Duration startupTime) {
|
||||
private CharSequence getStartedMessage(Duration timeTakeToStartup) {
|
||||
StringBuilder message = new StringBuilder();
|
||||
message.append("Started ");
|
||||
appendApplicationName(message);
|
||||
message.append(" in ");
|
||||
message.append(startupTime.toMillis() / 1000.0);
|
||||
message.append(timeTakeToStartup.toMillis() / 1000.0);
|
||||
message.append(" seconds");
|
||||
try {
|
||||
double uptime = ManagementFactory.getRuntimeMXBean().getUptime() / 1000.0;
|
||||
|
||||
@@ -37,7 +37,7 @@ public class ApplicationReadyEvent extends SpringApplicationEvent {
|
||||
|
||||
private final ConfigurableApplicationContext context;
|
||||
|
||||
private final Duration readyTime;
|
||||
private final Duration timeTaken;
|
||||
|
||||
/**
|
||||
* Create a new {@link ApplicationReadyEvent} instance.
|
||||
@@ -57,14 +57,14 @@ public class ApplicationReadyEvent extends SpringApplicationEvent {
|
||||
* @param application the current application
|
||||
* @param args the arguments the application is running with
|
||||
* @param context the context that was being created
|
||||
* @param readyTime the time taken to get the application ready to service requests
|
||||
* @param timeTaken the time taken to get the application ready to service requests
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public ApplicationReadyEvent(SpringApplication application, String[] args, ConfigurableApplicationContext context,
|
||||
Duration readyTime) {
|
||||
Duration timeTaken) {
|
||||
super(application, args);
|
||||
this.context = context;
|
||||
this.readyTime = readyTime;
|
||||
this.timeTaken = timeTaken;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -79,9 +79,10 @@ public class ApplicationReadyEvent extends SpringApplicationEvent {
|
||||
* Return the time taken for the application to be ready to service requests, or
|
||||
* {@code null} if unknown.
|
||||
* @return the time taken to be ready to service requests
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public Duration getReadyTime() {
|
||||
return this.readyTime;
|
||||
public Duration getTimeTaken() {
|
||||
return this.timeTaken;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ public class ApplicationStartedEvent extends SpringApplicationEvent {
|
||||
|
||||
private final ConfigurableApplicationContext context;
|
||||
|
||||
private final Duration startedTime;
|
||||
private final Duration timeTaken;
|
||||
|
||||
/**
|
||||
* Create a new {@link ApplicationStartedEvent} instance.
|
||||
@@ -57,14 +57,14 @@ public class ApplicationStartedEvent extends SpringApplicationEvent {
|
||||
* @param application the current application
|
||||
* @param args the arguments the application is running with
|
||||
* @param context the context that was being created
|
||||
* @param startedTime the time taken to start the application
|
||||
* @param timeTaken the time taken to start the application
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public ApplicationStartedEvent(SpringApplication application, String[] args, ConfigurableApplicationContext context,
|
||||
Duration startedTime) {
|
||||
Duration timeTaken) {
|
||||
super(application, args);
|
||||
this.context = context;
|
||||
this.startedTime = startedTime;
|
||||
this.timeTaken = timeTaken;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,9 +78,10 @@ public class ApplicationStartedEvent extends SpringApplicationEvent {
|
||||
/**
|
||||
* Return the time taken to start the application, or {@code null} if unknown.
|
||||
* @return the startup time
|
||||
* @since 2.6.0
|
||||
*/
|
||||
public Duration getStartedTime() {
|
||||
return this.startedTime;
|
||||
public Duration getTimeTaken() {
|
||||
return this.timeTaken;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -104,14 +104,14 @@ public class EventPublishingRunListener implements SpringApplicationRunListener,
|
||||
}
|
||||
|
||||
@Override
|
||||
public void started(ConfigurableApplicationContext context, Duration startedTime) {
|
||||
context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context, startedTime));
|
||||
public void started(ConfigurableApplicationContext context, Duration timeTaken) {
|
||||
context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context, timeTaken));
|
||||
AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void running(ConfigurableApplicationContext context, Duration readyTime) {
|
||||
context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context, readyTime));
|
||||
public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
|
||||
context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context, timeTaken));
|
||||
AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);
|
||||
}
|
||||
|
||||
|
||||
@@ -363,7 +363,7 @@ class SpringApplicationTests {
|
||||
void applicationRunningEventListener() {
|
||||
SpringApplication application = new SpringApplication(ExampleConfig.class);
|
||||
application.setWebApplicationType(WebApplicationType.NONE);
|
||||
AtomicReference<ApplicationReadyEvent> reference = setupListener(application, ApplicationReadyEvent.class);
|
||||
AtomicReference<ApplicationReadyEvent> reference = addListener(application, ApplicationReadyEvent.class);
|
||||
this.context = application.run("--foo=bar");
|
||||
assertThat(application).isSameAs(reference.get().getSpringApplication());
|
||||
}
|
||||
@@ -372,7 +372,7 @@ class SpringApplicationTests {
|
||||
void contextRefreshedEventListener() {
|
||||
SpringApplication application = new SpringApplication(ExampleConfig.class);
|
||||
application.setWebApplicationType(WebApplicationType.NONE);
|
||||
AtomicReference<ContextRefreshedEvent> reference = setupListener(application, ContextRefreshedEvent.class);
|
||||
AtomicReference<ContextRefreshedEvent> reference = addListener(application, ContextRefreshedEvent.class);
|
||||
this.context = application.run("--foo=bar");
|
||||
assertThat(this.context).isSameAs(reference.get().getApplicationContext());
|
||||
// Custom initializers do not switch off the defaults
|
||||
@@ -405,18 +405,18 @@ class SpringApplicationTests {
|
||||
void applicationStartedEventHasStartedTime() {
|
||||
SpringApplication application = new SpringApplication(ExampleConfig.class);
|
||||
application.setWebApplicationType(WebApplicationType.NONE);
|
||||
AtomicReference<ApplicationStartedEvent> reference = setupListener(application, ApplicationStartedEvent.class);
|
||||
AtomicReference<ApplicationStartedEvent> reference = addListener(application, ApplicationStartedEvent.class);
|
||||
this.context = application.run();
|
||||
assertThat(reference.get()).isNotNull().extracting(ApplicationStartedEvent::getStartedTime).isNotNull();
|
||||
assertThat(reference.get()).isNotNull().extracting(ApplicationStartedEvent::getTimeTaken).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void applicationReadyEventHasReadyTime() {
|
||||
SpringApplication application = new SpringApplication(ExampleConfig.class);
|
||||
application.setWebApplicationType(WebApplicationType.NONE);
|
||||
AtomicReference<ApplicationReadyEvent> reference = setupListener(application, ApplicationReadyEvent.class);
|
||||
AtomicReference<ApplicationReadyEvent> reference = addListener(application, ApplicationReadyEvent.class);
|
||||
this.context = application.run();
|
||||
assertThat(reference.get()).isNotNull().extracting(ApplicationReadyEvent::getReadyTime).isNotNull();
|
||||
assertThat(reference.get()).isNotNull().extracting(ApplicationReadyEvent::getTimeTaken).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1252,24 +1252,10 @@ class SpringApplicationTests {
|
||||
&& ((AvailabilityChangeEvent<?>) argument).getState().equals(state);
|
||||
}
|
||||
|
||||
private <T extends ApplicationEvent> AtomicReference<T> setupListener(SpringApplication application,
|
||||
Class<T> targetEventType) {
|
||||
final AtomicReference<T> reference = new AtomicReference<>();
|
||||
class TestEventListener implements SmartApplicationListener {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void onApplicationEvent(ApplicationEvent event) {
|
||||
reference.set((T) event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
|
||||
return targetEventType.isAssignableFrom(eventType);
|
||||
}
|
||||
|
||||
}
|
||||
application.addListeners(new TestEventListener());
|
||||
private <E extends ApplicationEvent> AtomicReference<E> addListener(SpringApplication application,
|
||||
Class<E> eventType) {
|
||||
AtomicReference<E> reference = new AtomicReference<>();
|
||||
application.addListeners(new TestEventListener<>(eventType, reference));
|
||||
return reference;
|
||||
}
|
||||
|
||||
@@ -1302,6 +1288,30 @@ class SpringApplicationTests {
|
||||
};
|
||||
}
|
||||
|
||||
static class TestEventListener<E extends ApplicationEvent> implements SmartApplicationListener {
|
||||
|
||||
private final Class<E> eventType;
|
||||
|
||||
private final AtomicReference<E> reference;
|
||||
|
||||
TestEventListener(Class<E> eventType, AtomicReference<E> reference) {
|
||||
this.eventType = eventType;
|
||||
this.reference = reference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
|
||||
return this.eventType.isAssignableFrom(eventType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void onApplicationEvent(ApplicationEvent event) {
|
||||
this.reference.set((E) event);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class InaccessibleConfiguration {
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import org.springframework.boot.system.ApplicationPid;
|
||||
import org.springframework.util.StopWatch;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
@@ -56,11 +55,9 @@ class StartupInfoLoggerTests {
|
||||
|
||||
@Test
|
||||
void startedFormat() {
|
||||
StopWatch stopWatch = new StopWatch();
|
||||
stopWatch.start();
|
||||
given(this.log.isInfoEnabled()).willReturn(true);
|
||||
stopWatch.stop();
|
||||
new StartupInfoLogger(getClass()).logStarted(this.log, Duration.ofMillis(stopWatch.getTotalTimeMillis()));
|
||||
Duration timeTakeToStartup = Duration.ofMillis(10);
|
||||
new StartupInfoLogger(getClass()).logStarted(this.log, timeTakeToStartup);
|
||||
ArgumentCaptor<Object> captor = ArgumentCaptor.forClass(Object.class);
|
||||
verify(this.log).info(captor.capture());
|
||||
assertThat(captor.getValue().toString()).matches("Started " + getClass().getSimpleName()
|
||||
|
||||
@@ -74,7 +74,7 @@ class EventPublishingRunListenerTests {
|
||||
context.refresh();
|
||||
this.runListener.started(context, null);
|
||||
checkApplicationEvents(ApplicationStartedEvent.class, AvailabilityChangeEvent.class);
|
||||
this.runListener.running(context, null);
|
||||
this.runListener.ready(context, null);
|
||||
checkApplicationEvents(ApplicationReadyEvent.class, AvailabilityChangeEvent.class);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user