|
19 | 19 |
|
20 | 20 | package org.elasticsearch.ingest;
|
21 | 21 |
|
22 |
| -import java.util.ArrayList; |
23 |
| -import java.util.Collections; |
24 |
| -import java.util.HashMap; |
25 |
| -import java.util.HashSet; |
26 |
| -import java.util.List; |
27 |
| -import java.util.Map; |
28 |
| -import java.util.Objects; |
29 |
| -import java.util.Set; |
30 |
| -import java.util.concurrent.TimeUnit; |
31 |
| -import java.util.function.BiConsumer; |
32 |
| -import java.util.function.Consumer; |
33 |
| -import java.util.stream.Collectors; |
34 |
| - |
35 | 22 | import org.elasticsearch.ElasticsearchParseException;
|
36 | 23 | import org.elasticsearch.ExceptionsHelper;
|
37 | 24 | import org.elasticsearch.ResourceNotFoundException;
|
|
49 | 36 | import org.elasticsearch.cluster.metadata.MetaData;
|
50 | 37 | import org.elasticsearch.cluster.node.DiscoveryNode;
|
51 | 38 | import org.elasticsearch.cluster.service.ClusterService;
|
| 39 | +import org.elasticsearch.common.collect.Tuple; |
52 | 40 | import org.elasticsearch.common.regex.Regex;
|
53 | 41 | import org.elasticsearch.common.unit.TimeValue;
|
54 | 42 | import org.elasticsearch.common.util.concurrent.AbstractRunnable;
|
|
61 | 49 | import org.elasticsearch.script.ScriptService;
|
62 | 50 | import org.elasticsearch.threadpool.ThreadPool;
|
63 | 51 |
|
| 52 | +import java.util.ArrayList; |
| 53 | +import java.util.Collections; |
| 54 | +import java.util.HashMap; |
| 55 | +import java.util.HashSet; |
| 56 | +import java.util.Iterator; |
| 57 | +import java.util.List; |
| 58 | +import java.util.Map; |
| 59 | +import java.util.Objects; |
| 60 | +import java.util.Set; |
| 61 | +import java.util.concurrent.TimeUnit; |
| 62 | +import java.util.function.BiConsumer; |
| 63 | +import java.util.function.Consumer; |
| 64 | + |
64 | 65 | /**
|
65 | 66 | * Holder class for several ingest related services.
|
66 | 67 | */
|
@@ -262,11 +263,59 @@ public void applyClusterState(final ClusterChangedEvent event) {
|
262 | 263 | Pipeline originalPipeline = originalPipelines.get(id);
|
263 | 264 | if (originalPipeline != null) {
|
264 | 265 | pipeline.getMetrics().add(originalPipeline.getMetrics());
|
| 266 | + List<Tuple<Processor, IngestMetric>> oldPerProcessMetrics = new ArrayList<>(); |
| 267 | + List<Tuple<Processor, IngestMetric>> newPerProcessMetrics = new ArrayList<>(); |
| 268 | + getProcessorMetrics(originalPipeline.getCompoundProcessor(), oldPerProcessMetrics); |
| 269 | + getProcessorMetrics(pipeline.getCompoundProcessor(), newPerProcessMetrics); |
| 270 | + //Best attempt to populate new processor metrics using a parallel array of the old metrics. This is not ideal since |
| 271 | + //the per processor metrics may get reset when the arrays don't match. However, to get to an ideal model, unique and |
| 272 | + //consistent id's per processor and/or semantic equals for each processor will be needed. |
| 273 | + if (newPerProcessMetrics.size() == oldPerProcessMetrics.size()) { |
| 274 | + Iterator<Tuple<Processor, IngestMetric>> oldMetricsIterator = oldPerProcessMetrics.iterator(); |
| 275 | + for (Tuple<Processor, IngestMetric> compositeMetric : newPerProcessMetrics) { |
| 276 | + String type = compositeMetric.v1().getType(); |
| 277 | + IngestMetric metric = compositeMetric.v2(); |
| 278 | + if (oldMetricsIterator.hasNext()) { |
| 279 | + Tuple<Processor, IngestMetric> oldCompositeMetric = oldMetricsIterator.next(); |
| 280 | + String oldType = oldCompositeMetric.v1().getType(); |
| 281 | + IngestMetric oldMetric = oldCompositeMetric.v2(); |
| 282 | + if (type.equals(oldType)) { |
| 283 | + metric.add(oldMetric); |
| 284 | + } |
| 285 | + } |
| 286 | + } |
| 287 | + } |
265 | 288 | }
|
266 | 289 | });
|
267 | 290 | }
|
268 | 291 | }
|
269 | 292 |
|
| 293 | + /** |
| 294 | + * Recursive method to obtain all of the non-failure processors for given compoundProcessor. Since conditionals are implemented as |
| 295 | + * wrappers to the actual processor, always prefer the actual processor's metric over the conditional processor's metric. |
| 296 | + * @param compoundProcessor The compound processor to start walking the non-failure processors |
| 297 | + * @param processorMetrics The list of {@link Processor} {@link IngestMetric} tuples. |
| 298 | + * @return the processorMetrics for all non-failure processor that belong to the original compoundProcessor |
| 299 | + */ |
| 300 | + private static List<Tuple<Processor, IngestMetric>> getProcessorMetrics(CompoundProcessor compoundProcessor, |
| 301 | + List<Tuple<Processor, IngestMetric>> processorMetrics) { |
| 302 | + //only surface the top level non-failure processors, on-failure processor times will be included in the top level non-failure |
| 303 | + for (Tuple<Processor, IngestMetric> processorWithMetric : compoundProcessor.getProcessorsWithMetrics()) { |
| 304 | + Processor processor = processorWithMetric.v1(); |
| 305 | + IngestMetric metric = processorWithMetric.v2(); |
| 306 | + if (processor instanceof CompoundProcessor) { |
| 307 | + getProcessorMetrics((CompoundProcessor) processor, processorMetrics); |
| 308 | + } else { |
| 309 | + //Prefer the conditional's metric since it only includes metrics when the conditional evaluated to true. |
| 310 | + if (processor instanceof ConditionalProcessor) { |
| 311 | + metric = ((ConditionalProcessor) processor).getMetric(); |
| 312 | + } |
| 313 | + processorMetrics.add(new Tuple<>(processor, metric)); |
| 314 | + } |
| 315 | + } |
| 316 | + return processorMetrics; |
| 317 | + } |
| 318 | + |
270 | 319 | private static Pipeline substitutePipeline(String id, ElasticsearchParseException e) {
|
271 | 320 | String tag = e.getHeaderKeys().contains("processor_tag") ? e.getHeader("processor_tag").get(0) : null;
|
272 | 321 | String type = e.getHeaderKeys().contains("processor_type") ? e.getHeader("processor_type").get(0) : "unknown";
|
@@ -371,11 +420,42 @@ protected void doRun() {
|
371 | 420 | }
|
372 | 421 |
|
373 | 422 | public IngestStats stats() {
|
| 423 | + IngestStats.Builder statsBuilder = new IngestStats.Builder(); |
| 424 | + statsBuilder.addTotalMetrics(totalMetrics); |
| 425 | + pipelines.forEach((id, pipeline) -> { |
| 426 | + CompoundProcessor rootProcessor = pipeline.getCompoundProcessor(); |
| 427 | + statsBuilder.addPipelineMetrics(id, pipeline.getMetrics()); |
| 428 | + List<Tuple<Processor, IngestMetric>> processorMetrics = new ArrayList<>(); |
| 429 | + getProcessorMetrics(rootProcessor, processorMetrics); |
| 430 | + processorMetrics.forEach(t -> { |
| 431 | + Processor processor = t.v1(); |
| 432 | + IngestMetric processorMetric = t.v2(); |
| 433 | + statsBuilder.addProcessorMetrics(id, getProcessorName(processor), processorMetric); |
| 434 | + }); |
| 435 | + }); |
| 436 | + return statsBuilder.build(); |
| 437 | + } |
374 | 438 |
|
375 |
| - Map<String, IngestStats.Stats> statsPerPipeline = |
376 |
| - pipelines.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, v -> v.getValue().getMetrics().createStats())); |
| 439 | + //package private for testing |
| 440 | + static String getProcessorName(Processor processor){ |
| 441 | + // conditionals are implemented as wrappers around the real processor, so get the real processor for the correct type for the name |
| 442 | + if(processor instanceof ConditionalProcessor){ |
| 443 | + processor = ((ConditionalProcessor) processor).getProcessor(); |
| 444 | + } |
| 445 | + StringBuilder sb = new StringBuilder(5); |
| 446 | + sb.append(processor.getType()); |
377 | 447 |
|
378 |
| - return new IngestStats(totalMetrics.createStats(), statsPerPipeline); |
| 448 | + if(processor instanceof PipelineProcessor){ |
| 449 | + String pipelineName = ((PipelineProcessor) processor).getPipelineName(); |
| 450 | + sb.append(":"); |
| 451 | + sb.append(pipelineName); |
| 452 | + } |
| 453 | + String tag = processor.getTag(); |
| 454 | + if(tag != null && !tag.isEmpty()){ |
| 455 | + sb.append(":"); |
| 456 | + sb.append(tag); |
| 457 | + } |
| 458 | + return sb.toString(); |
379 | 459 | }
|
380 | 460 |
|
381 | 461 | private void innerExecute(IndexRequest indexRequest, Pipeline pipeline, Consumer<IndexRequest> itemDroppedHandler) throws Exception {
|
|
0 commit comments