Skip to content

Commit 90883e4

Browse files
committed
[health] bootstrap HealthObserver from agent to API
1 parent 9e452d2 commit 90883e4

5 files changed

Lines changed: 165 additions & 1 deletion

File tree

logstash-core/lib/logstash/agent.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ class LogStash::Agent
4040
attr_reader :metric, :name, :settings, :dispatcher, :ephemeral_id, :pipeline_bus
4141
attr_accessor :logger
4242

43+
attr_reader :health_observer
44+
4345
# initialize method for LogStash::Agent
4446
# @param params [Hash] potential parameters are:
4547
# :name [String] - identifier for the agent
@@ -51,6 +53,9 @@ def initialize(settings = LogStash::SETTINGS, source_loader = nil)
5153
@auto_reload = setting("config.reload.automatic")
5254
@ephemeral_id = SecureRandom.uuid
5355

56+
java_import("org.logstash.health.HealthObserver")
57+
@health_observer = HealthObserver.new
58+
5459
# Mutex to synchronize in the exclusive method
5560
# Initial usage for the Ruby pipeline initialization which is not thread safe
5661
@webserver_control_lock = Mutex.new

logstash-core/lib/logstash/api/commands/default_metadata.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def all
2828
:id => service.agent.id,
2929
:name => service.agent.name,
3030
:ephemeral_id => service.agent.ephemeral_id,
31-
:status => "green", # This is hard-coded to mirror x-pack behavior
31+
:status => service.agent.health_observer.status,
3232
:snapshot => ::BUILD_INFO["build_snapshot"],
3333
:pipeline => {
3434
:workers => LogStash::SETTINGS.get("pipeline.workers"),
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.logstash.health;
2+
3+
import com.google.common.collect.Iterables;
4+
5+
import java.util.EnumSet;
6+
7+
public class HealthObserver {
8+
public final Status getStatus() {
9+
// INTERNAL-ONLY Proof-of-concept to show flow-through to API results
10+
switch (System.getProperty("logstash.apiStatus", "green")) {
11+
case "green": return Status.GREEN;
12+
case "yellow": return Status.YELLOW;
13+
case "red": return Status.RED;
14+
case "random":
15+
final EnumSet<Status> statuses = EnumSet.allOf(Status.class);
16+
return Iterables.get(statuses, new java.util.Random().nextInt(statuses.size()));
17+
default:
18+
return Status.UNKNOWN;
19+
}
20+
}
21+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package org.logstash.health;
2+
3+
import com.fasterxml.jackson.annotation.JsonValue;
4+
5+
public enum Status {
6+
UNKNOWN,
7+
GREEN,
8+
YELLOW,
9+
RED,
10+
;
11+
12+
private final String externalValue = name().toLowerCase();
13+
14+
@JsonValue
15+
public String externalValue() {
16+
return externalValue;
17+
}
18+
19+
/**
20+
* Combine this status with another status.
21+
* This method is commutative.
22+
* @param status the other status
23+
* @return the more-degraded of the two statuses.
24+
*/
25+
public Status reduce(Status status) {
26+
if (compareTo(status) >= 0) {
27+
return this;
28+
} else {
29+
return status;
30+
}
31+
}
32+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package org.logstash.health;
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import org.junit.Test;
5+
import org.junit.experimental.runners.Enclosed;
6+
import org.junit.runner.RunWith;
7+
import org.junit.runners.Parameterized;
8+
import org.junit.runners.Parameterized.Parameter;
9+
import org.junit.runners.Parameterized.Parameters;
10+
11+
import java.util.ArrayList;
12+
import java.util.Collection;
13+
import java.util.Collections;
14+
import java.util.EnumSet;
15+
import java.util.List;
16+
import java.util.stream.Collectors;
17+
18+
import static com.google.common.collect.Collections2.orderedPermutations;
19+
import static org.hamcrest.CoreMatchers.is;
20+
import static org.hamcrest.CoreMatchers.equalTo;
21+
import static org.hamcrest.MatcherAssert.assertThat;
22+
import static org.logstash.health.Status.*;
23+
24+
@RunWith(Enclosed.class)
25+
public class StatusTest {
26+
27+
public static class Tests {
28+
@Test
29+
public void testReduceUnknown() {
30+
assertThat(UNKNOWN.reduce(UNKNOWN), is(UNKNOWN));
31+
assertThat(UNKNOWN.reduce(GREEN), is(GREEN));
32+
assertThat(UNKNOWN.reduce(YELLOW), is(YELLOW));
33+
assertThat(UNKNOWN.reduce(RED), is(RED));
34+
}
35+
36+
@Test
37+
public void testReduceGreen() {
38+
assertThat(GREEN.reduce(UNKNOWN), is(GREEN));
39+
assertThat(GREEN.reduce(GREEN), is(GREEN));
40+
assertThat(GREEN.reduce(YELLOW), is(YELLOW));
41+
assertThat(GREEN.reduce(RED), is(RED));
42+
}
43+
44+
@Test
45+
public void testReduceYellow() {
46+
assertThat(YELLOW.reduce(UNKNOWN), is(YELLOW));
47+
assertThat(YELLOW.reduce(GREEN), is(YELLOW));
48+
assertThat(YELLOW.reduce(YELLOW), is(YELLOW));
49+
assertThat(YELLOW.reduce(RED), is(RED));
50+
}
51+
52+
@Test
53+
public void testReduceRed() {
54+
assertThat(RED.reduce(UNKNOWN), is(RED));
55+
assertThat(RED.reduce(GREEN), is(RED));
56+
assertThat(RED.reduce(YELLOW), is(RED));
57+
assertThat(RED.reduce(RED), is(RED));
58+
}
59+
}
60+
61+
@RunWith(Parameterized.class)
62+
public static class JacksonSerialization {
63+
@Parameters(name = "{0}")
64+
public static Iterable<?> data() {
65+
return EnumSet.allOf(Status.class);
66+
}
67+
68+
@Parameter
69+
public Status status;
70+
71+
private final ObjectMapper mapper = new ObjectMapper();
72+
73+
@Test
74+
public void testSerialization() throws Exception {
75+
assertThat(mapper.writeValueAsString(status), is(equalTo('"' + status.name().toLowerCase() + '"')));
76+
}
77+
}
78+
79+
@RunWith(Parameterized.class)
80+
public static class ReduceCommutativeSpecification {
81+
@Parameters(name = "{0}<=>{1}")
82+
public static Collection<Object[]> data() {
83+
return getCombinations(EnumSet.allOf(Status.class), 2);
84+
}
85+
86+
@Parameter(0)
87+
public Status statusA;
88+
@Parameter(1)
89+
public Status statusB;
90+
91+
@Test
92+
public void testReduceCommutative() {
93+
assertThat(statusA.reduce(statusB), is(statusB.reduce(statusA)));
94+
}
95+
96+
private static <T extends Comparable<T>> List<Object[]> getCombinations(Collection<T> source, int count) {
97+
return orderedPermutations(source).stream()
98+
.map((l) -> l.subList(0, count))
99+
.map(ArrayList::new).peek(Collections::sort)
100+
.collect(Collectors.toSet())
101+
.stream()
102+
.map(List::toArray)
103+
.collect(Collectors.toList());
104+
}
105+
}
106+
}

0 commit comments

Comments
 (0)