Skip to content

Commit 523cb23

Browse files
authored
Add ingest info to Cluster Stats (#48485)
This commit enhances the ClusterStatsNodes response to include global processor usage stats on a per-processor basis. example output: ``` ... "processor_stats": { "gsub": { "count": 0, "failed": 0 "current": 0 "time_in_millis": 0 }, "script": { "count": 0, "failed": 0 "current": 0, "time_in_millis": 0 } } ... ``` The purpose for this enhancement is to make it easier to collect stats on how specific processors are being used across the cluster beyond the current per-node usage statistics that currently exist in node stats. Closes #46146.
1 parent 4b89171 commit 523cb23

File tree

9 files changed

+157
-12
lines changed

9 files changed

+157
-12
lines changed

docs/reference/cluster/stats.asciidoc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,12 @@ The API returns the following response:
227227
},
228228
...
229229
],
230+
"ingest": {
231+
"number_of_pipelines" : 1,
232+
"processor_stats": {
233+
...
234+
}
235+
},
230236
"network_types": {
231237
...
232238
},
@@ -244,6 +250,7 @@ The API returns the following response:
244250
// TESTRESPONSE[s/"plugins": \[[^\]]*\]/"plugins": $body.$_path/]
245251
// TESTRESPONSE[s/"network_types": \{[^\}]*\}/"network_types": $body.$_path/]
246252
// TESTRESPONSE[s/"discovery_types": \{[^\}]*\}/"discovery_types": $body.$_path/]
253+
// TESTRESPONSE[s/"processor_stats": \{[^\}]*\}/"processor_stats": $body.$_path/]
247254
// TESTRESPONSE[s/"count": \{[^\}]*\}/"count": $body.$_path/]
248255
// TESTRESPONSE[s/"packaging_types": \[[^\]]*\]/"packaging_types": $body.$_path/]
249256
// TESTRESPONSE[s/: true|false/: $body.$_path/]

server/src/main/java/org/elasticsearch/action/admin/cluster/stats/ClusterStatsNodes.java

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.elasticsearch.common.xcontent.ToXContentFragment;
3737
import org.elasticsearch.common.xcontent.XContentBuilder;
3838
import org.elasticsearch.discovery.DiscoveryModule;
39+
import org.elasticsearch.ingest.IngestStats;
3940
import org.elasticsearch.monitor.fs.FsInfo;
4041
import org.elasticsearch.monitor.jvm.JvmInfo;
4142
import org.elasticsearch.plugins.PluginInfo;
@@ -49,7 +50,9 @@
4950
import java.util.List;
5051
import java.util.Map;
5152
import java.util.Set;
53+
import java.util.SortedMap;
5254
import java.util.TreeMap;
55+
import java.util.concurrent.TimeUnit;
5356
import java.util.concurrent.atomic.AtomicInteger;
5457

5558
public class ClusterStatsNodes implements ToXContentFragment {
@@ -64,6 +67,7 @@ public class ClusterStatsNodes implements ToXContentFragment {
6467
private final NetworkTypes networkTypes;
6568
private final DiscoveryTypes discoveryTypes;
6669
private final PackagingTypes packagingTypes;
70+
private final IngestStats ingestStats;
6771

6872
ClusterStatsNodes(List<ClusterStatsNodeResponse> nodeResponses) {
6973
this.versions = new HashSet<>();
@@ -97,6 +101,7 @@ public class ClusterStatsNodes implements ToXContentFragment {
97101
this.networkTypes = new NetworkTypes(nodeInfos);
98102
this.discoveryTypes = new DiscoveryTypes(nodeInfos);
99103
this.packagingTypes = new PackagingTypes(nodeInfos);
104+
this.ingestStats = new IngestStats(nodeStats);
100105
}
101106

102107
public Counts getCounts() {
@@ -178,6 +183,9 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
178183
discoveryTypes.toXContent(builder, params);
179184

180185
packagingTypes.toXContent(builder, params);
186+
187+
ingestStats.toXContent(builder, params);
188+
181189
return builder;
182190
}
183191

@@ -690,4 +698,68 @@ public XContentBuilder toXContent(final XContentBuilder builder, final Params pa
690698

691699
}
692700

701+
static class IngestStats implements ToXContentFragment {
702+
703+
final int pipelineCount;
704+
final SortedMap<String, long[]> stats;
705+
706+
IngestStats(final List<NodeStats> nodeStats) {
707+
Set<String> pipelineIds = new HashSet<>();
708+
SortedMap<String, long[]> stats = new TreeMap<>();
709+
for (NodeStats nodeStat : nodeStats) {
710+
if (nodeStat.getIngestStats() != null) {
711+
for (Map.Entry<String,
712+
List<org.elasticsearch.ingest.IngestStats.ProcessorStat>> processorStats : nodeStat.getIngestStats()
713+
.getProcessorStats().entrySet()) {
714+
pipelineIds.add(processorStats.getKey());
715+
for (org.elasticsearch.ingest.IngestStats.ProcessorStat stat : processorStats.getValue()) {
716+
stats.compute(stat.getType(), (k, v) -> {
717+
org.elasticsearch.ingest.IngestStats.Stats nodeIngestStats = stat.getStats();
718+
if (v == null) {
719+
return new long[] {
720+
nodeIngestStats.getIngestCount(),
721+
nodeIngestStats.getIngestFailedCount(),
722+
nodeIngestStats.getIngestCurrent(),
723+
nodeIngestStats.getIngestTimeInMillis()
724+
};
725+
} else {
726+
v[0] += nodeIngestStats.getIngestCount();
727+
v[1] += nodeIngestStats.getIngestFailedCount();
728+
v[2] += nodeIngestStats.getIngestCurrent();
729+
v[3] += nodeIngestStats.getIngestTimeInMillis();
730+
return v;
731+
}
732+
});
733+
}
734+
}
735+
}
736+
}
737+
this.pipelineCount = pipelineIds.size();
738+
this.stats = Collections.unmodifiableSortedMap(stats);
739+
}
740+
741+
@Override
742+
public XContentBuilder toXContent(final XContentBuilder builder, final Params params) throws IOException {
743+
builder.startObject("ingest");
744+
{
745+
builder.field("number_of_pipelines", pipelineCount);
746+
builder.startObject("processor_stats");
747+
for (Map.Entry<String, long[]> stat : stats.entrySet()) {
748+
long[] statValues = stat.getValue();
749+
builder.startObject(stat.getKey());
750+
builder.field("count", statValues[0]);
751+
builder.field("failed", statValues[1]);
752+
builder.field("current", statValues[2]);
753+
builder.humanReadableField("time_in_millis", "time",
754+
new TimeValue(statValues[3], TimeUnit.MILLISECONDS));
755+
builder.endObject();
756+
}
757+
builder.endObject();
758+
}
759+
builder.endObject();
760+
return builder;
761+
}
762+
763+
}
764+
693765
}

server/src/main/java/org/elasticsearch/action/admin/cluster/stats/TransportClusterStatsAction.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ protected ClusterStatsNodeResponse newNodeResponse(StreamInput in) throws IOExce
9595
protected ClusterStatsNodeResponse nodeOperation(ClusterStatsNodeRequest nodeRequest, Task task) {
9696
NodeInfo nodeInfo = nodeService.info(true, true, false, true, false, true, false, true, false, false);
9797
NodeStats nodeStats = nodeService.stats(CommonStatsFlags.NONE,
98-
true, true, true, false, true, false, false, false, false, false, false, false);
98+
true, true, true, false, true, false, false, false, false, false, true, false);
9999
List<ShardStats> shardsStats = new ArrayList<>();
100100
for (IndexService indexService : indicesService) {
101101
for (IndexShard indexShard : indexService) {

server/src/main/java/org/elasticsearch/ingest/IngestService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ public IngestStats stats() {
413413
processorMetrics.forEach(t -> {
414414
Processor processor = t.v1();
415415
IngestMetric processorMetric = t.v2();
416-
statsBuilder.addProcessorMetrics(id, getProcessorName(processor), processorMetric);
416+
statsBuilder.addProcessorMetrics(id, getProcessorName(processor), processor.getType(), processorMetric);
417417
});
418418
});
419419
return statsBuilder.build();

server/src/main/java/org/elasticsearch/ingest/IngestStats.java

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
package org.elasticsearch.ingest;
2121

22+
import org.elasticsearch.Version;
2223
import org.elasticsearch.common.io.stream.StreamInput;
2324
import org.elasticsearch.common.io.stream.StreamOutput;
2425
import org.elasticsearch.common.io.stream.Writeable;
@@ -67,8 +68,12 @@ public IngestStats(StreamInput in) throws IOException {
6768
List<ProcessorStat> processorStatsPerPipeline = new ArrayList<>(processorsSize);
6869
for (int j = 0; j < processorsSize; j++) {
6970
String processorName = in.readString();
71+
String processorType = null;
72+
if (in.getVersion().onOrAfter(Version.V_8_0_0)) {
73+
processorType = in.readString();
74+
}
7075
Stats processorStat = new Stats(in);
71-
processorStatsPerPipeline.add(new ProcessorStat(processorName, processorStat));
76+
processorStatsPerPipeline.add(new ProcessorStat(processorName, processorType, processorStat));
7277
}
7378
this.processorStats.put(pipelineId, processorStatsPerPipeline);
7479
}
@@ -88,6 +93,9 @@ public void writeTo(StreamOutput out) throws IOException {
8893
out.writeVInt(processorStatsForPipeline.size());
8994
for (ProcessorStat processorStat : processorStatsForPipeline) {
9095
out.writeString(processorStat.getName());
96+
if (out.getVersion().onOrAfter(Version.V_8_0_0)) {
97+
out.writeString(processorStat.getType());
98+
}
9199
processorStat.getStats().writeTo(out);
92100
}
93101
}
@@ -110,9 +118,12 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
110118
for (ProcessorStat processorStat : processorStatsForPipeline) {
111119
builder.startObject();
112120
builder.startObject(processorStat.getName());
121+
builder.field("type", processorStat.getType());
122+
builder.startObject("stats");
113123
processorStat.getStats().toXContent(builder, params);
114124
builder.endObject();
115125
builder.endObject();
126+
builder.endObject();
116127
}
117128
}
118129
builder.endArray();
@@ -224,9 +235,9 @@ Builder addPipelineMetrics(String pipelineId, IngestMetric pipelineMetric) {
224235
return this;
225236
}
226237

227-
Builder addProcessorMetrics(String pipelineId, String processorName, IngestMetric metric) {
238+
Builder addProcessorMetrics(String pipelineId, String processorName, String processorType, IngestMetric metric) {
228239
this.processorStats.computeIfAbsent(pipelineId, k -> new ArrayList<>())
229-
.add(new ProcessorStat(processorName, metric.createStats()));
240+
.add(new ProcessorStat(processorName, processorType, metric.createStats()));
230241
return this;
231242
}
232243

@@ -262,17 +273,23 @@ public Stats getStats() {
262273
*/
263274
public static class ProcessorStat {
264275
private final String name;
276+
private final String type;
265277
private final Stats stats;
266278

267-
public ProcessorStat(String name, Stats stats) {
279+
public ProcessorStat(String name, String type, Stats stats) {
268280
this.name = name;
281+
this.type = type;
269282
this.stats = stats;
270283
}
271284

272285
public String getName() {
273286
return name;
274287
}
275288

289+
public String getType() {
290+
return type;
291+
}
292+
276293
public Stats getStats() {
277294
return stats;
278295
}

server/src/test/java/org/elasticsearch/action/admin/cluster/node/stats/NodeStatsTests.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ public void testSerialization() throws IOException {
315315
}
316316
}
317317

318-
private static NodeStats createNodeStats() {
318+
public static NodeStats createNodeStats() {
319319
DiscoveryNode node = new DiscoveryNode("test_node", buildNewFakeTransportAddress(),
320320
emptyMap(), emptySet(), VersionUtils.randomVersion(random()));
321321
OsStats osStats = null;
@@ -456,7 +456,8 @@ private static NodeStats createNodeStats() {
456456
for (int j =0; j < numProcessors;j++) {
457457
IngestStats.Stats processorStats = new IngestStats.Stats
458458
(randomNonNegativeLong(), randomNonNegativeLong(), randomNonNegativeLong(), randomNonNegativeLong());
459-
processorPerPipeline.add(new IngestStats.ProcessorStat(randomAlphaOfLengthBetween(3, 10), processorStats));
459+
processorPerPipeline.add(new IngestStats.ProcessorStat(randomAlphaOfLengthBetween(3, 10),
460+
randomAlphaOfLengthBetween(3, 10), processorStats));
460461
}
461462
ingestProcessorStats.put(pipelineId,processorPerPipeline);
462463
}

server/src/test/java/org/elasticsearch/action/admin/cluster/stats/ClusterStatsNodesTests.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,26 @@
2020
package org.elasticsearch.action.admin.cluster.stats;
2121

2222
import org.elasticsearch.action.admin.cluster.node.info.NodeInfo;
23+
import org.elasticsearch.action.admin.cluster.node.stats.NodeStats;
2324
import org.elasticsearch.cluster.node.DiscoveryNode;
2425
import org.elasticsearch.common.network.NetworkModule;
2526
import org.elasticsearch.common.settings.Settings;
2627
import org.elasticsearch.common.xcontent.XContentType;
2728
import org.elasticsearch.test.ESTestCase;
2829

2930
import java.util.Arrays;
31+
import java.util.Collections;
32+
import java.util.Iterator;
3033
import java.util.List;
34+
import java.util.Map;
35+
import java.util.SortedMap;
36+
import java.util.TreeMap;
3137

3238
import static java.util.Collections.emptyList;
3339
import static java.util.Collections.singletonList;
40+
import static org.elasticsearch.action.admin.cluster.node.stats.NodeStatsTests.createNodeStats;
3441
import static org.elasticsearch.common.xcontent.XContentHelper.toXContent;
42+
import static org.hamcrest.Matchers.equalTo;
3543

3644
public class ClusterStatsNodesTests extends ESTestCase {
3745

@@ -59,6 +67,41 @@ public void testNetworkTypesToXContent() throws Exception {
5967
+ "}", toXContent(stats, XContentType.JSON, randomBoolean()).utf8ToString());
6068
}
6169

70+
public void testIngestStats() throws Exception {
71+
NodeStats nodeStats = createNodeStats();
72+
73+
SortedMap<String, long[]> processorStats = new TreeMap<>();
74+
nodeStats.getIngestStats().getProcessorStats().values().forEach(l -> l.forEach(s -> processorStats.put(s.getType(),
75+
new long[] { s.getStats().getIngestCount(), s.getStats().getIngestFailedCount(),
76+
s.getStats().getIngestCurrent(), s.getStats().getIngestTimeInMillis()})));
77+
ClusterStatsNodes.IngestStats stats = new ClusterStatsNodes.IngestStats(Collections.singletonList(nodeStats));
78+
assertThat(stats.pipelineCount, equalTo(nodeStats.getIngestStats().getProcessorStats().size()));
79+
String processorStatsString = "{";
80+
Iterator<Map.Entry<String, long[]>> iter = processorStats.entrySet().iterator();
81+
while (iter.hasNext()) {
82+
Map.Entry<String, long[]> entry = iter.next();
83+
long[] statValues = entry.getValue();
84+
long count = statValues[0];
85+
long failedCount = statValues[1];
86+
long current = statValues[2];
87+
long timeInMillis = statValues[3];
88+
processorStatsString += "\"" + entry.getKey() + "\":{\"count\":" + count
89+
+ ",\"failed\":" + failedCount
90+
+ ",\"current\":" + current
91+
+ ",\"time_in_millis\":" + timeInMillis
92+
+ "}";
93+
if (iter.hasNext()) {
94+
processorStatsString += ",";
95+
}
96+
}
97+
processorStatsString += "}";
98+
assertThat(toXContent(stats, XContentType.JSON, false).utf8ToString(), equalTo(
99+
"{\"ingest\":{"
100+
+ "\"number_of_pipelines\":" + stats.pipelineCount + ","
101+
+ "\"processor_stats\":" + processorStatsString
102+
+ "}}"));
103+
}
104+
62105
private static NodeInfo createNodeInfo(String nodeId, String transportType, String httpType) {
63106
Settings.Builder settings = Settings.builder();
64107
if (transportType != null) {

server/src/test/java/org/elasticsearch/ingest/IngestStatsTests.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,10 @@ private List<IngestStats.PipelineStat> createPipelineStats() {
5252

5353
private Map<String, List<IngestStats.ProcessorStat>> createProcessorStats(List<IngestStats.PipelineStat> pipelineStats){
5454
assert(pipelineStats.size() >= 2);
55-
IngestStats.ProcessorStat processor1Stat = new IngestStats.ProcessorStat("processor1", new IngestStats.Stats(1, 1, 1, 1));
56-
IngestStats.ProcessorStat processor2Stat = new IngestStats.ProcessorStat("processor2", new IngestStats.Stats(2, 2, 2, 2));
57-
IngestStats.ProcessorStat processor3Stat = new IngestStats.ProcessorStat("processor3", new IngestStats.Stats(47, 97, 197, 297));
55+
IngestStats.ProcessorStat processor1Stat = new IngestStats.ProcessorStat("processor1", "type", new IngestStats.Stats(1, 1, 1, 1));
56+
IngestStats.ProcessorStat processor2Stat = new IngestStats.ProcessorStat("processor2", "type", new IngestStats.Stats(2, 2, 2, 2));
57+
IngestStats.ProcessorStat processor3Stat = new IngestStats.ProcessorStat("processor3", "type",
58+
new IngestStats.Stats(47, 97, 197, 297));
5859
//pipeline1 -> processor1,processor2; pipeline2 -> processor3
5960
return MapBuilder.<String, List<IngestStats.ProcessorStat>>newMapBuilder()
6061
.put(pipelineStats.get(0).getPipelineId(), Stream.of(processor1Stat, processor2Stat).collect(Collectors.toList()))

x-pack/plugin/monitoring/src/test/java/org/elasticsearch/xpack/monitoring/collector/cluster/ClusterStatsMonitoringDocTests.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,11 @@ public void testToXContent() throws IOException {
536536
+ "\"type\":\"docker\","
537537
+ "\"count\":1"
538538
+ "}"
539-
+ "]"
539+
+ "],"
540+
+ "\"ingest\":{"
541+
+ "\"number_of_pipelines\":0,"
542+
+ "\"processor_stats\":{}"
543+
+ "}"
540544
+ "}"
541545
+ "},"
542546
+ "\"cluster_state\":{"

0 commit comments

Comments
 (0)