Commit 1d8d7ccc by Johannes Edmeier

Improve hover status info for down/offline apps

parent 14d8c01b
......@@ -4,10 +4,11 @@
<table class="table cable-condensed">
<tr ng-repeat="detail in $ctrl.details | orderBy:'name'">
<td style="text-transform: capitalize;" ng-bind="detail.name"></td>
<td ng-bind="detail.status " class="status-{{detail.status}}"></td>
<td ng-bind="detail.status" class="status-{{detail.status}}"></td>
</tr>
</table>
<div style="max-width: 400px;" class="alert alert-error" ng-if="$ctrl.statusInfo.details.message">
<div style="max-width: 400px;" class="alert alert-error" ng-if="$ctrl.statusInfo.details.message || $ctrl.statusInfo.details.error">
<b style="word-break: break-all;" ng-if="$ctrl.statusInfo.details.status" ng-bind="$ctrl.statusInfo.details.status + ' ' + $ctrl.statusInfo.details.error"></b>
<b style="word-break: break-all;" ng-if="$ctrl.statusInfo.details.exception" ng-bind="$ctrl.statusInfo.details.exception + ':'"></b><br>
<span ng-bind="$ctrl.statusInfo.details.message"></span>
</div>
......
......@@ -32,7 +32,7 @@ public class StatusInfo implements Serializable {
private final String status;
private final long timestamp;
private final Map<String, ? extends Serializable> details;
private final Map<String, Serializable> details;
protected StatusInfo(String status, long timestamp,
Map<String, ? extends Serializable> details) {
......@@ -87,7 +87,7 @@ public class StatusInfo implements Serializable {
return timestamp;
}
public Map<String, ? extends Serializable> getDetails() {
public Map<String, Serializable> getDetails() {
return details;
}
......
......@@ -100,31 +100,39 @@ public class StatusUpdater implements ApplicationEventPublisherAware {
protected StatusInfo queryStatus(Application application) {
LOGGER.trace("Updating status for {}", application);
try {
ResponseEntity<Map<String, Serializable>> response = applicationOps
.getHealth(application);
if (response.hasBody() && response.getBody().get("status") instanceof String) {
return StatusInfo.valueOf((String) response.getBody().get("status"),
response.getBody());
} else if (response.getStatusCode().is2xxSuccessful()) {
return StatusInfo.ofUp();
} else {
return StatusInfo.ofDown();
}
return convertStatusInfo(applicationOps.getHealth(application));
} catch (Exception ex) {
if ("OFFLINE".equals(application.getStatusInfo().getStatus())) {
LOGGER.debug("Couldn't retrieve status for {}", application, ex);
} else {
LOGGER.info("Couldn't retrieve status for {}", application, ex);
}
return StatusInfo.ofOffline(toDetails(ex));
return convertStatusInfo(ex);
}
}
private StatusInfo convertStatusInfo(ResponseEntity<Map<String, Serializable>> response) {
if (response.hasBody() && response.getBody().get("status") instanceof String) {
return StatusInfo.valueOf((String) response.getBody().get("status"),
response.getBody());
}
if (response.getStatusCode().is2xxSuccessful()) {
return StatusInfo.ofUp();
}
Map<String, Serializable> details = new HashMap<>();
details.put("status", response.getStatusCodeValue());
details.put("error", response.getStatusCode().getReasonPhrase());
if (response.hasBody()) {
details.putAll(response.getBody());
}
return StatusInfo.ofDown(details);
}
protected Map<String, Serializable> toDetails(Exception ex) {
private StatusInfo convertStatusInfo(Exception ex) {
Map<String, Serializable> details = new HashMap<>();
details.put("message", ex.getMessage());
details.put("exception", ex.getClass().getName());
return details;
return StatusInfo.ofOffline(details);
}
public void setStatusLifetime(long statusLifetime) {
......
......@@ -92,8 +92,7 @@ public class StatusUpdaterTest {
}
@Test
public void test_update_noBody() {
// HTTP 200 - UP
public void test_update_up_noBody() {
when(applicationOps.getHealth(any(Application.class)))
.thenReturn(ResponseEntity.ok((Map<String, Serializable>) null));
......@@ -102,14 +101,36 @@ public class StatusUpdaterTest {
assertThat(store.find("id").getStatusInfo().getStatus(), CoreMatchers.is("UP"));
// HTTP != 200 - DOWN
}
@Test
public void test_update_down() {
when(applicationOps.getHealth(any(Application.class)))
.thenReturn(
ResponseEntity.status(503).body(
Collections.<String, Serializable>singletonMap("foo", "bar")));
updater.updateStatus(
Application.create("foo").withId("id").withHealthUrl("health").build());
StatusInfo statusInfo = store.find("id").getStatusInfo();
assertThat(statusInfo.getStatus(), CoreMatchers.is("DOWN"));
assertThat(statusInfo.getDetails(), hasEntry("foo", (Serializable) "bar"));
}
@Test
public void test_update_down_noBody() {
when(applicationOps.getHealth(any(Application.class)))
.thenReturn(ResponseEntity.status(503).body((Map<String, Serializable>) null));
updater.updateStatus(
Application.create("foo").withId("id").withHealthUrl("health").build());
assertThat(store.find("id").getStatusInfo().getStatus(), CoreMatchers.is("DOWN"));
StatusInfo statusInfo = store.find("id").getStatusInfo();
assertThat(statusInfo.getStatus(), CoreMatchers.is("DOWN"));
assertThat(statusInfo.getDetails(), hasEntry("status", (Serializable) 503));
assertThat(statusInfo.getDetails(),
hasEntry("error", (Serializable) "Service Unavailable"));
}
@Test
......@@ -121,7 +142,11 @@ public class StatusUpdaterTest {
.withStatusInfo(StatusInfo.ofUp()).build();
updater.updateStatus(app);
assertThat(store.find("id").getStatusInfo().getStatus(), CoreMatchers.is("OFFLINE"));
StatusInfo statusInfo = store.find("id").getStatusInfo();
assertThat(statusInfo.getStatus(), CoreMatchers.is("OFFLINE"));
assertThat(statusInfo.getDetails(), hasEntry("message", (Serializable) "error"));
assertThat(statusInfo.getDetails(), hasEntry("exception",
(Serializable) "org.springframework.web.client.ResourceAccessException"));
}
@Test
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment