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