Bash logrotate: soll immer nur die Hälfte einer Datei rotieren

:freak: Ok, ich muss wohl mal nach Alternativen zu goaccess suchen, die auch mit rotierten log files umgehen können.

nutrix schrieb:
Ansonsten interessieren die Logs doch nur in Problemfällen.
Ja, stimmt auch wieder, aber möchte halt von Zeit zu Zeit herausfinden, ob es vielleicht problematische Fälle gab. Dafür wäre so ein Tool dann schon ganz praktisch, das zeigt, wie viele Aufrufe eine IP generiert hat.
 
Eine Alternative als Log-Viewer, die ich vorhin gefunden habe, wäre:


Das bietet aber keine Weboberfläche an, und ist irgendwie sehr umständlich zu bedienen ... also ich kam damit noch nicht so klar. Es gibt wohl eine Textsuche, Text-Filter (RegEx), SQL-Filter und Commands. Zudem baut das Teil gleich eine ganze Datenbank auf.

Eine andere Wahl wäre, goaccess nur im Terminal zu nutzen. Nachteil ist aber, dass es keine schönen Diagramme gibt.
 
Habs lösen können:

Bash:
#!/bin/bash
function shrink_file_x_to_y_mb() {
        fn=$1
        limit=$(($2*1000*1000))
        size=$(stat -c%s "$fn")
        lines=$(wc -l "$fn" | awk '{ print $1 }')
        lines_to_del=$((((size-limit)*lines)/size))
        printf "%s %s %s %s %s\n" "$fn" "$limit" "$size" "$lines" "$lines_to_del"
        sed -i 1,"$lines_to_del"d "$fn"
        echo "Successfully!"
}

Wenn ein Log-File zum Beispiel >10 MB geworden ist, kann man das mit 5 MB aufrufen.
Ergänzung ()

Caveats:

  • Es verkleinert die Datei nur "so ungefähr" auf y MB, ggf. muss die Funktion mehrmals aufgerufen werden.
  • Die Zeilen werden gelöscht, nicht rotiert.
  • Docker bzw. Traefik muss über diese Änderung informiert werden.
  • Und es findet keine Überprüfung der Parameter statt.
 
Zuletzt bearbeitet:
Das sollte jetzt richtig bzw. vollständig sein:

Bash:
#!/bin/bash
shrink_file_x_to_y_mb() {
        fn=$1
        limit=$(($2*1000*1000))
        size=$(stat -c%s "$fn")
        if ((limit >= size))
        then
          return 1
        fi
        lines=$(wc -l "$fn" | awk '{ print $1 }')
        lines_to_del=$((((size-limit)*lines)/size))
        if ((lines_to_del <= 0)) || ((lines_to_del > lines))
        then
          return 1
        fi
        printf "%s %s %s %s %s\n" "$fn" "$limit" "$size" "$lines" "$lines_to_del"
        sed -i 1,"$lines_to_del"d "$fn"
        return 0
}

shrink_file_x_to_y_mb_loop() {
        while (shrink_file_x_to_y_mb "$@" == 0)
        do
          printf "Not yet completed\n"
        done
        docker kill --signal="USR1" traefik
        return 0
}
 
Das sieht mir nach möglichem Datenverlust aus, wenn zwischen dem Ersetzen der Datei durch sed -i und dem späteren logreopen mit --signal="USR1" traefik nochmal Daten geschrieben werden. Denn ich gehe davon aus, dass der Filehandle nach dem ersten sed Durchlauf dann verwaist ist. Würde also an der Stelle definitv davon abraten, das so in einer Schleife auszuführen.
 
@simpsonsfan Es geht ja auch ohne die Schleife, indem man nur einmal shrink_file_x_to_y_mb() aufruft ... shrink_file_x_to_y_mb_loop() war eher ein Workaround von mir, falls das Logfile wirklich nicht größer als y MB sein darf. Deine Begründung klingt für mich schlüssig. sed -i ... sollte sich aber atomar verhalten, hoffe ich (also nur ein Aufruf ebenjenem).
Ergänzung ()

Btw. https://doc.traefik.io/traefik/observability/access-logs/#log-rotation :

Traefik will close and reopen its log files, assuming they're configured, on receipt of a USR1 signal. This allows the logs to be rotated and processed by an external program, such as logrotate.
 
sed macht für Inplace (zumindest GNU sed) eine temporäre Datei, die dann anch Beendigung umbenannt wird. Grundlegend wirst du das Problem, dass zwischen dem Austauschen der Datei (mit der halben / abgeschnittenen) und dem Schließen des alten Filehandle und Öffnen des neuen in traefik nochmals Daten geloggt werden könnten, auch bei einmaligem Ausführen haben.

Beim normalen logrotate ist das kein großes Problem, weil dein altes Logfile ja bestehen bleibt (nur unter anderem Namen.) Im Zweifel hast du dann eben eine etwas größere alte Logdatei.
Da sed -i aber das Originalfile löscht, sind dann dahin geschriebene Daten im Zweifel im Nirvana.

Ich glaube, ich würde eher auf inplace verzichten und ein neues File anlegen. Dann könnte dir eben maximal passieren, dass in deinem neuen Logfile ein paar Einträge fehlen, die im alten aber dennoch vorhanden sind.
So wie ich das hier lese, geht es dir ja zunächst nicht um Speicherplatz.

Um es sauberer zu machen, müsstest du den Output von traefik buffern.
Bzw. werfe ich auch nochmal die bereits erähnte Variante in den Raum, deine logs regulär mit logrotate rotieren zu lassen und für goacces einfach jeweils den letzten und den aktuellen log gemeinsam in ein neues file zu pipen.
 
  • Gefällt mir
Reaktionen: Tobias0
Tobias0 schrieb:
Das sollte jetzt richtig bzw. vollständig sein:
Mist, das Ganze war nicht POSIX-konform ...

Bash:
#!/bin/sh
set -e
fn="/var/log/traefik/access.log"
limit=$((20*1000*1000))
size=$(stat -c%s "$fn")
if [ $((limit >= 0 && limit <= size)) = 0 ]
then
  echo "Nothing to do."
  return 1
fi
lines=$(wc -l "$fn" | awk '{ print $1 }')
lines_to_del=$((((size-limit)*lines)/size))
if [ $((lines_to_del > 0 && lines_to_del <= lines)) = 0 ]
then
  echo "Nothing to do."
  return 1
fi
printf "%s %s %s %s %s\n" "$fn" "$limit" "$size" "$lines" "$lines_to_del"
sed -i "1,${lines_to_del}d" "$fn"
docker kill --signal="USR1" traefik
return 0

Man muss aufpassen, wenn man ein #!/bin/bash-Script mit sh aufruft, dann wird es dennoch nicht als bash ausgeführt, sondern als sh, und in Posix geben die Vergleichsoperatoren innerhalb von arithmetischen Ausdruckserweiterungen 1, wenn wahr, und 0, wenn falsch, zurück - das ist genau umgekehrt zu Bash, wo der return value 0==wahr und 1==falsch ist. Kein Plan, weshalb das so ist.
 
Tobias0 schrieb:
Eine Alternative als Log-Viewer, die ich vorhin gefunden habe, wäre:

Sorry, ich einfach bin doof. Man braucht nicht extra einen Log-Viewer dafür, das "Aggregieren" (und Auffinden von Problemkindern) geht auch über die Konsole sehr einfach:

sudo grep " 404 " /var/log/traefik/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | more
 
  • Gefällt mir
Reaktionen: nutrix
Hab mich eh schon gewundert, was Du da groß an GUI brauchst. 🙃😉 Wir machen das teilweise auch genau so, bzw. haben dafür dann SIEM wie ELK oder Splunk und Co. dahinter.
 
nutrix schrieb:
haben dafür dann SIEM wie ELK oder Splunk und Co. dahinter

Nein, das sind komplette Business-Lösungen, bei denen zudem Daten an Dritte weitergegeben werden. Das möchte ich nicht, bzw. ist überdimensioniert für mich.

Meine Frage wäre eher,

1755764704646.png


wo hier die vielen 4xx herkamen, und wieso es 0xx Codes im Log gibt.
 
Tobias0 schrieb:
Nein, das sind komplette Business-Lösungen,
Das war jetzt auch nicht aus Aufruf gedacht, daß Du das so machen sollst, nur für den geneigten Mitleser oder durch Suchmaschine gefundenen, der in dem Umfeld auch zu tun hat und sowas vielleicht nicht kennt. Die Kommandozeile reicht für Dich klar vollkommen aus.
Tobias0 schrieb:
bei denen zudem Daten an Dritte weitergegeben werden.
Nein. Woher hast Du diese Idee?
Tobias0 schrieb:
Anhang anzeigen 1649490
wo hier die vielen 4xx herkamen, und wieso es 0xx Codes im Log gibt.
Daß muß man sich dann im Detail genauer anschauen pro Meldung.
 
nutrix schrieb:
Nein. Woher hast Du diese Idee?
Ich meinte damit, die Analyse läuft remote.

nutrix schrieb:
Daß muß man sich dann im Detail genauer anschauen pro Meldung.

Leider kann ich die einzelnen Einträge nicht weiter aufklappen:

1755765916749.png


Aber, wenn ich es richtig verstehe, so waren dies Client-Requests mit einer extrem langen Antwortzeit, also der Client die Annahme der Antwort verzögert oder gestört hat? (Geht das, bringt das etwas?)

Aber wir bewegen uns jetzt inzwischen ganz schön weit weg von der ursprünglichen Frage (die eigentlich schon gelöst war).
 
Zurück
Oben