An index template before the first document, or reindex later

Field types are decided by whichever document arrives first, so a field that is an integer in one service and a string in another is rejected in the second — silently, in a counter nobody watches.

PUT /_template/logs
{
  "index_patterns": ["logs-*"],
  "settings": { "number_of_shards": 1, "number_of_replicas": 1 },
  "mappings": {
    "dynamic_templates": [
      { "strings": { "match_mapping_type": "string",
                     "mapping": { "type": "keyword", "ignore_above": 1024 }}}
    ],
    "properties": {
      "@timestamp":     { "type": "date" },
      "correlation_id": { "type": "keyword" },
      "duration_ms":    { "type": "float" }
    }
  }
}

Defaulting strings to keyword rather than analysed text is the decision worth making up front: analysed text is for prose, and a hostname or a status code is a value to filter and aggregate on. Getting it wrong doubles the index size and makes exact matching unreliable. Changing a mapping after documents exist means a reindex, which is why the template has to precede the first write rather than follow it.