Mule, Cloudhub und Elastic Stack

Keine Kommentare

Ich will es ja gar nicht in Frage stellen, dass Deployment in der Cloud – und hier geht es speziell um Cloudhub – Vorteile hat. Features wie Zero Downtime Deployment muss man auf eigenen Servern erstmal hinbekommen. Aber seien wir mal ehrlich: Man muss sich auf einmal über Dinge Gedanken machen, die gestern (a.k.a. on premise) noch selbstverständlich waren. Zum Beispiel der Dateizugriff. Konnte ich gestern noch die Logdateien im Dateisystem durchstöbern, liegen die Logdateien heute auf einer AWS-Instanz, auf die ich keinen Zugriff habe.

Runtime Manager von Cloudhub

Der Runtime Manager von Cloudhub stellt eine Ansicht zur Verfügung, über die man die Logdateien durchsuchen kann. Der Funktionsumfang entspricht dem, was man so in der Regel erwartet. Logeinträge erscheinen automatisch, sobald sie verfügbar sind. Man kann sie durchsuchen, nach Log-Level filtern und sich Logeinträge aus einer bestimmten Zeitspanne anzeigen lassen. Nichtsdestotrotz kommt die Ansicht für die Logdateien schnell an ihre Grenzen – spätestens wenn man einen Vorfall untersuchen will, an dem mehrere Anwendungen beteiligt sind. Funktioniert eine Anwendung nicht wie erwartet, weil eine andere die benötigten Daten nicht liefern kann, ist man schnell dabei, zwischen den Logdateien einzelner Anwendungen zu wechseln, um den Grund herauszufinden. Besser wäre es doch, die Logdateien aller beteiligten Anwendungen an einer zentralen Stellen zu sammeln und für Auswertungen bereitzustellen. Noch bevor ich den Satz zu Ende schreibe, muss ich schon an den Elastic Stack (früher auch ELK Stack) denken.

Logstash, Elasticsearch und Kibana

Dabei handelt es sich um die Kombination aus Logstash, Elasticsearch und Kibana, die jeweils für eine der oben genannten Aufgaben zuständig sind: Logstash sammelt die Logdateien ein und bereitet die Logeiträge auf. Elasticsearch stellt sie bereit. Und Kibana ist das Interface für die Auswertung.

Jetzt werde ich Logstash nicht einfach auf die Logdateien loslassen können. Wie gesagt, diese liegen auf einer AWS-Instanz, die von Cloudhub verwaltet
wird. Unerreichbar sind sie für mich trotzdem nicht. Mulesoft bietet eine Reihe an APIs rund um Cloudhub an, darunter auch die Cloudhub Enhanced Logging API. Der Name lässt es bereits vermuten: Man kann die Logeinträge über eine HTTP-Schnittstelle abrufen.

CloudHub Enhanced Logging API

Die Verwendung der API ist recht einfach. Ich logge mich mit einem Benutzer, der auf die gewünschte Anwendung zugreifen kann, ein und bekomme ein Session-Token als Antwort im Erfolgsfall:

curl -XPOST --data 'username=&password=' https://anypoint.mulesoft.com/accounts/login
{
   "access_token": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxx",
   "token_type": "bearer",
   "redirectUrl": "/home/"
}

Mit dem Token kann ich nun API-Aufrufe tätigen. Was mich interessiert, ist eigentlich nur der Aufruf von /api/v2/applications/DOMAIN/logs, wobei DOMAIN der Name der Anwendung ist, von der ich die Logeinträge haben will. Der Aufruf lässt sich über ein JSON-Dokument parametrisieren, das ich mit dem Request mitsende. Folgendes Beispiel aus der API-Dokumentation zeigt die Felder, die das JSON-Dokument beinhalten kann:

{
   "deploymentId": "55ae8526e4b046c45954ca8d",
   "instanceId": "i-ff5ddd16",
   "tenantId": "",
   "startTime": 0,
   "endTime": 1437500983188,
   "text": "",
   "priority": "INFO",
   "loggerName": "org.mule.api.processor.LoggerMessageProcessor",
   "threadName": "[360-new-logs].logstressFlow1.stage1.02",
   "limit": 100,
   "limitMsgLen": 20,
   "descending": true,
   "upperId": "",
   "lowerId": ""
}

Hier ist der Vollständigkeit halber noch der Aufruf von curl, um die API auszuprobieren:

curl -XPOST -H "Content-Type: application/json" -H "Authorization: Bearer TOKEN" \
   -H "X-ANYPNT-ENV-ID: ENV-ID" --data '{ "limit": 100 }' \
   https://anypoint.mulesoft.com/cloudhub/api/v2/applications/DOMAIN/logs

TOKEN, ENV-ID und DOMAIN muss ich noch gegen die ensprechenden Werte austauschen. Den Wert für TOKEN habe ich im Feld access_token bekommen, als ich /accounts/login aufgerufen habe. ENV-ID ist die ID der Umgebung, auf der die Anwendung läuft, für die ich mich interessiere. Wenn es nur eine Umgebung gibt, kann ich den Header auch weglassen. Und DOMAIN ist der Name der Anwendung. Als Antwort bekomme ich eine Liste von JSON-Objekten. Jedes davon repräsentiert einen Logeintrag. Das ist praktisch, denn ich muss Logstash nicht mehr beibringen, wo ein Logeintrag anfängt und wo er endet. Bei Stacktraces und mehrzeiligen Logeinträgen ist es nicht ganz einfach.

Logstash Plugin

Jetzt, wo ich ein Gefühl für die API bekommen habe, muss ich „nur“ noch Logstash dazu bringen, die Cloudhub-API zu benutzen. Das mache ich, indem ich die API-Aufrufe in ein Logstash-Plugin verpacke. Den dazu notwendigen Boilerplate Code lasse ich mir direkt von Logstash generieren.

/bin/logstash-plugin generate --type input --name cloudhub

Das Ergebnis ist ein Ruby-Projekt – ja, Logstash-Plugins werden in Ruby geschrieben – mit den notwendigen Abhängigkeiten, der Konfiguration und einem Beispiel. Die Details der Implementierung lasse ich hier weg. Den Code kann man sich auf Github anschauen. Je nach Umsetzung könnte die Konfiguration für das Plugin so aussehen:

input {
   cloudhub {
      domain => "my-application"
      username => "Bob"
      password => "secret"
      interval => 300
   }
}

output {
   elasticsearch { ... }
}

Jetzt sind die Logeinträge aus Cloudhub in Elasticsearch, und ich kann ich mir damit eine Übersicht verschaffen, die über das hinausgeht, was mir die Logs-Ansicht in Cloudhub bietet – obwohl ich zugeben muss: So bunt wie auf der Projekt-Seite von Kibana sehen meine Auswertungen noch nicht aus. 🙂

Yevgeniy Melnichuk

Yevgeniy unterstützt seit 2009 im Namen von codecentric AG die Kunden dabei ihre Ideen in Software zu gießen. Dabei ist die Software bevorzugt verteilt, gut getestet und natürlich Open Source.

Share on FacebookGoogle+Share on LinkedInTweet about this on TwitterShare on RedditDigg thisShare on StumbleUpon

Kommentieren

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.