Skip to content

Commit 4233310

Browse files
authored
Add health indicator impact to HealthPeriodicLogger (#122390)
1 parent 1ca04b7 commit 4233310

File tree

4 files changed

+76
-14
lines changed

4 files changed

+76
-14
lines changed

docs/changelog/122390.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 122390
2+
summary: Add health indicator impact to `HealthPeriodicLogger`
3+
area: Health
4+
type: enhancement
5+
issues: []

server/src/main/java/org/elasticsearch/health/HealthPeriodicLogger.java

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,10 @@
5252
import static org.elasticsearch.health.HealthStatus.RED;
5353

5454
/**
55-
* This class periodically logs the results of the Health API to the standard Elasticsearch server log file. It a lifecycle
56-
* aware component because it health depends on other lifecycle aware components. This means:
55+
* This class periodically logs the results of the Health API to the standard Elasticsearch server log file. It is a lifecycle
56+
* aware component because it depends on other lifecycle aware components. This means:
5757
* - We do not schedule any jobs until the lifecycle state is STARTED
58-
* - When the lifecycle state becomes STOPPED, do not schedule any more runs, but we do let the current one finish
58+
* - When the lifecycle state becomes STOPPED, we do not schedule any more runs, but we do let the current one finish
5959
* - When the lifecycle state becomes CLOSED, we will interrupt the current run as well.
6060
*/
6161
public class HealthPeriodicLogger extends AbstractLifecycleComponent implements ClusterStateListener, SchedulerEngine.Listener {
@@ -361,11 +361,24 @@ static Map<String, Object> convertToLoggedFields(List<HealthIndicatorResult> ind
361361
String.format(Locale.ROOT, "%s.%s.status", HEALTH_FIELD_PREFIX, indicatorResult.name()),
362362
indicatorResult.status().xContentValue()
363363
);
364-
if (GREEN.equals(indicatorResult.status()) == false && indicatorResult.details() != null) {
365-
result.put(
366-
String.format(Locale.ROOT, "%s.%s.details", HEALTH_FIELD_PREFIX, indicatorResult.name()),
367-
Strings.toString(indicatorResult.details())
368-
);
364+
if (GREEN.equals(indicatorResult.status()) == false) {
365+
// indicator details
366+
if (indicatorResult.details() != null) {
367+
result.put(
368+
String.format(Locale.ROOT, "%s.%s.details", HEALTH_FIELD_PREFIX, indicatorResult.name()),
369+
Strings.toString(indicatorResult.details())
370+
);
371+
}
372+
// indicator impact
373+
if (indicatorResult.impacts() != null) {
374+
indicatorResult.impacts()
375+
.forEach(
376+
impact -> result.put(
377+
String.format(Locale.ROOT, "%s.%s.%s.impacted", HEALTH_FIELD_PREFIX, indicatorResult.name(), impact.id()),
378+
true
379+
)
380+
);
381+
}
369382
}
370383
});
371384

server/src/main/java/org/elasticsearch/health/node/DiskHealthIndicatorService.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ public class DiskHealthIndicatorService implements HealthIndicatorService {
6666

6767
private static final Logger logger = LogManager.getLogger(DiskHealthIndicatorService.class);
6868

69-
private static final String IMPACT_INGEST_UNAVAILABLE_ID = "ingest_capability_unavailable";
69+
// VisibleForTesting
70+
public static final String IMPACT_INGEST_UNAVAILABLE_ID = "ingest_capability_unavailable";
7071
private static final String IMPACT_INGEST_AT_RISK_ID = "ingest_capability_at_risk";
7172
private static final String IMPACT_CLUSTER_STABILITY_AT_RISK_ID = "cluster_stability_at_risk";
7273
private static final String IMPACT_CLUSTER_FUNCTIONALITY_UNAVAILABLE_ID = "cluster_functionality_unavailable";

server/src/test/java/org/elasticsearch/health/HealthPeriodicLoggerTests.java

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.elasticsearch.cluster.node.DiscoveryNode;
2020
import org.elasticsearch.cluster.node.DiscoveryNodeRole;
2121
import org.elasticsearch.cluster.node.DiscoveryNodeUtils;
22+
import org.elasticsearch.cluster.routing.allocation.shards.ShardsAvailabilityHealthIndicatorService;
2223
import org.elasticsearch.cluster.routing.allocation.shards.ShardsAvailabilityHealthIndicatorServiceTests;
2324
import org.elasticsearch.cluster.service.ClusterService;
2425
import org.elasticsearch.common.Strings;
@@ -28,6 +29,7 @@
2829
import org.elasticsearch.common.settings.ClusterSettings;
2930
import org.elasticsearch.common.settings.Settings;
3031
import org.elasticsearch.core.TimeValue;
32+
import org.elasticsearch.health.node.DiskHealthIndicatorService;
3133
import org.elasticsearch.telemetry.TelemetryProvider;
3234
import org.elasticsearch.telemetry.metric.LongGaugeMetric;
3335
import org.elasticsearch.telemetry.metric.MeterRegistry;
@@ -51,9 +53,12 @@
5153
import java.util.function.BiConsumer;
5254
import java.util.function.Consumer;
5355

56+
import static org.elasticsearch.cluster.routing.allocation.shards.ShardsAvailabilityHealthIndicatorService.PRIMARY_UNASSIGNED_IMPACT_ID;
57+
import static org.elasticsearch.cluster.routing.allocation.shards.ShardsAvailabilityHealthIndicatorService.REPLICA_UNASSIGNED_IMPACT_ID;
5458
import static org.elasticsearch.health.HealthStatus.GREEN;
5559
import static org.elasticsearch.health.HealthStatus.RED;
5660
import static org.elasticsearch.health.HealthStatus.YELLOW;
61+
import static org.elasticsearch.health.node.DiskHealthIndicatorService.IMPACT_INGEST_UNAVAILABLE_ID;
5762
import static org.elasticsearch.test.ClusterServiceUtils.createClusterService;
5863
import static org.hamcrest.Matchers.equalTo;
5964
import static org.mockito.ArgumentMatchers.any;
@@ -125,9 +130,9 @@ public void testConvertToLoggedFields() {
125130

126131
Map<String, Object> loggerResults = HealthPeriodicLogger.convertToLoggedFields(results);
127132

128-
// verify that the number of fields is the number of indicators + 4
129-
// (for overall and for message, plus details for the two yellow indicators)
130-
assertThat(loggerResults.size(), equalTo(results.size() + 4));
133+
// verify that the number of fields is the number of indicators + 7
134+
// (for overall and for message, plus details for the two yellow indicators, plus three impact)
135+
assertThat(loggerResults.size(), equalTo(results.size() + 7));
131136

132137
// test indicator status
133138
assertThat(loggerResults.get(makeHealthStatusString("master_is_stable")), equalTo("green"));
@@ -165,6 +170,17 @@ public void testConvertToLoggedFields() {
165170
equalTo(String.format(Locale.ROOT, "health=%s [disk,shards_availability]", overallStatus.xContentValue()))
166171
);
167172

173+
// test impact
174+
assertThat(loggerResults.get(makeHealthImpactString(DiskHealthIndicatorService.NAME, IMPACT_INGEST_UNAVAILABLE_ID)), equalTo(true));
175+
assertThat(
176+
loggerResults.get(makeHealthImpactString(ShardsAvailabilityHealthIndicatorService.NAME, PRIMARY_UNASSIGNED_IMPACT_ID)),
177+
equalTo(true)
178+
);
179+
assertThat(
180+
loggerResults.get(makeHealthImpactString(ShardsAvailabilityHealthIndicatorService.NAME, REPLICA_UNASSIGNED_IMPACT_ID)),
181+
equalTo(true)
182+
);
183+
168184
// test empty results
169185
{
170186
List<HealthIndicatorResult> empty = new ArrayList<>();
@@ -793,15 +809,38 @@ private List<HealthIndicatorResult> getTestIndicatorResults() {
793809
1
794810
)
795811
),
796-
null,
812+
List.of(
813+
new HealthIndicatorImpact(
814+
DiskHealthIndicatorService.NAME,
815+
IMPACT_INGEST_UNAVAILABLE_ID,
816+
2,
817+
"description",
818+
List.of(ImpactArea.INGEST)
819+
)
820+
),
797821
null
798822
);
799823
var shardsAvailable = new HealthIndicatorResult(
800824
"shards_availability",
801825
YELLOW,
802826
null,
803827
new SimpleHealthIndicatorDetails(ShardsAvailabilityHealthIndicatorServiceTests.addDefaults(Map.of())),
804-
null,
828+
List.of(
829+
new HealthIndicatorImpact(
830+
ShardsAvailabilityHealthIndicatorService.NAME,
831+
PRIMARY_UNASSIGNED_IMPACT_ID,
832+
2,
833+
"description",
834+
List.of(ImpactArea.SEARCH)
835+
),
836+
new HealthIndicatorImpact(
837+
ShardsAvailabilityHealthIndicatorService.NAME,
838+
REPLICA_UNASSIGNED_IMPACT_ID,
839+
2,
840+
"description",
841+
List.of(ImpactArea.SEARCH)
842+
)
843+
),
805844
null
806845
);
807846

@@ -846,6 +885,10 @@ private String makeHealthDetailsString(String key) {
846885
return String.format(Locale.ROOT, "%s.%s.details", HealthPeriodicLogger.HEALTH_FIELD_PREFIX, key);
847886
}
848887

888+
private String makeHealthImpactString(String indicatorName, String impact) {
889+
return String.format(Locale.ROOT, "%s.%s.%s.impacted", HealthPeriodicLogger.HEALTH_FIELD_PREFIX, indicatorName, impact);
890+
}
891+
849892
private HealthPeriodicLogger createAndInitHealthPeriodicLogger(
850893
ClusterService clusterService,
851894
HealthService testHealthService,

0 commit comments

Comments
 (0)