Polish StartupInfoLogger message creation

Rework some of the internals of `StartupInfoLogger` so that fewer
strings are created.
This commit is contained in:
Phillip Webb
2019-04-19 14:08:13 -07:00
parent ba196b47ac
commit 405135d5a8
2 changed files with 75 additions and 65 deletions

View File

@@ -25,6 +25,7 @@ import org.apache.commons.logging.Log;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.boot.system.ApplicationPid;
import org.springframework.context.ApplicationContext;
import org.springframework.core.log.LogMessage;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StopWatch;
@@ -44,51 +45,48 @@ class StartupInfoLogger {
this.sourceClass = sourceClass;
}
public void logStarting(Log log) {
Assert.notNull(log, "Log must not be null");
if (log.isInfoEnabled()) {
log.info(getStartupMessage());
}
if (log.isDebugEnabled()) {
log.debug(getRunningMessage());
public void logStarting(Log applicationLog) {
Assert.notNull(applicationLog, "Log must not be null");
applicationLog.info(LogMessage.of(this::getStartingMessage));
applicationLog.debug(LogMessage.of(this::getRunningMessage));
}
public void logStarted(Log applicationLog, StopWatch stopWatch) {
if (applicationLog.isInfoEnabled()) {
applicationLog.info(getStartedMessage(stopWatch));
}
}
public void logStarted(Log log, StopWatch stopWatch) {
if (log.isInfoEnabled()) {
log.info(getStartedMessage(stopWatch));
}
}
private String getStartupMessage() {
private CharSequence getStartingMessage() {
StringBuilder message = new StringBuilder();
message.append("Starting ");
message.append(getApplicationName());
message.append(getVersion(this.sourceClass));
message.append(getOn());
message.append(getPid());
message.append(getContext());
return message.toString();
}
private StringBuilder getRunningMessage() {
StringBuilder message = new StringBuilder();
message.append("Running with Spring Boot");
message.append(getVersion(getClass()));
message.append(", Spring");
message.append(getVersion(ApplicationContext.class));
appendApplicationName(message);
appendVersion(message, this.sourceClass);
appendOn(message);
appendPid(message);
appendContext(message);
return message;
}
private StringBuilder getStartedMessage(StopWatch stopWatch) {
private CharSequence getRunningMessage() {
StringBuilder message = new StringBuilder();
message.append("Running with Spring Boot");
appendVersion(message, getClass());
message.append(", Spring");
appendVersion(message, ApplicationContext.class);
return message;
}
private CharSequence getStartedMessage(StopWatch stopWatch) {
StringBuilder message = new StringBuilder();
message.append("Started ");
message.append(getApplicationName());
appendApplicationName(message);
message.append(" in ");
message.append(stopWatch.getTotalTimeSeconds());
message.append(" seconds");
try {
double uptime = ManagementFactory.getRuntimeMXBean().getUptime() / 1000.0;
message.append(" seconds (JVM running for ").append(uptime).append(")");
message.append(" (JVM running for ").append(uptime).append(")");
}
catch (Throwable ex) {
// No JVM time available
@@ -96,56 +94,64 @@ class StartupInfoLogger {
return message;
}
private String getApplicationName() {
return (this.sourceClass != null) ? ClassUtils.getShortName(this.sourceClass)
: "application";
private void appendApplicationName(StringBuilder message) {
String name = (this.sourceClass != null)
? ClassUtils.getShortName(this.sourceClass) : "application";
message.append(name);
}
private String getVersion(Class<?> source) {
return getValue(" v", () -> source.getPackage().getImplementationVersion(), "");
private void appendVersion(StringBuilder message, Class<?> source) {
append(message, "v", () -> source.getPackage().getImplementationVersion());
}
private String getOn() {
return getValue(" on ", () -> InetAddress.getLocalHost().getHostName());
private void appendOn(StringBuilder message) {
append(message, "on ", () -> InetAddress.getLocalHost().getHostName());
}
private String getPid() {
return getValue(" with PID ", () -> new ApplicationPid().toString());
private void appendPid(StringBuilder message) {
append(message, "with PID ", () -> new ApplicationPid());
}
private String getContext() {
String startedBy = getValue("started by ", () -> System.getProperty("user.name"));
String in = getValue("in ", () -> System.getProperty("user.dir"));
private void appendContext(StringBuilder message) {
StringBuilder context = new StringBuilder();
ApplicationHome home = new ApplicationHome(this.sourceClass);
String path = (home.getSource() != null) ? home.getSource().getAbsolutePath()
: "";
if (startedBy == null && path == null) {
return "";
if (home.getSource() != null) {
context.append(home.getSource().getAbsolutePath());
}
if (StringUtils.hasLength(startedBy) && StringUtils.hasLength(path)) {
startedBy = " " + startedBy;
append(context, "started by ", () -> System.getProperty("user.name"));
append(context, "in ", () -> System.getProperty("user.dir"));
if (context.length() > 0) {
message.append(" (");
message.append(context);
message.append(")");
}
if (StringUtils.hasLength(in) && StringUtils.hasLength(startedBy)) {
in = " " + in;
}
return " (" + path + startedBy + in + ")";
}
private String getValue(String prefix, Callable<Object> call) {
return getValue(prefix, call, "");
private void append(StringBuilder message, String prefix, Callable<Object> call) {
append(message, prefix, call, "");
}
private String getValue(String prefix, Callable<Object> call, String defaultValue) {
private void append(StringBuilder message, String prefix, Callable<Object> call,
String defaultValue) {
Object result = callIfPossible(call);
String value = (result != null) ? result.toString() : null;
if (!StringUtils.hasLength(value)) {
value = defaultValue;
}
if (StringUtils.hasLength(value)) {
message.append(message.length() > 0 ? " " : "");
message.append(prefix);
message.append(value);
}
}
private Object callIfPossible(Callable<Object> call) {
try {
Object value = call.call();
if (value != null && StringUtils.hasLength(value.toString())) {
return prefix + value;
}
return call.call();
}
catch (Exception ex) {
// Swallow and continue
return null;
}
return defaultValue;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,8 +18,9 @@ package org.springframework.boot;
import org.apache.commons.logging.Log;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import static org.mockito.ArgumentMatchers.startsWith;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -38,7 +39,10 @@ public class StartUpLoggerTests {
public void sourceClassIncluded() {
given(this.log.isInfoEnabled()).willReturn(true);
new StartupInfoLogger(getClass()).logStarting(this.log);
verify(this.log).info(startsWith("Starting " + getClass().getSimpleName()));
ArgumentCaptor<Object> captor = ArgumentCaptor.forClass(Object.class);
verify(this.log).info(captor.capture());
assertThat(captor.getValue().toString())
.startsWith("Starting " + getClass().getSimpleName());
}
}