Commit 73911fba by Johannes Edmeier

Fix subsequent logging messages when registering at multiple servers

parent 997ee850
......@@ -19,12 +19,15 @@ import de.codecentric.boot.admin.client.config.ClientProperties;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.LongAdder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
......@@ -34,8 +37,10 @@ import org.springframework.web.client.RestTemplate;
*/
public class ApplicationRegistrator {
private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationRegistrator.class);
private static final ParameterizedTypeReference<Map<String, Object>> RESPONSE_TYPE = new ParameterizedTypeReference<Map<String, Object>>() {
};
private static final HttpHeaders HTTP_HEADERS = createHttpHeaders();
private final AtomicInteger unsuccessfulAttempts = new AtomicInteger(0);
private final ConcurrentHashMap<String, LongAdder> attempts = new ConcurrentHashMap<>();
private final AtomicReference<String> registeredId = new AtomicReference<>();
private final ClientProperties client;
private final RestTemplate template;
......@@ -62,51 +67,60 @@ public class ApplicationRegistrator {
* @return true if successful registration on at least one admin server
*/
public boolean register() {
boolean isRegistrationSuccessful = false;
Application self = createApplication();
boolean isRegistrationSuccessful = false;
for (String adminUrl : client.getAdminUrl()) {
try {
@SuppressWarnings("rawtypes") ResponseEntity<Map> response = template.postForEntity(adminUrl,
new HttpEntity<>(self, HTTP_HEADERS), Map.class);
LongAdder attempt = this.attempts.computeIfAbsent(adminUrl, k -> new LongAdder());
boolean successful = register(self, adminUrl, attempt.intValue() == 0);
if (response.getStatusCode().is2xxSuccessful()) {
if (registeredId.compareAndSet(null, response.getBody().get("id").toString())) {
LOGGER.info("Application registered itself as {}", response.getBody().get("id").toString());
} else {
LOGGER.debug("Application refreshed itself as {}", response.getBody().get("id").toString());
}
if (!successful) {
attempt.increment();
} else {
attempt.reset();
isRegistrationSuccessful = true;
if (client.isRegisterOnce()) {
break;
}
}
}
isRegistrationSuccessful = true;
if (client.isRegisterOnce()) {
break;
}
return isRegistrationSuccessful;
}
protected boolean register(Application self, String adminUrl, boolean firstAttempt) {
try {
ResponseEntity<Map<String, Object>> response = template.exchange(adminUrl, HttpMethod.POST,
new HttpEntity<>(self, HTTP_HEADERS), RESPONSE_TYPE);
if (response.getStatusCode().is2xxSuccessful()) {
if (registeredId.compareAndSet(null, response.getBody().get("id").toString())) {
LOGGER.info("Application registered itself as {}", response.getBody().get("id").toString());
} else {
if (unsuccessfulAttempts.get() == 0) {
LOGGER.warn(
"Application failed to registered itself as {}. Response: {}. Further attempts are logged on DEBUG level",
self, response.toString());
} else {
LOGGER.debug("Application failed to registered itself as {}. Response: {}", self,
response.toString());
}
LOGGER.debug("Application refreshed itself as {}", response.getBody().get("id").toString());
}
} catch (Exception ex) {
if (unsuccessfulAttempts.get() == 0) {
return true;
} else {
if (firstAttempt) {
LOGGER.warn(
"Failed to register application as {} at spring-boot-admin ({}): {}. Further attempts are logged on DEBUG level",
self, client.getAdminUrl(), ex.getMessage());
"Application failed to registered itself as {}. Response: {}. Further attempts are logged on DEBUG level",
self, response.toString());
} else {
LOGGER.debug("Failed to register application as {} at spring-boot-admin ({}): {}", self,
client.getAdminUrl(), ex.getMessage());
LOGGER.debug("Application failed to registered itself as {}. Response: {}", self,
response.toString());
}
}
} catch (Exception ex) {
if (firstAttempt) {
LOGGER.warn(
"Failed to register application as {} at spring-boot-admin ({}): {}. Further attempts are logged on DEBUG level",
self, client.getAdminUrl(), ex.getMessage());
} else {
LOGGER.debug("Failed to register application as {} at spring-boot-admin ({}): {}", self,
client.getAdminUrl(), ex.getMessage());
}
}
if (!isRegistrationSuccessful) {
unsuccessfulAttempts.incrementAndGet();
} else {
unsuccessfulAttempts.set(0);
}
return isRegistrationSuccessful;
return false;
}
public void deregister() {
......
......@@ -167,6 +167,7 @@ public class DefaultApplicationFactory implements ApplicationFactory {
} else {
Map<String, String> metadata = new LinkedHashMap<>();
metadata.put("startup", this.timestamp.format(DateTimeFormatter.ISO_DATE_TIME));
metadata.putAll(instance.getMetadata());
return metadata;
}
}
......
/*
* Copyright 2014-2017 the original author or authors.
* Copyright 2014-2018 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.
......@@ -21,14 +21,17 @@ import java.util.Collections;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import static java.util.Collections.singletonMap;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
......@@ -37,7 +40,8 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class ApplicationRegistratorTest {
private static final ParameterizedTypeReference<Map<String, Object>> RESPONSE_TYPE = new ParameterizedTypeReference<Map<String, Object>>() {
};
private ClientProperties client;
private ApplicationRegistrator registrator;
private RestTemplate restTemplate;
......@@ -64,11 +68,10 @@ public class ApplicationRegistratorTest {
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
}
@SuppressWarnings("rawtypes")
@Test
public void register_successful() {
when(restTemplate.postForEntity(isA(String.class), isA(HttpEntity.class), eq(Map.class))).thenReturn(
new ResponseEntity<>(Collections.singletonMap("id", "-id-"), HttpStatus.CREATED));
when(restTemplate.exchange(isA(String.class), eq(HttpMethod.POST), isA(HttpEntity.class),
eq(RESPONSE_TYPE))).thenReturn(new ResponseEntity<>(singletonMap("id", "-id-"), HttpStatus.CREATED));
assertThat(registrator.register()).isTrue();
......@@ -77,34 +80,33 @@ public class ApplicationRegistratorTest {
.managementUrl("http://localhost:8080/mgmt")
.serviceUrl("http://localhost:8080")
.build();
verify(restTemplate).postForEntity("http://sba:8080/instances", new HttpEntity<>(applicationRef, headers),
Map.class);
verify(restTemplate).exchange(eq("http://sba:8080/instances"), eq(HttpMethod.POST),
eq(new HttpEntity<>(applicationRef, headers)), eq(RESPONSE_TYPE));
}
@Test
public void register_failed() {
when(restTemplate.postForEntity(isA(String.class), isA(HttpEntity.class), eq(Application.class))).thenThrow(
new RestClientException("Error"));
when(restTemplate.exchange(isA(String.class), eq(HttpMethod.POST), isA(HttpEntity.class),
eq(RESPONSE_TYPE))).thenThrow(new RestClientException("Error"));
assertThat(registrator.register()).isFalse();
}
@SuppressWarnings("rawtypes")
@Test
public void register_retry() {
when(restTemplate.postForEntity(isA(String.class), isA(HttpEntity.class), eq(Application.class))).thenThrow(
new RestClientException("Error"));
when(restTemplate.postForEntity(isA(String.class), isA(HttpEntity.class), eq(Map.class))).thenReturn(
new ResponseEntity<>(Collections.singletonMap("id", "-id-"), HttpStatus.CREATED));
when(restTemplate.exchange(isA(String.class), eq(HttpMethod.POST), isA(HttpEntity.class),
eq(RESPONSE_TYPE))).thenThrow(new RestClientException("Error"));
when(restTemplate.exchange(isA(String.class), eq(HttpMethod.POST), isA(HttpEntity.class),
eq(RESPONSE_TYPE))).thenReturn(new ResponseEntity<>(singletonMap("id", "-id-"), HttpStatus.CREATED));
assertThat(registrator.register()).isTrue();
}
@SuppressWarnings("rawtypes")
@Test
public void deregister() {
when(restTemplate.postForEntity(isA(String.class), isA(HttpEntity.class), eq(Map.class))).thenReturn(
new ResponseEntity<>(Collections.singletonMap("id", "-id-"), HttpStatus.CREATED));
when(restTemplate.exchange(isA(String.class), eq(HttpMethod.POST), isA(HttpEntity.class),
eq(RESPONSE_TYPE))).thenReturn(new ResponseEntity<>(singletonMap("id", "-id-"), HttpStatus.CREATED));
registrator.register();
assertThat(registrator.getRegisteredId()).isEqualTo("-id-");
registrator.deregister();
......@@ -113,13 +115,12 @@ public class ApplicationRegistratorTest {
verify(restTemplate).delete("http://sba:8080/instances/-id-");
}
@SuppressWarnings("rawtypes")
@Test
public void register_multiple() {
client.setRegisterOnce(false);
when(restTemplate.postForEntity(isA(String.class), isA(HttpEntity.class), eq(Map.class))).thenReturn(
new ResponseEntity<>(Collections.singletonMap("id", "-id-"), HttpStatus.CREATED));
when(restTemplate.exchange(isA(String.class), eq(HttpMethod.POST), isA(HttpEntity.class),
eq(RESPONSE_TYPE))).thenReturn(new ResponseEntity<>(singletonMap("id", "-id-"), HttpStatus.CREATED));
assertThat(registrator.register()).isTrue();
......@@ -128,22 +129,19 @@ public class ApplicationRegistratorTest {
.managementUrl("http://localhost:8080/mgmt")
.serviceUrl("http://localhost:8080")
.build();
verify(restTemplate).postForEntity("http://sba:8080/instances", new HttpEntity<>(applicationRef, headers),
Map.class);
verify(restTemplate).postForEntity("http://sba2:8080/instances", new HttpEntity<>(applicationRef, headers),
Map.class);
verify(restTemplate).exchange(eq("http://sba:8080/instances"), eq(HttpMethod.POST),
eq(new HttpEntity<>(applicationRef, headers)), eq(RESPONSE_TYPE));
verify(restTemplate).exchange(eq("http://sba2:8080/instances"), eq(HttpMethod.POST),
eq(new HttpEntity<>(applicationRef, headers)), eq(RESPONSE_TYPE));
}
@SuppressWarnings("rawtypes")
@Test
public void register_multiple_one_failure() {
client.setRegisterOnce(false);
when(restTemplate.postForEntity(isA(String.class), isA(HttpEntity.class), eq(Map.class))).thenReturn(
new ResponseEntity<>(Collections.singletonMap("id", "-id-"), HttpStatus.CREATED))
.thenThrow(
new RestClientException(
"Error"));
when(restTemplate.exchange(isA(String.class), eq(HttpMethod.POST), isA(HttpEntity.class),
eq(RESPONSE_TYPE))).thenReturn(new ResponseEntity<>(singletonMap("id", "-id-"), HttpStatus.CREATED))
.thenThrow(new RestClientException("Error"));
assertThat(registrator.register()).isTrue();
......@@ -152,18 +150,18 @@ public class ApplicationRegistratorTest {
.managementUrl("http://localhost:8080/mgmt")
.serviceUrl("http://localhost:8080")
.build();
verify(restTemplate).postForEntity("http://sba:8080/instances", new HttpEntity<>(applicationRef, headers),
Map.class);
verify(restTemplate).postForEntity("http://sba2:8080/instances", new HttpEntity<>(applicationRef, headers),
Map.class);
verify(restTemplate).exchange(eq("http://sba:8080/instances"), eq(HttpMethod.POST),
eq(new HttpEntity<>(applicationRef, headers)), eq(RESPONSE_TYPE));
verify(restTemplate).exchange(eq("http://sba2:8080/instances"), eq(HttpMethod.POST),
eq(new HttpEntity<>(applicationRef, headers)), eq(RESPONSE_TYPE));
}
@Test
public void register_multiple_all_failures() {
client.setRegisterOnce(false);
when(restTemplate.postForEntity(isA(String.class), isA(HttpEntity.class), eq(Map.class))).thenThrow(
new RestClientException("Error"));
when(restTemplate.exchange(isA(String.class), eq(HttpMethod.POST), isA(HttpEntity.class),
eq(RESPONSE_TYPE))).thenThrow(new RestClientException("Error"));
assertThat(registrator.register()).isFalse();
}
......
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