Enhancing the `logs-*-*` index template with a default ingest pipeline that is first doing a pre-flight check if the `message` field might be JSON and then uses the JSON processor to decode the JSON and merge it top-level with the document.

See also this prototype: https://gist.github.com/felixbarny/a9a2f6243153d5508643fd95ac968a88#file-routing-yml-L114-L174

Open questions and things to consider
* How do users opt-out of default JSON parsing? They could override the index template. Maybe that's good enough.
* Similarly to the logs@custom component template, should we call out to a custom index pipeline? Align with naming in Fleet.
x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/template/IndexTemplateRegistryTests.java
private static void assertPutPipelineAction(
        AtomicInteger calledTimes,
        ActionType<?> action,
        ActionRequest request,
        ActionListener<?> listener
    ) {
        assertThat(action, instanceOf(PutPipelineAction.class));
        assertThat(request, instanceOf(PutPipelineRequest.class));
        final PutPipelineRequest putRequest = (PutPipelineRequest) request;
        assertThat(putRequest.getId(), oneOf("custom-plugin-default_pipeline", "custom-plugin-final_pipeline"));
        PipelineConfiguration pipelineConfiguration = new PipelineConfiguration(
            putRequest.getId(),
            putRequest.getSource(),
            putRequest.getXContentType()
        );
        List<?> processors = (List<?>) pipelineConfiguration.getConfigAsMap().get("processors");
        assertThat(processors, hasSize(1));
        Map<?, ?> setProcessor = (Map<?, ?>) ((Map<?, ?>) processors.get(0)).get("set");
        assertNotNull(setProcessor.get("field"));
        assertNotNull(setProcessor.get("copy_from"));
        assertNotNull(listener);
        calledTimes.incrementAndGet();
    }
    private ClusterChangedEvent createClusterChangedEvent(Map<String, Integer> existingTemplates, DiscoveryNodes nodes) {
        return createClusterChangedEvent(existingTemplates, Collections.emptyMap(), Collections.emptyMap(), nodes);
    }
    private ClusterChangedEvent createClusterChangedEvent(
        Map<String, Integer> existingTemplates,
        Map<String, LifecyclePolicy> existingPolicies,
        Map<String, Integer> existingIngestPipelines,