Move code from spring-boot-actuator to spring-boot-couchbase
This commit is contained in:
committed by
Phillip Webb
parent
ec0370bc2e
commit
0c55d5beb8
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.couchbase.actuate.health;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.couchbase.client.core.diagnostics.ClusterState;
|
||||
import com.couchbase.client.core.diagnostics.DiagnosticsResult;
|
||||
import com.couchbase.client.core.diagnostics.EndpointDiagnostics;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health.Builder;
|
||||
|
||||
/**
|
||||
* Details of Couchbase's health.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class CouchbaseHealth {
|
||||
|
||||
private final DiagnosticsResult diagnostics;
|
||||
|
||||
CouchbaseHealth(DiagnosticsResult diagnostics) {
|
||||
this.diagnostics = diagnostics;
|
||||
}
|
||||
|
||||
void applyTo(Builder builder) {
|
||||
builder = isCouchbaseUp(this.diagnostics) ? builder.up() : builder.down();
|
||||
builder.withDetail("sdk", this.diagnostics.sdk());
|
||||
builder.withDetail("endpoints",
|
||||
this.diagnostics.endpoints()
|
||||
.values()
|
||||
.stream()
|
||||
.flatMap(Collection::stream)
|
||||
.map(this::describe)
|
||||
.toList());
|
||||
}
|
||||
|
||||
private boolean isCouchbaseUp(DiagnosticsResult diagnostics) {
|
||||
return diagnostics.state() == ClusterState.ONLINE;
|
||||
}
|
||||
|
||||
private Map<String, Object> describe(EndpointDiagnostics endpointHealth) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("id", endpointHealth.id());
|
||||
map.put("lastActivity", endpointHealth.lastActivity());
|
||||
map.put("local", endpointHealth.local());
|
||||
map.put("remote", endpointHealth.remote());
|
||||
map.put("state", endpointHealth.state());
|
||||
map.put("type", endpointHealth.type());
|
||||
return map;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.couchbase.actuate.health;
|
||||
|
||||
import com.couchbase.client.core.diagnostics.DiagnosticsResult;
|
||||
import com.couchbase.client.java.Cluster;
|
||||
|
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link HealthIndicator} for Couchbase.
|
||||
*
|
||||
* @author Eddú Meléndez
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public class CouchbaseHealthIndicator extends AbstractHealthIndicator {
|
||||
|
||||
private final Cluster cluster;
|
||||
|
||||
/**
|
||||
* Create an indicator with the specified {@link Cluster}.
|
||||
* @param cluster the Couchbase Cluster
|
||||
* @since 2.0.6
|
||||
*/
|
||||
public CouchbaseHealthIndicator(Cluster cluster) {
|
||||
super("Couchbase health check failed");
|
||||
Assert.notNull(cluster, "'cluster' must not be null");
|
||||
this.cluster = cluster;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doHealthCheck(Health.Builder builder) throws Exception {
|
||||
DiagnosticsResult diagnostics = this.cluster.diagnostics();
|
||||
new CouchbaseHealth(diagnostics).applyTo(builder);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.couchbase.actuate.health;
|
||||
|
||||
import com.couchbase.client.java.Cluster;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.boot.actuate.health.AbstractReactiveHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
|
||||
|
||||
/**
|
||||
* A {@link ReactiveHealthIndicator} for Couchbase.
|
||||
*
|
||||
* @author Mikalai Lushchytski
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public class CouchbaseReactiveHealthIndicator extends AbstractReactiveHealthIndicator {
|
||||
|
||||
private final Cluster cluster;
|
||||
|
||||
/**
|
||||
* Create a new {@link CouchbaseReactiveHealthIndicator} instance.
|
||||
* @param cluster the Couchbase cluster
|
||||
*/
|
||||
public CouchbaseReactiveHealthIndicator(Cluster cluster) {
|
||||
super("Couchbase health check failed");
|
||||
this.cluster = cluster;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Mono<Health> doHealthCheck(Health.Builder builder) {
|
||||
return this.cluster.reactive().diagnostics().map((diagnostics) -> {
|
||||
new CouchbaseHealth(diagnostics).applyTo(builder);
|
||||
return builder.build();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Health integration for Couchbase.
|
||||
*/
|
||||
package org.springframework.boot.couchbase.actuate.health;
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.couchbase.actuate.health;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.couchbase.client.core.diagnostics.DiagnosticsResult;
|
||||
import com.couchbase.client.core.diagnostics.EndpointDiagnostics;
|
||||
import com.couchbase.client.core.endpoint.CircuitBreaker;
|
||||
import com.couchbase.client.core.endpoint.EndpointState;
|
||||
import com.couchbase.client.core.service.ServiceType;
|
||||
import com.couchbase.client.java.Cluster;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.then;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link CouchbaseHealthIndicator}
|
||||
*
|
||||
* @author Eddú Meléndez
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class CouchbaseHealthIndicatorTests {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void couchbaseClusterIsUp() {
|
||||
Cluster cluster = mock(Cluster.class);
|
||||
CouchbaseHealthIndicator healthIndicator = new CouchbaseHealthIndicator(cluster);
|
||||
Map<ServiceType, List<EndpointDiagnostics>> endpoints = Collections.singletonMap(ServiceType.KV,
|
||||
Collections.singletonList(new EndpointDiagnostics(ServiceType.KV, EndpointState.CONNECTED,
|
||||
CircuitBreaker.State.DISABLED, "127.0.0.1", "127.0.0.1", Optional.empty(), Optional.of(1234L),
|
||||
Optional.of("endpoint-1"), Optional.empty())));
|
||||
|
||||
DiagnosticsResult diagnostics = new DiagnosticsResult(endpoints, "test-sdk", "test-id");
|
||||
given(cluster.diagnostics()).willReturn(diagnostics);
|
||||
Health health = healthIndicator.health();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
assertThat(health.getDetails()).containsEntry("sdk", "test-sdk");
|
||||
assertThat(health.getDetails()).containsKey("endpoints");
|
||||
assertThat((List<Map<String, Object>>) health.getDetails().get("endpoints")).hasSize(1);
|
||||
then(cluster).should().diagnostics();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void couchbaseClusterIsDown() {
|
||||
Cluster cluster = mock(Cluster.class);
|
||||
CouchbaseHealthIndicator healthIndicator = new CouchbaseHealthIndicator(cluster);
|
||||
Map<ServiceType, List<EndpointDiagnostics>> endpoints = Collections.singletonMap(ServiceType.KV,
|
||||
Arrays.asList(
|
||||
new EndpointDiagnostics(ServiceType.KV, EndpointState.CONNECTED, CircuitBreaker.State.DISABLED,
|
||||
"127.0.0.1", "127.0.0.1", Optional.empty(), Optional.of(1234L),
|
||||
Optional.of("endpoint-1"), Optional.empty()),
|
||||
new EndpointDiagnostics(ServiceType.KV, EndpointState.CONNECTING, CircuitBreaker.State.DISABLED,
|
||||
"127.0.0.1", "127.0.0.1", Optional.empty(), Optional.of(1234L),
|
||||
Optional.of("endpoint-2"), Optional.empty())));
|
||||
DiagnosticsResult diagnostics = new DiagnosticsResult(endpoints, "test-sdk", "test-id");
|
||||
given(cluster.diagnostics()).willReturn(diagnostics);
|
||||
Health health = healthIndicator.health();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
|
||||
assertThat(health.getDetails()).containsEntry("sdk", "test-sdk");
|
||||
assertThat(health.getDetails()).containsKey("endpoints");
|
||||
assertThat((List<Map<String, Object>>) health.getDetails().get("endpoints")).hasSize(2);
|
||||
then(cluster).should().diagnostics();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.couchbase.actuate.health;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.couchbase.client.core.diagnostics.DiagnosticsResult;
|
||||
import com.couchbase.client.core.diagnostics.EndpointDiagnostics;
|
||||
import com.couchbase.client.core.endpoint.CircuitBreaker;
|
||||
import com.couchbase.client.core.endpoint.EndpointState;
|
||||
import com.couchbase.client.core.service.ServiceType;
|
||||
import com.couchbase.client.java.Cluster;
|
||||
import com.couchbase.client.java.ReactiveCluster;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.then;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link CouchbaseReactiveHealthIndicator}.
|
||||
*/
|
||||
class CouchbaseReactiveHealthIndicatorTests {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void couchbaseClusterIsUp() {
|
||||
Cluster cluster = mock(Cluster.class);
|
||||
CouchbaseReactiveHealthIndicator healthIndicator = new CouchbaseReactiveHealthIndicator(cluster);
|
||||
Map<ServiceType, List<EndpointDiagnostics>> endpoints = Collections.singletonMap(ServiceType.KV,
|
||||
Collections.singletonList(new EndpointDiagnostics(ServiceType.KV, EndpointState.CONNECTED,
|
||||
CircuitBreaker.State.DISABLED, "127.0.0.1", "127.0.0.1", Optional.empty(), Optional.of(1234L),
|
||||
Optional.of("endpoint-1"), Optional.empty())));
|
||||
DiagnosticsResult diagnostics = new DiagnosticsResult(endpoints, "test-sdk", "test-id");
|
||||
ReactiveCluster reactiveCluster = mock(ReactiveCluster.class);
|
||||
given(reactiveCluster.diagnostics()).willReturn(Mono.just(diagnostics));
|
||||
given(cluster.reactive()).willReturn(reactiveCluster);
|
||||
Health health = healthIndicator.health().block(Duration.ofSeconds(30));
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
assertThat(health.getDetails()).containsEntry("sdk", "test-sdk");
|
||||
assertThat(health.getDetails()).containsKey("endpoints");
|
||||
assertThat((List<Map<String, Object>>) health.getDetails().get("endpoints")).hasSize(1);
|
||||
then(reactiveCluster).should().diagnostics();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void couchbaseClusterIsDown() {
|
||||
Cluster cluster = mock(Cluster.class);
|
||||
CouchbaseReactiveHealthIndicator healthIndicator = new CouchbaseReactiveHealthIndicator(cluster);
|
||||
Map<ServiceType, List<EndpointDiagnostics>> endpoints = Collections.singletonMap(ServiceType.KV,
|
||||
Arrays.asList(
|
||||
new EndpointDiagnostics(ServiceType.KV, EndpointState.CONNECTED, CircuitBreaker.State.DISABLED,
|
||||
"127.0.0.1", "127.0.0.1", Optional.empty(), Optional.of(1234L),
|
||||
Optional.of("endpoint-1"), Optional.empty()),
|
||||
new EndpointDiagnostics(ServiceType.KV, EndpointState.CONNECTING, CircuitBreaker.State.DISABLED,
|
||||
"127.0.0.1", "127.0.0.1", Optional.empty(), Optional.of(1234L),
|
||||
Optional.of("endpoint-2"), Optional.empty())));
|
||||
DiagnosticsResult diagnostics = new DiagnosticsResult(endpoints, "test-sdk", "test-id");
|
||||
ReactiveCluster reactiveCluster = mock(ReactiveCluster.class);
|
||||
given(reactiveCluster.diagnostics()).willReturn(Mono.just(diagnostics));
|
||||
given(cluster.reactive()).willReturn(reactiveCluster);
|
||||
Health health = healthIndicator.health().block(Duration.ofSeconds(30));
|
||||
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
|
||||
assertThat(health.getDetails()).containsEntry("sdk", "test-sdk");
|
||||
assertThat(health.getDetails()).containsKey("endpoints");
|
||||
assertThat((List<Map<String, Object>>) health.getDetails().get("endpoints")).hasSize(2);
|
||||
then(reactiveCluster).should().diagnostics();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user