We use `totalMetrics` with a `startTimeInNanos` and a call to `postIngest` to track the 'total time' that ingest is running for a given document. You can imagine it's a little stopwatch that we start and stop. Unfortunately, I think we're stopping the stopwatch just a little too soon, on the start side, we include the time spent transforming the document into an `IngestDocument`, but we do not include the (non-negligible) time transforming from an `IngestDocument` after the pipeline logic has run.

That is, the call to `sourceAsMap` is included:

https://github.com/elastic/elasticsearch/blob/d03664f84f15dcfcb900cf2d43121ca9d89bdda8/server/src/main/java/org/elasticsearch/ingest/IngestService.java#L905

But the call to `source` is not:

https://github.com/elastic/elasticsearch/blob/d03664f84f15dcfcb900cf2d43121ca9d89bdda8/server/src/main/java/org/elasticsearch/ingest/IngestService.java#L948

The consequence of this is that the `total` ingest stats doesn't actually reflect the true time spent in ingest code:

```
GET _nodes/stats?filter_path=nodes.*.ingest
{
  "nodes" : {
    "Aysm6ztIRne2ES5ktyuqtw" : {
      "ingest" : {
        "total" : {
          "count" : 1,
          "time_in_millis" : 110, <--- this should be a little higher than it is
```
server/src/main/java/org/elasticsearch/ingest/IngestService.java
updatedPipelines.put(id, new PipelineHolder(holder.configuration, updatedPipeline));
        this.pipelines = Map.copyOf(updatedPipelines);
    }
    private static Pipeline substitutePipeline(String id, ElasticsearchParseException e) {
        String tag = e.getHeaderKeys().contains("processor_tag") ? e.getHeader("processor_tag").get(0) : null;
        String type = e.getHeaderKeys().contains("processor_type") ? e.getHeader("processor_type").get(0) : "unknown";
        String errorMessage = "pipeline with id [" + id + "] could not be loaded, caused by [" + e.getDetailedMessage() + "]";
        Processor failureProcessor = new AbstractProcessor(tag, "this is a placeholder processor") {
            @Override
            public IngestDocument execute(IngestDocument ingestDocument) {
                throw new IllegalStateException(errorMessage);
            }
            @Override
            public String getType() {
                return type;
            }
        };
        String description = "this is a place holder pipeline, because pipeline with id [" + id + "] could not be loaded";
        return new Pipeline(id, description, null, null, new CompoundProcessor(failureProcessor));
    }
    static class PipelineHolder {
        final PipelineConfiguration configuration;
        final Pipeline pipeline;
        PipelineHolder(PipelineConfiguration configuration, Pipeline pipeline) {
            this.configuration = Objects.requireNonNull(configuration);
            this.pipeline = Objects.requireNonNull(pipeline);
        }
    }
}