Kennzahlen live im Terminal, ohne Grafana
Nicht jedes Team hat Grafana oder ein ELK-Stack im Zugriff, wenn es schnell wissen muss, wie viele Fehler ein Dienst gerade produziert. Ein Bash-Terminal-Dashboard aus watch, tput und ANSI-Farbcodes zeigt Fehlerquoten, Request-Raten und Log-Level live an, direkt in der SSH-Session, ohne Browser und ohne zusätzliche Infrastruktur.
Inhaltsverzeichnis
- 1. Wann ein Terminal-Dashboard sinnvoller ist als Grafana
- 2. Grundlagen: watch als einfachster Live-Refresh
- 3. Log-Zeilen aggregieren: Fehlerquote pro Minute mit awk
- 4. Layout mit tput: Cursor-Positionierung ohne Flackern
- 5. ANSI-Farben für Schwellenwerte und Status-Ampeln
- 6. Sparklines und Mini-Trends im Terminal zeichnen
- 7. Eigene Refresh-Loop statt watch für mehr Kontrolle
- 8. Performance bei wachsenden Log-Dateien im Griff behalten
- 9. Terminal-Dashboard im Vergleich zu Grafana und ELK
- 10. Zusammenfassung
- 11. FAQ
1. Wann ein Terminal-Dashboard sinnvoller ist als Grafana
Ein Bash Terminal-Dashboard löst ein sehr spezifisches Problem: Man ist per SSH auf einem Server, ein Dienst zeigt Auffälligkeiten, und man will in Sekunden sehen, wie sich Fehlerquote oder Request-Rate gerade entwickeln, ohne erst ein Grafana-Dashboard zu öffnen, einen VPN-Tunnel aufzubauen oder eine Kibana-Query zu bauen. Für genau diesen Moment ist ein Bash Terminal-Dashboard, das direkt aus den lokal vorhandenen Log-Dateien aggregiert, oft schneller einsatzbereit als jedes browserbasierte Tool.
Der zweite Anwendungsfall für ein Bash Terminal-Dashboard ist die Umgebung ohne zentrales Monitoring: kleine Projekte, Staging-Server oder Kundensysteme, auf denen kein ELK-Stack läuft und keiner laufen soll, weil der Betriebsaufwand in keinem Verhältnis zur Serverzahl steht. Ein Skript, das tail -f, awk und ein bisschen ANSI-Formatierung kombiniert, liefert in solchen Fällen einen brauchbaren Ersatz für ein vollwertiges Observability-Setup, ohne einen einzigen zusätzlichen Prozess dauerhaft laufen zu lassen.
Dieser Artikel zeigt, wie ein Bash Terminal-Dashboard von der einfachsten Form mit watch bis zu einem vollwertigen Live-Dashboard mit Farbcodierung, Sparklines und eigener Refresh-Loop wächst, speziell für die Auswertung von Log-Dateien.
2. Grundlagen: watch als einfachster Live-Refresh
Der einfachste Einstieg in ein Bash Terminal-Dashboard ist das watch-Kommando. watch -n 5 './metrics.sh' führt ein Skript alle fünf Sekunden aus und ersetzt die Bildschirmausgabe komplett, wodurch der Eindruck eines Live-Updates entsteht. Für die meisten Log-Analytics-Anwendungen reicht dieser einfache Ansatz bereits aus, weil die Aktualisierungsfrequenz selten unter einer Sekunde liegen muss.
watch bietet mit -d zusätzlich Difference-Highlighting, das geänderte Werte zwischen zwei Durchläufen farblich hervorhebt. Für ein Bash Terminal-Dashboard, das Fehlerzähler zeigt, macht das auf einen Blick sichtbar, welche Metrik sich seit dem letzten Refresh verändert hat, ohne dass man selbst eine Delta-Berechnung programmieren muss.
#!/usr/bin/env bash
# metrics.sh — collect and print current error rate metrics
set -euo pipefail
readonly LOG_FILE="/var/log/app/access.log"
readonly WINDOW_MINUTES=5
cutoff="$(date -d "-${WINDOW_MINUTES} minutes" '+%Y-%m-%dT%H:%M')"
total_requests=$(awk -v cutoff="$cutoff" '$1 >= cutoff' "$LOG_FILE" | wc -l)
error_requests=$(awk -v cutoff="$cutoff" '$1 >= cutoff && $2 >= 500' "$LOG_FILE" | wc -l)
error_rate="0.0"
if (( total_requests > 0 )); then
error_rate=$(awk -v e="$error_requests" -v t="$total_requests" 'BEGIN { printf "%.2f", (e/t)*100 }')
fi
echo "=== Log Dashboard — last ${WINDOW_MINUTES} min ==="
echo "Total requests: $total_requests"
echo "5xx errors: $error_requests"
echo "Error rate: ${error_rate}%"
Aufgerufen mit watch -n 5 -d ./metrics.sh entsteht bereits ein funktionierendes Bash Terminal-Dashboard, das alle fünf Sekunden aktualisiert und Änderungen hervorhebt. Der nächste logische Schritt ist, die Aggregationslogik zu verfeinern, damit nicht nur ein Gesamtwert, sondern eine zeitliche Aufschlüsselung entsteht.
3. Log-Zeilen aggregieren: Fehlerquote pro Minute mit awk
Ein Bash Terminal-Dashboard, das nur eine einzelne Gesamtzahl zeigt, verschenkt Informationsgehalt. Interessanter ist eine Aufschlüsselung nach Zeitfenstern, damit ein Betrachter sofort sieht, ob eine Fehlerspitze gerade erst begonnen hat oder schon seit zehn Minuten anhält. awk eignet sich hervorragend für diese Art der Aggregation, weil es Log-Zeilen in einem einzigen Durchlauf gruppieren und zählen kann, ohne eine externe Datenbank zu benötigen.
Die Technik dafür ist ein assoziatives Array in awk, das pro Minute (oder pro Statuscode, pro Endpoint) einen Zähler führt. Am Ende des Durchlaufs iteriert awk über alle gesammelten Schlüssel und gibt eine sortierte Tabelle aus. Für ein Bash Terminal-Dashboard, das mehrere Kennzahlen gleichzeitig zeigen soll, lohnt es sich, diese Aggregation in eine wiederverwendbare Funktion auszulagern.
#!/usr/bin/env bash
set -euo pipefail
readonly LOG_FILE="/var/log/app/access.log"
# Aggregate error rate per minute using an associative array in awk
awk '
{
minute = substr($1, 1, 16) # YYYY-MM-DDTHH:MM
total[minute]++
if ($2 >= 500) errors[minute]++
}
END {
for (m in total) {
rate = (errors[m] > 0) ? (errors[m] / total[m]) * 100 : 0
printf "%s total=%-5d errors=%-4d rate=%.1f%%\n", m, total[m], errors[m]+0, rate
}
}' "$LOG_FILE" | sort | tail -n 10
Dieses Aggregations-Pattern ist der Baustein, der ein Bash Terminal-Dashboard von einer statischen Zahl zu einer echten Zeitreihe macht. Kombiniert mit watch entsteht daraus bereits ein rollierendes Bild der letzten zehn Minuten, das sich bei jedem Refresh automatisch aktualisiert.
4. Layout mit tput: Cursor-Positionierung ohne Flackern
Der Nachteil von watch ist, dass es den kompletten Bildschirm bei jedem Durchlauf löscht und neu zeichnet, was bei größeren Dashboards zu sichtbarem Flackern führt. Für ein ruhigeres Bash Terminal-Dashboard übernimmt tput die Kontrolle über Cursor-Position und Bildschirmbereiche gezielter. Mit tput cup ZEILE SPALTE springt der Cursor an eine bestimmte Position, ohne den Rest des Bildschirms zu löschen, was ermöglicht, nur die Werte zu aktualisieren, die sich tatsächlich geändert haben.
tput clear löscht den gesamten Bildschirm einmalig beim Start, tput civis blendet den blinkenden Cursor während der Laufzeit aus, und tput cnorm stellt ihn beim Beenden wieder her. Diese drei Befehle zusammen mit einer eigenen Refresh-Loop (siehe Abschnitt sieben) ergeben ein Bash Terminal-Dashboard, das deutlich professioneller wirkt als eine reine watch-Lösung, weil einzelne Zahlen aktualisiert werden, statt den ganzen Bildschirm zu leeren.
#!/usr/bin/env bash
set -euo pipefail
readonly ROW_TOTAL=3
readonly ROW_ERRORS=4
readonly ROW_RATE=5
draw_static_layout() {
tput clear
tput cup 1 2; echo "=== Log Analytics Dashboard ==="
tput cup "$ROW_TOTAL" 2; echo "Total requests:"
tput cup "$ROW_ERRORS" 2; echo "5xx errors:"
tput cup "$ROW_RATE" 2; echo "Error rate:"
}
update_value() {
local row="$1" col="$2" value="$3"
tput cup "$row" "$col"
printf "%-20s" "$value" # pad to overwrite any leftover characters
}
draw_static_layout
while true; do
total=$(( RANDOM % 500 + 100 ))
errors=$(( RANDOM % 20 ))
rate=$(awk -v e="$errors" -v t="$total" 'BEGIN { printf "%.1f", (e/t)*100 }')
update_value "$ROW_TOTAL" 20 "$total"
update_value "$ROW_ERRORS" 20 "$errors"
update_value "$ROW_RATE" 20 "${rate}%"
sleep 2
done
5. ANSI-Farben für Schwellenwerte und Status-Ampeln
Reine Zahlen in einem Bash Terminal-Dashboard zwingen den Betrachter, jeden Wert gedanklich gegen einen Schwellenwert zu prüfen. Farbe übernimmt diese Bewertung visuell und sofort erkennbar. ANSI-Escape-Codes wie \033[31m für Rot, \033[33m für Gelb und \033[32m für Grün, gefolgt von \033[0m zum Zurücksetzen, reichen aus, um jeden Wert im Bash Terminal-Dashboard nach Schwellenwert einzufärben.
Wichtig ist, diese Farblogik in einer Funktion zu bündeln, statt Escape-Codes über das Skript zu verstreuen. Eine Funktion colorize, die einen Wert und zwei Schwellenwerte entgegennimmt und die passende Farbe zurückgibt, macht ein Bash Terminal-Dashboard wartbar und konsistent, weil die Schwellenwertlogik an einer einzigen Stelle definiert ist.
#!/usr/bin/env bash
set -euo pipefail
readonly RED=$'\033[31m'
readonly YELLOW=$'\033[33m'
readonly GREEN=$'\033[32m'
readonly RESET=$'\033[0m'
colorize_rate() {
local rate="$1"
local color="$GREEN"
awk -v r="$rate" 'BEGIN { exit !(r >= 10) }' && color="$RED"
awk -v r="$rate" 'BEGIN { exit !(r >= 3 && r < 10) }' && color="$YELLOW"
printf "%s%s%%%s" "$color" "$rate" "$RESET"
}
error_rate="7.4"
echo "Error rate: $(colorize_rate "$error_rate")"
Diese Farbcodierung, konsequent auf jede Kennzahl im Bash Terminal-Dashboard angewendet, verwandelt eine Zahlenkolonne in ein auf den ersten Blick lesbares Ampelsystem, ganz ohne Browser oder grafische Bibliothek.
6. Sparklines und Mini-Trends im Terminal zeichnen
Ein einzelner aktueller Wert verrät nichts über den Trend. Eine Sparkline, eine winzige Trendlinie aus Unicode-Blockzeichen, zeigt den Verlauf der letzten Messwerte in einer einzigen Textzeile. Für ein Bash Terminal-Dashboard ist das die kompakteste Form, eine Zeitreihe darzustellen, ohne ein komplettes Diagramm zu zeichnen.
Die Technik: Ein Array von acht Unicode-Blockzeichen mit steigender Höhe (▁▂▃▄▅▆▇█) wird per Index anhand des normalisierten Werts ausgewählt. Für eine Reihe von Messwerten wird jeder Wert auf einen Index zwischen null und sieben abgebildet, das entsprechende Zeichen aneinandergereiht ergibt die Sparkline.
#!/usr/bin/env bash
set -euo pipefail
readonly BLOCKS=("▁" "▂" "▃" "▄" "▅" "▆" "▇" "█")
render_sparkline() {
local values=("$@")
local max=0
for v in "${values[@]}"; do (( v > max )) && max=$v; done
(( max == 0 )) && max=1
local sparkline=""
for v in "${values[@]}"; do
local index=$(( v * 7 / max ))
sparkline+="${BLOCKS[$index]}"
done
echo "$sparkline"
}
# Sample: error counts for the last 10 monitoring windows
error_history=(2 3 1 5 8 12 9 4 2 1)
echo "Error trend: $(render_sparkline "${error_history[@]}")"
Eine Sparkline in einem Bash Terminal-Dashboard lässt sich mit dem Aggregations-Pattern aus Abschnitt drei kombinieren: Statt nur die letzten zehn Minuten als Tabelle auszugeben, wird dieselbe Datenreihe zusätzlich als Sparkline neben der Kennzahl gerendert, sodass der Trend auf einen Blick erkennbar ist.
7. Eigene Refresh-Loop statt watch für mehr Kontrolle
Sobald ein Bash Terminal-Dashboard mehrere Datenquellen kombiniert, Tastatureingaben verarbeiten soll (etwa Pause mit der Leertaste) oder eine variable Refresh-Rate je nach Systemlast braucht, stößt watch an seine Grenzen. Eine eigene Endlosschleife mit trap für sauberes Beenden und read -t für nicht blockierende Tastatureingabe gibt die volle Kontrolle über das Verhalten des Dashboards.
Der Cursor wird beim Start mit tput civis ausgeblendet und beim Beenden über einen trap auf EXIT mit tput cnorm zuverlässig wiederhergestellt, selbst wenn das Skript mit Strg+C abgebrochen wird. Das ist bei einem Bash Terminal-Dashboard besonders wichtig, weil ein verschwundener Cursor nach einem abgebrochenen Skript ein häufiges und störendes Ärgernis für den Benutzer ist.
#!/usr/bin/env bash
set -euo pipefail
cleanup() {
tput cnorm # restore cursor visibility
tput sgr0 # reset all text attributes
echo
}
trap cleanup EXIT INT TERM
tput civis
tput clear
refresh_interval=2
paused=false
while true; do
if [[ "$paused" == false ]]; then
tput cup 0 0
echo "Dashboard running — press 'p' to pause, 'q' to quit"
# ... render metrics here ...
fi
# Non-blocking read: wait up to $refresh_interval seconds for a keypress
if read -r -t "$refresh_interval" -n 1 key; then
case "$key" in
p|P) paused=true ;;
r|R) paused=false ;;
q|Q) break ;;
esac
fi
done
8. Performance bei wachsenden Log-Dateien im Griff behalten
Ein Bash Terminal-Dashboard, das bei jedem Refresh die komplette Log-Datei neu einliest, wird bei großen Dateien spürbar langsamer, je länger der Dienst läuft. Für Dateien im Gigabyte-Bereich ist ein vollständiger Scan alle paar Sekunden nicht praktikabel. Die Lösung ist, nur den seit dem letzten Durchlauf neu hinzugekommenen Teil der Datei zu lesen, ähnlich wie es tail -f intern macht, aber mit eigener Byte-Offset-Verfolgung.
Die Byte-Position wird nach jedem Durchlauf in einer Zustandsdatei gespeichert, und beim nächsten Durchlauf liest dd oder tail -c +OFFSET nur den neuen Abschnitt. Für ein Bash Terminal-Dashboard, das kontinuierlich läuft, ist dieser inkrementelle Ansatz der Unterschied zwischen konstanter Reaktionszeit und einer Verlangsamung, die mit der Größe der Log-Datei linear wächst.
#!/usr/bin/env bash
set -euo pipefail
readonly LOG_FILE="/var/log/app/access.log"
readonly STATE_FILE="/tmp/dashboard-offset.state"
last_offset=0
[[ -f "$STATE_FILE" ]] && last_offset="$(cat "$STATE_FILE")"
current_size="$(stat -c%s "$LOG_FILE")"
# Log rotated (file shrank) — restart from the beginning
(( current_size < last_offset )) && last_offset=0
new_lines="$(tail -c +$((last_offset + 1)) "$LOG_FILE")"
echo "$current_size" > "$STATE_FILE"
new_error_count="$(echo "$new_lines" | awk '$2 >= 500' | wc -l)"
echo "New errors since last check: $new_error_count"
9. Terminal-Dashboard im Vergleich zu Grafana und ELK
Ein Bash Terminal-Dashboard konkurriert nicht direkt mit einem vollständigen Observability-Stack, sondern deckt eine andere Nische ab: schnelle, lokale Diagnose ohne Setup-Aufwand. Die folgende Tabelle stellt die wichtigsten Unterschiede gegenüber.
| Kriterium | Bash Terminal-Dashboard | Grafana | ELK-Stack |
|---|---|---|---|
| Setup-Zeit | Sekunden | Stunden | Tage |
| Zugriff via SSH ausreichend | Ja | Nein, Browser nötig | Nein, Browser nötig |
| Historische Daten, Retention | Nicht vorgesehen | Voll unterstützt | Voll unterstützt |
| Mehrere Server gleichzeitig | Nur ein Host pro Session | Zentrale Sicht | Zentrale Sicht |
| Betriebsaufwand | Keiner | Mittel | Hoch |
Für die schnelle Diagnose eines einzelnen Servers während eines Incidents ist ein Bash Terminal-Dashboard praktisch konkurrenzlos schnell einsatzbereit. Für langfristige Trends über viele Server hinweg bleibt ein zentrales Observability-Tool die richtige Wahl, beide Ansätze schließen sich nicht gegenseitig aus.
Mironsoft
Shell-Automatisierung, Monitoring und Deployment-Infrastruktur
Log-Diagnose in Sekunden statt über den Browser?
Wir bauen maßgeschneiderte Terminal-Dashboards für eure Log-Analytics, mit Farbcodierung, Sparklines und effizienter Verarbeitung auch großer Log-Dateien, einsatzbereit über jede SSH-Session.
Dashboard-Design
tput-Layouts mit Farbcodierung und Sparklines für eure Kennzahlen
Effiziente Log-Verarbeitung
Inkrementelles Lesen großer Dateien, auch bei Log-Rotation stabil
Kein zusätzlicher Betrieb
Reine Bash-Skripte ohne dauerhaft laufende Zusatzdienste
10. Zusammenfassung
Ein Bash Terminal-Dashboard für Log-Analytics beginnt mit dem simplen watch-Kommando, das ein Skript in festen Intervallen wiederholt. Für ruhigere, professionellere Darstellungen übernimmt tput die gezielte Cursor-Positionierung, sodass nur geänderte Werte neu gezeichnet werden statt des gesamten Bildschirms. ANSI-Farbcodes verwandeln nackte Zahlen in ein sofort lesbares Ampelsystem, Sparklines aus Unicode-Blockzeichen zeigen Trends in einer einzigen Textzeile.
Für anspruchsvollere Anforderungen wie Tastatureingabe oder variable Refresh-Raten ersetzt eine eigene Endlosschleife mit trap und read -t das starre watch-Kommando. Bei wachsenden Log-Dateien verhindert inkrementelles Lesen mit Byte-Offset-Tracking, dass die Performance mit der Dateigröße linear absackt. Ein Bash Terminal-Dashboard ersetzt kein zentrales Observability-Tool für langfristige Trends über viele Server, ist aber für die schnelle Diagnose eines einzelnen Systems oft die pragmatischste Lösung.
Terminal-Dashboards für Log-Analytics: Das Wichtigste auf einen Blick
Einstieg
watch -n 5 -d ./skript.sh liefert bereits ein funktionierendes Live-Dashboard mit Delta-Hervorhebung.
Layout ohne Flackern
tput cup positioniert den Cursor gezielt, nur geänderte Werte werden neu geschrieben.
Visualisierung
ANSI-Farben für Schwellenwerte, Sparklines aus Unicode-Blöcken für Trends in einer Zeile.
Skalierung
Byte-Offset-Tracking für inkrementelles Lesen, damit große Log-Dateien nicht ausbremsen.