Speichern Sie die Ausgabe eines Befehls in einem Ringpuffer

16

Ich habe einen lang laufenden Befehl, der eine Menge Ausgabe auf stdout erzeugt. Ich möchte zum Beispiel nur die letzten drei Tage oder das letzte Gibibyte (ohne Schnittlinien in der Mitte) und wenn möglich in Datei-Chunks von nicht mehr als 20 MiB speichern können. Jeder Datei-Chunk wird mit einem numerischen Suffix oder einem Zeitstempel benannt.

Etwas wie:

my-cmd | magic-command --output-file-template=my-cmd-%t \
                       --keep-bytes=1G \
                       --keep-time=3d \
                       --max-chunk-size=20M \
                       --compress=xz

Würde schreiben:

my-cmd-2014-09-05T10:04:23Z

Wenn es 20 Millionen erreicht, wird es komprimiert und ein neues geöffnet, und nach einer Weile werden die ältesten Dateien gelöscht.

Existiert ein solcher Befehl?

Ich bin mir logrotatedessen bewusst und seiner Fähigkeit, von anderen Anwendungen geschriebene Dateien zu verwalten, aber ich suche nach etwas Einfacherem, bei dem ich keinen Cron-Job einrichten, Regeln festlegen, den Prozess anhalten usw. muss.

Stéphane Chazelas
quelle
Was ist ein Gibibyte?
Peter Mortensen
@PeterMortensen Wikipedia: Gibibyte
jw013

Antworten:

6

Sie können einige der gewünschten Informationen über das Pipelog abrufen , das "das Drehen oder Löschen des Protokolls eines laufenden Prozesses ermöglicht, indem es über ein Zwischenprodukt weitergeleitet wird, das auf externe Signale reagiert", z.

spewstuff | pipelog spew.log -p /tmp/spewpipe.pid -x "gzip spew.log.1"

Sie können dann die PID von erhalten /tmp/spewpipe.pid, und:

kill -s USR1 $(</tmp/spewpipe.pid)

Aber das müsstest du mit cron oder so einrichten. Das hat jedoch einen Haken. Hinweis I gzip spew.log.1- Dies liegt daran, dass der -xBefehl ausgeführt wird, nachdem das Protokoll gedreht wurde. Sie haben also das weitere Problem, spew.log.1.gzjedes Mal zu überschreiben, es sei denn, Sie schreiben ein kurzes Skript, um den gzip auszuführen und die Datei anschließend zu verschieben, und verwenden dieses als -xBefehl.

Vollständige Offenlegung: Ich habe dies geschrieben, daher funktioniert es natürlich perfekt . ;) Ich werde eine Komprimierungsoption für Version 0.2 im Hinterkopf behalten oder etwas, das dies besser erleichtert (der beabsichtigte Zweck von -xist etwas anders, aber es funktioniert wie oben). Auch automatisiertes Rollover ist eine gute Idee ... die erste Version ist absichtlich minimal, da ich der Versuchung widerstand, Funktionen hinzuzufügen, die nicht notwendig waren (es ist schließlich nicht so schwer, einen Cron-Job dafür einzurichten).

Beachten Sie, dass es für die Textausgabe vorgesehen ist . Wenn es potenzielle Null-Bytes gibt, sollten Sie verwenden, -zdie die Null durch etwas anderes ersetzt. Dies war ein Kompromiss, um die Implementierung zu vereinfachen.

Goldlöckchen
quelle
Vielen Dank. Ich freue mich darauf pipelog-0.3;-). Ich bin auch auf metacpan.org/release/File-Write-Rotate gestoßen . Beachten Sie, dass Cron-Jobs beim Drehen auf der Grundlage der Dateigröße nicht viel helfen.
Stéphane Chazelas
Drehen nach Größe!?! Es hält die Ausgabe gespült, so dass Sie die Datei in Abständen stat ...
Goldlöckchen
Auf diese Weise konnte die Größe (wie in meinen Fragenanforderungen) nicht zuverlässig unter 20 MB gehalten werden.
Stéphane Chazelas
Die andere Sache ist, dass es so ziemlich nur Text ist (ich habe einen letzten Absatz dazu hinzugefügt).
Goldlöckchen
4

Dan Bernsteins Multilog kann dies anscheinend tun - oder vielleicht das meiste davon, während er dem Prozessor einen Ausgang über Dateideskriptoren zur Verfügung stellt , um den Unterschied zu kompensieren, wie Sie möchten - obwohl die Größenangaben für 20M / 1G möglicherweise ein wenig ins Wanken geraten, da es den Anschein haben, dass es sich um 16M handelt Außengrenze pro Protokoll. Was folgt , ist in der Mehrzahl, + eine Kopie Auswahl aus dem obigen Link einfügen, obwohl auch der Link andere Optionen Details wie timestamping pro Zeile, die Aufrechterhaltung [eine] andere Datei [s] nur die letzte Leitungsanpassung enthält , Muster und mehr .

Schnittstelle

 multilog script

... Skript besteht aus beliebig vielen Argumenten. Jedes Argument gibt eine Aktion an. Die Aktionen werden für jede Eingabezeile in der richtigen Reihenfolge ausgeführt.

Linien auswählen

Jede Zeile ist anfänglich ausgewählt. Die Aktion...

-pattern

... hebt die Auswahl der Linie auf, wenn das Muster mit der Linie übereinstimmt. Die Aktion...

+pattern

Wählt die Linie aus, wenn das Muster mit der Linie übereinstimmt.

... Muster ist eine Reihe von Sternen und Nicht-Sternen. Es stimmt mit jeder Verkettung von Zeichenfolgen überein, die von allen Sternen und Nicht-Sternen in derselben Reihenfolge abgeglichen werden. Ein Nicht-Star passt zu sich. Ein Stern vor dem Ende des Musters entspricht einer Zeichenfolge, die nicht das nächste Zeichen im Muster enthält. Ein Stern am Ende des Musters entspricht einer beliebigen Zeichenfolge.

Automatisch gedrehte Protokolle

Wenn dir mit einem Punkt oder Schrägstrich beginnt, dann ist die Aktion ...

 dir

... hängt jede ausgewählte Zeile an ein Protokoll mit dem Namen dir an . Wenn dir nicht existiert, multilogwird es erstellt.

Das Protokollformat lautet wie folgt:

  1. dir ist ein Verzeichnis, das einige alte Protokolldateien, eine Protokolldatei mit dem Namen current und andere Dateien enthält multilog, um die Aktionen zu verfolgen.

  2. Jede alte Protokolldatei hat einen Namen, der mit @ beginnt , mit einem genauen Zeitstempel fortfährt, der anzeigt, wann die Datei fertig ist, und mit einem der folgenden Codes endet:

    • .s : Diese Datei wird vollständig verarbeitet und sicher auf die Festplatte geschrieben.
    • .u : Diese Datei wurde im Moment eines Ausfalls erstellt. Möglicherweise wurde es abgeschnitten. Es wurde nicht verarbeitet.

Die Aktion...

 ssize

... legt die maximale Dateigröße für nachfolgende dir- Aktionen fest. multilogwird entscheiden , dass Strom ist groß genug , wenn Strom hat eine Größe bytes. ( multilogEntscheidet auch, dass current groß genug ist, wenn eine neue Zeile innerhalb von 2000 Byte der maximalen Dateigröße angezeigt wird. Es wird versucht, die Protokolldateien an den Zeilengrenzen zu beenden.) Die Größe muss zwischen 4096 und 16777215 liegen. Die maximale Standarddateigröße beträgt 99999.

In den Versionen 0.75 und höher: Wenn multilogein ALRM- Signal empfangen wird, wird sofort entschieden, dass der Strom groß genug ist, wenn der Strom nicht leer ist.

(Hinweis: Ich vermute, dass das zsh scheduleeingebaute Programm leicht dazu gebracht werden kann, ALRMbei Bedarf in bestimmten Abständen ein E-Mail zu senden .)

Die Aktion...

 nnum

... legt die Anzahl der Protokolldateien für nachfolgende Verzeichnisaktionen fest . Nach der Umbenennung Strom , wenn multilogsieht num oder mehrere alte Log - Dateien, entfernt es die alte Protokolldatei mit dem kleinsten Zeitstempel. num muss mindestens 2 sein. Die Standardanzahl der Protokolldateien beträgt 10.

Die Aktion...

 !processor

... setzt einen Prozessor für nachfolgende dir- Aktionen. multilogspeist Strom durch den Prozessor und speichert die Ausgabe als alte Protokolldatei anstelle von Strom . multilogspeichert auch alle Ausgaben, die der Prozessor in Deskriptor 5 schreibt, und macht diese Ausgabe für Deskriptor 4 lesbar, wenn der Prozessor in der nächsten Protokolldatei ausgeführt wird. Aus Gründen der Zuverlässigkeit muss der Prozessor den Modus ungleich Null beenden, wenn beim Erstellen der Ausgabe Probleme auftreten. multilogwerde es dann nochmal laufen lassen. Beachten Sie, dass der laufende Prozessor möglicherweise alle Programmeingaben blockiert multilog.

mikeserv
quelle
2

Das Beste, was ich bisher als Näherungswert finden konnte, bei dem es nicht darum geht, große Codestücke zu schreiben, ist dieser zshCode:

autoload zmv
mycmd |
  while head -c20M > mycmd.log && [ -s mycmd.log ]; do
    zmv -f '(mycmd.log)(|.(<->))(|.gz)(#qnOn)' '$1.$(($3+1))$4'
    {rm -f mycmd.log.1 mycmd.log.50.gz; (gzip&) > mycmd.log.1.gz} < mycmd.log.1
  done

Hier aufteilen und in maximal 51 20MiB große Dateien drehen.

Stéphane Chazelas
quelle
vielleicht ... loopmounts? btrfsKann auch mit montiert werden compress-force=zlib.
mikeserv
2

Hier ist ein gehacktes Python-Skript, um etwas zu tun, was Sie verlangen:

#!/bin/sh
''':'
exec python "$0" "$@"
'''

KEEP = 10
MAX_SIZE = 1024 # bytes
LOG_BASE_NAME = 'log'

from sys import stdin
from subprocess import call

log_num = 0
log_size = 0
log_name = LOG_BASE_NAME + '.' + str(log_num)
log_fh = open(log_name, 'w', 1)

while True:
        line = stdin.readline()
        if len(line) == 0:
                log_fh.close()
                call(['gzip', '-f', log_name])
                break
        log_fh.write(line)
        log_size += len(line)
        if log_size >= MAX_SIZE:
                log_fh.close()
                call(['gzip', '-f', log_name])
                if log_num < KEEP:
                        log_num += 1
                else:
                        log_num = 0
                log_size = 0
                log_name = LOG_BASE_NAME + '.' + str(log_num)
                log_fh = open(log_name, 'w', 1)
Mark Wagner
quelle
1
Gibt es einen Grund, es als Shell-Skript zu verwenden, bei dem execPython das erste ist, anstatt das pythonoder das env pythonHashbang zu verwenden?
Peterph