Juli 2025
Autor des Beitrags
Kevin
Senior Consultant
Veröffentlicht am
07.07.2025 von Kevin
Jetzt Blogbeitrag teilen
Xing LinkedIn Facebook Twitter
WAS SIE JETZT WISSEN MÜSSEN

NetScaler-Logs verwerten mit Vector & Prometheus: So geht’s!

NetScaler produziert riesige Mengen an Logs – und genau darin liegt enormes Potenzial. Wenn man die TCP-Logs richtig verarbeitet, lassen sich wertvolle Metriken zum Netzwerkverhalten extrahieren, die dir helfen, Engpässe zu erkennen, Performance zu verbessern und Ausfälle frühzeitig zu bemerken. In diesem Artikel zeigen wir dir, wie du NetScaler TCP-Logs mit Vector verarbeitest und sie anschließend in Prometheus speicherst – für eine saubere Visualisierung und einfache Analyse. Klingt gut? Dann legen wir los!

Seit der Version 14.1 unterstützt der NetScaler ADC ein neues Feature, das es ermöglicht, Transaction Logs aktiv via Push zu versenden – ganz ohne zusätzliche Tools wie nswl. Das eröffnet neue Möglichkeiten für eine moderne und effiziente Log-Verarbeitung, insbesondere in dynamischen Infrastrukturen.

Hier kommt Vector ins Spiel: ein leistungsstarkes Open-Source-Tool von Datadog, das speziell für das Sammeln, Transformieren und Weiterleiten von Logs und Metriken entwickelt wurde. Weitere Infos findest du auf der offiziellen Webseite: https://vector.dev/. Mit Vector kannst du Datenströme flexibel verarbeiten und nahtlos an Systeme wie Prometheus, Elasticsearch oder Grafana Loki übergeben.

Im folgenden Abschnitt zeigen wir dir, wie du Vector nutzt, um NetScaler-Logs smart weiterzuverarbeiten – Schritt für Schritt.

Architekturüberblick

Bevor wir uns in die Details stürzen, ein kurzer Überblick, was hier eigentlich passiert:

  1. NetScaler schickt die Logs über HTTP an Vector.
  2. Vector verarbeitet die Logs: Unnötige Events rausfiltern, IP-Adressen umwandeln und Metriken extrahieren.
  3. Vector exportiert die Metriken nach Prometheus.
  4. Prometheus scrapt die Daten und stellt sie für Grafana & Co. bereit.

 

Vector-Konfiguration

Hier ist die komplette Vector-Konfigurationsdatei im YAML-Format. Sie sorgt dafür, dass die Logs von NetScaler aufgenommen, gefiltert und in Prometheus überführt werden:

sources:
 ns_tcp_logs_http_server:
 type: "http_server"
 address: "0.0.0.0:8080"
 encoding: "text"

transforms:
  ns_tcp_logs_create_json_array:
  type: remap
  inputs:
    - ns_tcp_logs_http_server
  source: |
    input = "[" + string!(.message) + "]"
    . = input # Replace the current message with the new JSON array

ns_tcp_logs_delete_event_without_observationPointId:
  type: remap
  inputs:
    - ns_tcp_logs_create_json_array
  source: |
  parsed = parse_json!(.message)
  parsed = filter(array!(parsed)) -> |event_index, event_details| {
     exists(event_details.event.observationPointId)
  }
  . = encode_json(parsed)

ns_tcp_logs_rewrite_ip_ntoa_to_ipv4:
  type: remap
  inputs:
    - ns_tcp_logs_delete_event_without_observationPointId
  source: |
    ipv4_fields = ["cltIpv4Address", "cltDstIpv4Address", "observationPointId"]
    parsed = parse_json!(.message)
    parsed = map_values(array!(parsed)) -> |event_details| {
      if is_object(event_details.event) {
        for_each(array(ipv4_fields)) -> |field_index, field_name| {
          .field = get!(event_details.event, [field_name])
          if .field != null {
            .converted_field = ip_ntoa!(.field)
            event_details.event = set!(event_details.event, [field_name], .converted_field)
          }
        }
      }
      event_details
   }
   . = encode_json(parsed)

ns_tcp_logs_metrics:
  type: "log_to_metric"
  inputs:
    - ns_tcp_logs_rewrite_ip_ntoa_to_ipv4
  metrics:
    - type: "gauge"
      field: ".event.clientMss"
      name: "clientMss"
      tags:
        nsip: "{{.event.observationPointId}}"
        appName: "{{.event.appName}}"
    - type: "gauge"
      field: ".event.transCltTotTxOctCnt"
      name: "transCltTotTxOctCnt"
      tags:
        nsip: "{{.event.observationPointId}}"
        appName: "{{.event.appName}}"
    - type: "gauge"
      field: ".event.transCltTotRxOctCnt"
      name: "transCltTotRxOctCnt"
      tags:
        nsip: "{{.event.observationPointId}}"
        appName: "{{.event.appName}}"
    - type: "gauge"
      field: ".event.clntFastRetxCount"
      name: "clntFastRetxCount"
      tags:
        nsip: "{{.event.observationPointId}}"
        appName: "{{.event.appName}}"
    - type: "gauge"
      field: ".event.clntTcpJitter"
      name: "clntTcpJitter"
      tags:
        nsip: "{{.event.observationPointId}}"
        appName: "{{.event.appName}}"
    - type: "gauge"‚
      field: ".event.clntTcpPacketsRetransmited"
      name: "clntTcpPacketsRetransmited"
      tags:
        nsip: "{{.event.observationPointId}}"
        appName: "{{.event.appName}}"
    - type: "gauge"
      field: ".event.clntTcpRtoCount"
      name: "clntTcpRtoCount"
      tags:
        nsip: "{{.event.observationPointId}}"
        appName: "{{.event.appName}}"
    - type: "gauge"
      field: ".event.clntTcpZeroWindowCount"
      name: "clntTcpZeroWindowCount"
      tags:
        nsip: "{{.event.observationPointId}}"
        appName: "{{.event.appName}}"
    - type: "gauge"
      field: ".event.connectionChainHopCount"
      name: "connectionChainHopCount"
      tags:
        nsip: "{{.event.observationPointId}}"
        appName: "{{.event.appName}}"
    - type: "gauge"
      field: ".event.originRspLen"
      name: "originRspLen"
      tags:
        nsip: "{{.event.observationPointId}}"
        appName: "{{.event.appName}}"
    - type: "gauge"
      field: ".event.tcpClntConnRstCode"
      name: "tcpClntConnRstCode"
      tags:
        nsip: "{{.event.observationPointId}}"
        appName: "{{.event.appName}}"
   - type: "gauge"
     field: ".event.transCltFlowEndUsecRx"
     name: "transCltFlowEndUsecRx"
     tags:
       nsip: "{{.event.observationPointId}}"
       appName: "{{.event.appName}}"
   - type: "gauge"
     field: ".event.transCltFlowEndUsecTx"
     name: "transCltFlowEndUsecTx"
     tags:
       nsip: "{{.event.observationPointId}}"
       appName: "{{.event.appName}}"
   - type: "gauge"
     field: ".event.transCltFlowStartUsecRx"
     name: "transCltFlowStartUsecRx"
     tags:
       nsip: "{{.event.observationPointId}}"
       appName: "{{.event.appName}}"
   - type: "gauge"
     field: ".event.transCltFlowStartUsecTx"
     name: "transCltFlowStartUsecTx"
     tags:
       nsip: "{{.event.observationPointId}}"
       appName: "{{.event.appName}}"

sinks:
  ns_tcp_logs_prometheus_exporter:
    type: "prometheus_exporter"
    inputs:
      - ns_tcp_logs_metrics
    address: "0.0.0.0:9090"





Quelle: HTTP Server

Hier wird eine Quelle definiert, die HTTP-Logs entgegennimmt. Der Server lauscht auf 0.0.0.0:8080, also auf allen Netzwerkschnittstellen unter Port 8080. Die eingehenden Daten sind als “text” kodiert.

sources:
  ns_tcp_logs_http_server:
    type: "http_server"
    address: "0.0.0.0:8080"
    encoding: "text"
 

Transformation: JSON Array erstellen

Der ursprüngliche Logeintrag wird hier als JSON-Array formatiert, da der NetScaler beim Push-Vorgang mehrere Events gebündelt überträgt – allerdings nicht als zusammenhängendes JSON-Dokument, sondern als einzelne JSON-Objekte. Um diese korrekt weiterzuverarbeiten, müssen sie daher zunächst zu einem gültigen JSON-Array zusammengeführt werden.

transforms:
  ns_tcp_logs_create_json_array:
    type: remap
    inputs:
      - ns_tcp_logs_http_server
    source: |
      input = "[" + string!(.message) + "]"
      . = input # Replace the current message with the new JSON array

Transformation: Events ohne observationPointId entfernen

Falls ein Event keinen observationPointId enthält, wird es herausgefiltert. Das sorgt dafür, dass nur relevante Events weiterverarbeitet werden. Hinter der observationPointId verbirgt sich die IP-Adresse des NetScaler (in einer numerischen Darstellung), über die sich das Event eindeutig einer Quelle zuordnen lässt.

ns_tcp_logs_delete_event_without_observationPointId:
  type: remap
  inputs:
    - ns_tcp_logs_create_json_array
  source: |
    parsed = parse_json!(.message)
    parsed = filter(array!(parsed)) -> |event_index, event_details| {
        exists(event_details.event.observationPointId)
    }
    . = encode_json(parsed)
 

Transformation: IP-Adressen umwandeln

Hier werden bestimmte Felder (cltIpv4Address, cltDstIpv4Address, observationPointId) von einer numerischen Darstellung in eine lesbare IPv4-Adresse konvertiert.

ns_tcp_logs_rewrite_ip_ntoa_to_ipv4:
  type: remap
  inputs:
    - ns_tcp_logs_delete_event_without_observationPointId
  source: |
    ipv4_fields = ["cltIpv4Address", "cltDstIpv4Address", "observationPointId"]
    parsed = parse_json!(.message)
    parsed = map_values(array!(parsed)) -> |event_details| {
      if is_object(event_details.event) {
        for_each(array(ipv4_fields)) -> |field_index, field_name| {
          .field = get!(event_details.event, [field_name])
          if .field != null {
            .converted_field = ip_ntoa!(.field)
            event_details.event = set!(event_details.event, [field_name], .converted_field)
          }
        }
      }
      event_details
    }
    . = encode_json(parsed)

 

Transformation: Logs in Metriken umwandeln

Hier werden bestimmte Felder aus den Events extrahiert und als Metriken gespeichert. Diese Metriken können dann für Monitoring-Zwecke genutzt werden. Beispielsweise clientMss mit Tags nsip und appName.

ns_tcp_logs_metrics:
  type: "log_to_metric"
  inputs:
    - ns_tcp_logs_rewrite_ip_ntoa_to_ipv4
  metrics:
    - type: "gauge"
      field: ".event.clientMss"
      name: "clientMss"
      tags:
        nsip: "{{.event.observationPointId}}"
        appName: "{{.event.appName}}"
   Weitere Metriken...

 

Sink: Prometheus Exporter

Die verarbeiteten Metriken werden über einen Prometheus-Exporter auf 0.0.0.0:9090 bereitgestellt, sodass Prometheus sie abrufen kann.

sinks:
  ns_tcp_logs_prometheus_exporter:
    type: "prometheus_exporter"
    inputs:
      - ns_tcp_logs_metrics
    address: "0.0.0.0:9090"

 

Prometheus Konfiguration

Damit Prometheus die von Vector exportierten Metriken abrufen kann, fügen wir folgenden Scrape-Job in der prometheus.yml hinzu:

scrape_configs:
  - job_name: 'ns_tcp_log_metrics'
    static_configs:
      - targets: ['<Vector-IP>:9090']

 

NetScaler Konfiguration

  1. SSH-Verbindung zum NetScaler herstellen:
ssh<NetScaler-Admin-User>@<NetScaler-IP>

 

2. Wechsel in das Verzeichnis /var/analytics_conf:

cd /var/analytics_conf

 

3. Kopie der Datei splunk_format.txt erstellen:

cp splunk_format.txt splunk_format_custom.txt

 

4. In splunk_format_custom.txt den Trenner in ein komma ändern:

Vorher

RECORD-DELIMITER

RECORD-DELIMITER-END

Nachher

RECORD-DELIMITER
,
RECORD-DELIMITER-END

 

5. Service für den Log-Export anlegen:

add service lb_sv_vector <vector-ip/fqdn> HTTP 8080 -gslb NONE -maxClient 0 -maxReq 0 -cip DISABLED -usip NO -useproxyport YES -sp OFF -cltTimeout 180 -svrTimeout 360 -CKA NO -TCPB NO -CMP NO

 

6. Analytics-Profil erstellen:

add analytics profile vector -collectors lb_sv_vector -type tcpinsight -tcpBurstReporting DISABLED -dataFormatFiletxt -analyticsEndpointUrl"/"-analyticsEndpointContentType"application/json"

 

7. Analytics-Profil global binden:

bind analytics global vector

Fazit

Mit dieser Konfiguration haben wir NetScaler TCP-Logs erfolgreich mit Vector verarbeitet und an Prometheus weitergeleitet. Jetzt können wir sie in Grafana oder einem anderen Dashboard visualisieren und zur Netzwerküberwachung nutzen. Einfach, oder?

Sie möchten mehr Infos?

Wir sind für Sie da.

Bei welchem Projekt oder welcher Herausforderung dürfen wir Sie unterstützen?
Wir sind gerne für Sie da.

 

HEIKO WESSELS

+49 89 71040920

heiko@provectus.de

 

Zum Kontaktformular

 

Wollen Sie immer up2date sein? Dann melden Sie sich jetzt zu unserem Newsletter an

Bleiben Sie auf dem Laufenden. Wir informieren Sie regelmäßig über aktuelle Trends und technologische Neuerungen sowie geplante Webinare und Events. Sie erhalten Einblick in interessante Kundenprojekte und werfen einen Blick hinter die Kulissen. Melden Sie sich jetzt an.

Zur Newsletter Anmeldung 

Blogbeitrag

Cloud Exit als Enterprise Risk Management – Was Auditoren und Regulatoren erwarten

DORA, NIS2, DSGVO & Co. erhöhen die Anforderungen an den Umgang mit Cloud-Abhängigkeiten. Wir zeigen, warum Exit-Readiness zunehmend zur Compliance-Pflicht wird und welche Nachweise Auditoren konkret erwarten.
Weiterlesen
Blogbeitrag

Typische KI-Workflows im Unternehmen: Welche Aufgaben in Chat, Agenten und Zielsysteme gehören

Gute KI-Workflows entstehen durch klare Arbeitsteilung: Wir zeigen, welches Werkzeug sich für welchen Arbeitsschritt eignet – und wie KI dadurch effizienter und wirtschaftlicher wird.
Weiterlesen
Blogbeitrag

Warum Cloud Exit kein Widerspruch zur Cloud-Strategie ist

Was bedeutet Cloud Exit wirklich? Erfahren Sie, warum Unternehmen trotz Microsoft Cloud auf Exit-Readiness setzen sollten und welche Rolle DORA, NIS2 und DSGVO spielen.
Weiterlesen
Webinar

12.500 € verbrannt und niemand merkt’s: So verhindern Managed Services Kostenfallen und Risiken

In diesem kostenlosen Webinar erfahren Sie, wie Azure-Kostenfallen entstehen, wie Fehlkonfigurationen frühzeitig erkannt werden und welche Betriebsstandards Managed Services dafür einsetzen.
Weiterlesen
Blogbeitrag

KI wirtschaftlich einsetzen: Warum nicht jede Aufgabe einen KI-Agenten braucht

Nicht jede Aufgabe braucht einen KI-Agenten – und nicht jede Automatisierung überhaupt KI. Erfahren Sie, wie Sie für jede Anforderung die passende Lösung wählen und KI wirtschaftlich, effizient und mit der richtigen Komplexität einsetzen.
Weiterlesen
Blogbeitrag

Microsoft NGO Tour 2026

Die Microsoft NGO Tour hat einmal mehr gezeigt, wie viel Potenzial in diesem Austausch steckt. Die besten Lösungen entstehen dort, wo Menschen ihr Wissen teilen, unterschiedliche Perspektiven zusammenkommen und Herausforderungen gemeinsam gedacht werden.
Weiterlesen
Blogbeitrag

Echtes Zero Trust im Citrix-Workspace mit deviceTRUST

Conditional Access prüft beim Login, deviceTRUST während der gesamten Citrix-Session: kontinuierlich und kontextbasiert. Wie du deine Citrix-Umgebung zu einem Zero-Trust-Workspace weiterentwickelst, der Security-Anforderungen und Alltag der Fachbereiche zusammenbringt.
Weiterlesen
Blogbeitrag

Secure Boot 2026: Warum Unternehmen jetzt handeln sollten

2026 laufen wichtige Secure-Boot-Zertifikate ab – erfahren Sie, warum Unternehmen ihre Systeme schon heute prüfen und vorbereiten sollten.
Weiterlesen
Blogbeitrag

KI wirtschaftlich einsetzen: Warum der richtige Workflow wichtiger ist als der Prompt

Mit der verbrauchsabhängigen Abrechnung von Microsoft Copilot Cowork wird Wirtschaftlichkeit im KI-Einsatz zur operativen Frage. Der Artikel zeigt, warum nicht der Prompt, sondern vor allem der passende Workflow über Aufwand, Transparenz und Nutzen entscheidet.
Weiterlesen
Blogbeitrag

US-Urteil zur FTC: Handlungsbedarf für Microsoft-Kunden?

Das Urteil des US Supreme Court zur FTC sorgt für neue Fragen rund um das EU-US Data Privacy Framework. Wir ordnen ein, was das für Microsoft 365, Azure und die nächsten Schritte in der Praxis bedeutet.
Weiterlesen
Jetzt Blogbeitrag teilen
Xing LinkedIn Facebook Twitter