Skip to content

Commit

Permalink
Merge pull request #557 from xstefank/filters
Browse files Browse the repository at this point in the history
Implement health filters feature
  • Loading branch information
xstefank authored Aug 28, 2024
2 parents 86cc7eb + 90ec932 commit 4c02d0c
Show file tree
Hide file tree
Showing 6 changed files with 195 additions and 2 deletions.
4 changes: 4 additions & 0 deletions api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
<artifactId>jakarta.enterprise.cdi-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.json</groupId>
<artifactId>jakarta.json-api</artifactId>
</dependency>
<dependency>
<groupId>io.smallrye.reactive</groupId>
<artifactId>mutiny</artifactId>
Expand Down
22 changes: 22 additions & 0 deletions api/src/main/java/io/smallrye/health/api/HealthContentFilter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.smallrye.health.api;

import jakarta.json.JsonObject;

import io.smallrye.common.annotation.Experimental;

/**
* Implementations of this interface are invoked prior the health report to filter(remove, add, or modify) fields in the
* returned JSON object. Individual implementations are collected through CDI so they must be annotated with some of the
* bean-defining annotations (e.g., {@link jakarta.enterprise.context.ApplicationScoped}).
*/
@FunctionalInterface
@Experimental("Health content filtering")
public interface HealthContentFilter {

/**
* Filters (removes, adds, or modifies) fields in the provided {@link JsonObject}.
*
* @param payload An object representing the payload to be reported to the caller.
*/
JsonObject filter(JsonObject payload);
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.context.Dependent;
import jakarta.enterprise.inject.Any;
import jakarta.enterprise.inject.Instance;
import jakarta.enterprise.inject.spi.Bean;
Expand All @@ -45,6 +46,7 @@
import io.smallrye.common.annotation.Experimental;
import io.smallrye.config.SmallRyeConfig;
import io.smallrye.health.api.AsyncHealthCheck;
import io.smallrye.health.api.HealthContentFilter;
import io.smallrye.health.api.HealthGroup;
import io.smallrye.health.api.HealthType;
import io.smallrye.health.api.Wellness;
Expand Down Expand Up @@ -100,6 +102,10 @@ public class SmallRyeHealthReporter {
@Any
Instance<AsyncHealthCheck> allAsyncHealthChecks;

@Inject
@Any
Instance<HealthContentFilter> healthContentFilters;

@Inject
BeanManager beanManager;

Expand Down Expand Up @@ -210,15 +216,28 @@ private void initUnis(List<Uni<HealthCheckResponse>> list, Iterable<HealthCheck>
}

public void reportHealth(OutputStream out, SmallRyeHealth health) {
JsonObject payload = health.getPayload();
if (health.isDown() && HealthLogging.logger.isInfoEnabled()) {
// Log reason, as not reported by container orchestrators, yet container may get killed.
HealthLogging.logger.healthDownStatus(health.getPayload().toString());
HealthLogging.logger.healthDownStatus(payload.toString());
}

if (healthContentFilters != null) {
for (Instance.Handle<HealthContentFilter> handle : healthContentFilters.handles()) {
try {
payload = handle.get().filter(payload);
} finally {
if (handle.getBean().getScope().equals(Dependent.class)) {
handle.destroy();
}
}
}
}

JsonWriterFactory factory = JSON_PROVIDER.createWriterFactory(JSON_CONFIG);
JsonWriter writer = factory.createWriter(out);

writer.writeObject(health.getPayload());
writer.writeObject(payload);
writer.close();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package io.smallrye.health.deployment;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.json.Json;
import jakarta.json.JsonObject;

import io.smallrye.health.api.HealthContentFilter;

@ApplicationScoped
public class TestHealthContentFilter implements HealthContentFilter {

@Override
public JsonObject filter(JsonObject payload) {
return Json.createObjectBuilder(payload)
.add("foo", "bar")
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package io.smallrye.health.deployment;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.json.Json;
import jakarta.json.JsonObject;

import io.smallrye.health.api.HealthContentFilter;

@ApplicationScoped
public class TestHealthContentFilter2 implements HealthContentFilter {

@Override
public JsonObject filter(JsonObject payload) {
return Json.createObjectBuilder(payload)
.add("foo2", "bar2")
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
* Copyright (c) 2020 Contributors to the Eclipse Foundation
*
* See the NOTICES file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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
*
* http://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.
*
* SPDX-License-Identifier: Apache-2.0
*
*/

package io.smallrye.health.test;

import jakarta.json.JsonArray;
import jakarta.json.JsonObject;

import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.OperateOnDeployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.shrinkwrap.api.Archive;
import org.testng.Assert;
import org.testng.annotations.Test;

import io.smallrye.health.deployment.SuccessLiveness;
import io.smallrye.health.deployment.TestHealthContentFilter;
import io.smallrye.health.deployment.TestHealthContentFilter2;

@RunAsClient
public class HealthContentFilterTest extends TCKBase {

private static final String DEPLOYMENT_1 = "deployment1";
private static final String DEPLOYMENT_2 = "deployment2";

@Deployment(name = DEPLOYMENT_1)
public static Archive getDeployment() {
return DeploymentUtils.createWarFileWithClasses(HealthContentFilterTest.class.getSimpleName(),
TestHealthContentFilter.class, SuccessLiveness.class, TCKBase.class);
}

@Deployment(name = DEPLOYMENT_2)
public static Archive getDeployment2() {
return DeploymentUtils.createWarFileWithClasses(HealthContentFilterTest.class.getSimpleName() + "2",
TestHealthContentFilter.class, TestHealthContentFilter2.class, SuccessLiveness.class, TCKBase.class);
}

/**
* Verifies that the filter implementations process the payload before its returned to the caller.
*/
@Test
@OperateOnDeployment(DEPLOYMENT_1)
public void testHealthContentFilterFiltersReturnedJson() {
Response response = getUrlHealthContents();

// status code
Assert.assertEquals(response.getStatus(), 200);

JsonObject json = readJson(response);

// response size
JsonArray checks = json.getJsonArray("checks");
Assert.assertEquals(checks.size(), 1, "Expected one check response");

JsonObject checkJson = checks.getJsonObject(0);
Assert.assertEquals(SuccessLiveness.class.getName(), checkJson.getString("name"));
verifySuccessStatus(checkJson);

assertOverallSuccess(json);

System.out.println(json);
Assert.assertEquals("bar", json.getString("foo"));
}

/**
* Verifies that the filter implementations process the payload before its returned to the caller.
*/
@Test
@OperateOnDeployment(DEPLOYMENT_2)
public void testMultipleHealthContentFiltersFilterReturnedJson() {
Response response = getUrlHealthContents();

// status code
Assert.assertEquals(response.getStatus(), 200);

JsonObject json = readJson(response);

// response size
JsonArray checks = json.getJsonArray("checks");
Assert.assertEquals(checks.size(), 1, "Expected one check response");

JsonObject checkJson = checks.getJsonObject(0);
Assert.assertEquals(SuccessLiveness.class.getName(), checkJson.getString("name"));
verifySuccessStatus(checkJson);

assertOverallSuccess(json);

System.out.println(json);
Assert.assertEquals("bar", json.getString("foo"));
Assert.assertEquals("bar2", json.getString("foo2"));
}

}

0 comments on commit 4c02d0c

Please sign in to comment.