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
long startTimeInNanos = System.nanoTime();
        
        
        totalMetrics.preIngest();
        String index = indexRequest.index();
        String id = indexRequest.id();
        String routing = indexRequest.routing();
        long version = indexRequest.version();
        VersionType versionType = indexRequest.versionType();
        Map<String, Object> sourceAsMap = indexRequest.sourceAsMap();
        IngestDocument ingestDocument = new IngestDocument(index, id, version, routing, versionType, sourceAsMap);
        /*
         * Our assumption is that the listener passed to the processor is only ever called once. However, there is no way to enforce
         * that in all processors and all of the code that they call. If the listener is called more than once it causes problems
         * such as the metrics being wrong. The listenerHasBeenCalled variable is used to make sure that the code in the listener
         * is only executed once.
         */
        final AtomicBoolean listenerHasBeenCalled = new AtomicBoolean(false);
        ingestDocument.executePipeline(pipeline, (result, e) -> {
            if (listenerHasBeenCalled.getAndSet(true)) {
                logger.warn("A listener was unexpectedly called more than once", new RuntimeException(e));
                assert false : "A listener was unexpectedly called more than once";
            } else {
                long ingestTimeInNanos = System.nanoTime() - startTimeInNanos;
                totalMetrics.postIngest(ingestTimeInNanos);
                if (e != null) {
                    totalMetrics.ingestFailed();
                    handler.accept(e);
                } else if (result == null) {
                    itemDroppedHandler.accept(slot);