Engineering

Kurze Logstash-Lektionen – Teil 1: Datentypen festlegen mit Grok und Mutate

Logstash ist eine Pipeline zur Verarbeitung von Ereignissen, die ein reichhaltiges Ökosystem von Plugins enthält, mit denen Benutzer Daten übergeben, bearbeiten und dann an verschiedene Backends senden können.

Eines dieser Plugins ist Grok. Grok ist aktuell das beste Logstash-Plugin zum Analysieren unstrukturierter Logdaten und zum Strukturieren, sodass sie besser mit Elasticsearch abgefragt werden können. Mutate, ein anderes beliebtes Plugin, ermöglicht dem Benutzer, Logstash-Ereignisdaten auf viele nützliche Arten zu bearbeiten.

Warum sollte ich meine Daten typisieren?

Elasticsearch hat noch viel mehr zu bieten als nur seine Volltextsuche. Man kann es auch zur Berechnung einer Reihe von Statistiken zu Zahlendaten nahezu in Echtzeit nutzen. Kibana kann dann die Ergebnisse dieser Berechnungen in Diagramme und Dashboards umsetzen. Wenn die Daten nicht ordentlich mit Typen versehen werden, kann Elasticsearch diese Berechnungen nicht durchführen. Es bedarf etwas Zeit und Aufwand, Ihre Daten ordentlich mit Typen zu versehen, aber die Ergebnisse sind beeindruckend!

JSON, Strings und Zahlen

Alle an Elasticsearch gesendeten Dokumente müssen im JSON-Format vorliegen. Logstash ist dazu da, Ihre Daten für Sie in JSON-Dokumente umzuwandeln. Wenn Elasticsearch ein JSON-Dokument erhält, gibt es sich größte Mühe, den im jeweiligen Feld enthaltenen Datentyp zu identifizieren. Die Liste der Kerntypen und eine umfassende Beschreibung jedes Typs finden Sie hier.

Wenn ich folgendes JSON-Dokument an Elasticsearch senden würde (als Logstash-Ereignis ausgewiesen):

{
    "@timestamp": "2014-10-07T20:11:45.000Z",
    "@version": "1",
    "count": 2048,
    "average": 1523.33,
    "host": "elasticsearch.com"
}

Wir können 5 Felder sehen: @timestamp, @version, count, average und host.

Im von mir gesendeten JSON sind @timestamp und host String-Felder, count und average sind Zahlenfelder, aber @version ist ein merkwürdiger Hybrid. Der Wert von @version ist eine Zahl, aber aufgrund der doppelten Anführungszeichen (") wird es in diesem JSON-Dokument als String erfasst.

Wenn ich dieses Dokument zum Indexieren an Elasticsearch senden würde:

curl -XPOST localhost:9200/Logstash-2014.10.07/logs/1 -d '
{
    "@timestamp": "2014-10-07T20:11:45.000Z",
    "@version": "1",
    "count": 2048,
    "average": 1523.33,
    "host": "elasticsearch.com"
}

und dann das Mapping prüfen würde …

curl localhost:9200/Logstash-2014.10.07/_mapping?pretty
{
  "Logstash-2014.10.07" : {
    "mappings" : {
      "logs" : {
        "properties" : {
          "@timestamp" : {
            "type" : "date",
            "format" : "dateOptionalTime"
          },
          "@version" : {
            "type" : "string"
          },
          "average" : {
            "type" : "double"
          },
          "count" : {
            "type" : "long"
          },
          "host" : {
            "type" : "string"
          }
        }
      }
    }
  }
}

average hat den Typ double, count hat den Typ long, Elasticsearch hat @timestamp erfolgreich als Datumsfeld erkannt und host ist ein String.

@version wurde als String gesendet, daher bleibt er als Typ ein String.

Sie müssen bedenken, dass Logstash alle Werte als Strings an Elasticsearch sendet, sofern Sie Ihre Daten nicht entsprechend mit einem Typ versehen (oder markieren).

Einen Datentyp in Logstash erzwingen

Es gibt aktuell zwei Möglichkeiten, Logstash zum Senden von Zahlenwerten zu zwingen: grok und mutate. Sie können Typen auch bei Elasticsearch erzwingen.

grok

Grok zum Parsen unstrukturierter Daten zu nutzen, mutet allein schon als gewaltige Aufgabe an. Erst recht verwirrend wird es, numerische Daten mit dem grok-Muster %{NUMBER:num} in ein Feld zu tokenisieren (wir nennen es num), nur um festzustellen, dass Elasticsearch num für ein String-Feld hält. Ein Teil der Verwirrung ist bedingt durch die Tatsache, dass grok die Quelldaten als String behandelt, weil es eine Engine für reguläre Ausdrücke ist. Und weil grok alle Eingaben als ein String betrachtet, erfolgt die Ausgabe ohne weiteres Zutun auch als String. Wir brauchen eine Methode, um grok und Logstash klarzumachen, dass der Wert eine Zahl sein soll.

In der offiziellen Dokumentation für grok wird das folgendermaßen erklärt:

Optional können Sie eine Datentypenumwandlung zu Ihrem grok-Muster hinzufügen. Standardmäßig wird jegliche Semantik als String gespeichert. Wenn Sie den Datentyp einer Semantik umwandeln möchten, bspw. einen String in einen Integer ändern wollen, hängen Sie ein Suffix mit dem Zieldatentyp an. Zum Beispiel %{NUMBER:num:int}, was die num-Semantik von string in integer umwandelt. Aktuell sind die einzigen unterstützten Umwandlungen int und float.

Wenn ich also ein :int zu meiner grok-Felddefinition hinzufüge, wird mein Wert auf einmal als Integer behandelt. Achtung: Das grok-Muster NUMBER erkennt auch Zahlen mit Dezimalwerten. Wenn Sie eine Zahl mit einem Dezimalwert als :int kennzeichnen, wird der Dezimalwert abgeschnitten und nur der ganzzahlige Teil berücksichtigt.

In diesem Fall kann die Zahl als float, sprich als Gleitkommawert behandelt werden.

mutate

Wie grok ermöglicht auch mutate Ihnen, Ihre Felder mit Typen zu versehen. Der mutate-Filter erlaubt momentan die Umwandlung eines Felds in einen integer, float oder string. Wenn wir von unserem vorigen Beispiel des num-Felds ausgehen, würde die Konfiguration etwa so aussehen:

filter {
  mutate {
    convert => { "num" => "integer" }
  }
}

Wie bei grok wird auch hier bei der Umwandlung eines Dezimalwerts zum integer-Typ der Dezimalteil abgeschnitten und nur die Ganzzahl bleibt übrig.

Unsere Arbeit prüfen

Wenn ich das Mapping in Elasticsearch nach der Umwandlung des num-Felds in integer prüfen würde, bekäme ich ein ungewöhnliches Ergebnis.

curl localhost:9200/Logstash-2014.10.07/_mapping?pretty
...
          "num" : {
            "type" : "long"
          }
...

Dort steht, der Typ ist long. Aber ich habe den Typ doch mit integer angegeben! Was ist passiert?

Die Antwort liegt bei JSON. Logstash kann nur JSON an Elasticsearch senden. In unserem ersten Beispiel in diesem Post haben wir ein Dokument gesendet, für das die Feldanzahl 2048 betrug. Elasticsearch hatte das auch als Typ long erfasst. In diesem Beispiel haben wir dasselbe getan, nur dass der Feldname num lautete. Wenn Sie Elasticsearch nicht sagen, was auf es zukommt, kann es nur vermuten, wie das gesendete JSON zu interpretieren ist.

Nächste Schritte: Typisierung in Elasticsearch

Wie machen wir also die Typisierung in Elasticsearch? Das muss bis zur nächsten Ausgabe von Little Logstash Lessons warten.

Ich hoffe, Sie fanden unsere heutige Ausgabe von Little Logstash Lesson informativ. Darin haben wir dargestellt, wie wir Zahlenwerte in Logstash mit neuen Typen versehen. Freuen Sie sich schon auf die nächste Ausgabe! Darin werden Sie Ihr Wissen über die Typisierung in Elasticsearch um vieles erweitern.