Ich habe ein Programm, dessen Ausgabe ich in eine Protokolldatei umleite:
./my_app > log
Ich möchte das Protokoll von Zeit zu Zeit löschen (dh leeren) (auf Anfrage) und verschiedene Dinge ausprobieren wie
cat "" > log
Es scheint jedoch immer, dass die ursprüngliche Pipe dann unterbrochen wird und das Programm seine Ausgabe nicht mehr in die Protokolldatei umleitet.
Gibt es eine Möglichkeit, das zu tun?
Aktualisieren
Beachten Sie, dass ich die Anwendung, die die Ausgabe erzeugt, nicht ändern kann. Es wird nur als Standard ausgegeben, und ich möchte es in einem Protokoll speichern, damit ich es bei Bedarf überprüfen und löschen kann, wenn ich möchte. Allerdings sollte ich die Anwendung nicht neu starten müssen.
bash
io-redirection
Bangnab
quelle
quelle
syslogd
oderlogrotate
./my_app >> log
Anhängen erzwingen undcp /dev/null log
abschneiden?cat "" > log
kein gültigercat
Befehl, da keine Datei aufgerufen wird""
.Antworten:
Eine andere Form dieses Problems tritt bei lang laufenden Anwendungen auf, deren Protokolle regelmäßig gewechselt werden. Auch wenn Sie das ursprüngliche Protokoll verschieben (z. B.
mv log.txt log.1
) verschieben und sofort durch eine Datei mit dem gleichen Namen ersetzen, bevor eine tatsächliche Protokollierung erfolgt, wird beim Öffnen der Datei entweder in das Protokoll geschriebenlog.1
(da dies möglicherweise immer noch der Fall ist) die offene inode) oder nichts.Ein üblicher Weg, um damit umzugehen (der Systemlogger selbst funktioniert auf diese Weise), ist die Implementierung eines Signal-Handlers in dem Prozess, der seine Protokolle schließt und wieder öffnet. Wenn Sie dann das Protokoll verschieben oder löschen möchten (indem Sie es löschen), senden Sie das Signal sofort danach an den Prozess.
Hier ist eine einfache Demonstration für bash - verzeihen Sie meine groben Shell-Fähigkeiten (aber wenn Sie dies für Best Practices usw. bearbeiten wollen, stellen Sie bitte sicher, dass Sie die Funktionalität zuerst verstehen und Ihre Revision testen, bevor Sie sie bearbeiten):
Beginnen Sie dies, indem Sie in den Hintergrund treten:
Beachten Sie, dass es seine PID an das Terminal meldet und dann mit der Protokollierung beginnt
log.txt
. Sie haben jetzt 2 Minuten Zeit, um herumzuspielen. Warte ein paar Sekunden und versuche:kill -2 12356
Vielleicht funktioniert auch hier einfach alles für Sie. Signal 2 ist SIGINT (es ist auch das, was Ctrl-C tut, also können Sie dies im Vordergrund versuchen und die Protokolldatei von einem anderen Terminal verschieben oder entfernen), was dertrap
Trap ausführen soll. Überprüfen;Nun wollen wir sehen, ob es noch in a schreibt,
log.txt
obwohl wir es verschoben haben:Beachten Sie, dass es dort weiterging, wo es aufgehört hat. Wenn Sie die Aufzeichnung nicht behalten möchten, löschen Sie einfach das Protokoll, indem Sie es löschen
Prüfen:
Geht immer noch.
Dies ist in einem Shell-Skript für einen ausgeführten Unterprozess leider nicht möglich, da die bash-eigenen Signal-Handler (
trap
angehalten werden und Sie nicht neu zuweisen können, wenn Sie sie in den Hintergrund stellen Ausgabe. Das heißt, dies ist etwas, das Sie in Ihrer Anwendung implementieren müssen.Jedoch...
Wenn Sie die Anwendung nicht ändern können (z. B. weil Sie sie nicht geschrieben haben), habe ich ein CLI-Dienstprogramm, das Sie als Vermittler verwenden können. Sie können auch eine einfache Version davon in einem Skript implementieren, das als Pipe zum Protokoll dient:
Nennen wir das mal
pipetrap.sh
. Jetzt benötigen wir ein separates Programm zum Testen, das die zu protokollierende Anwendung imitiert:Das wird sein
test.sh
:Dies sind zwei separate Prozesse mit separaten PIDs. So löschen Sie
test.sh
die Ausgabe, die übertragen wirdpipetrap.sh
:Prüfen:
15858
test.sh
läuft noch und die Ausgabe wird protokolliert. In diesem Fall sind keine Änderungen an der Anwendung erforderlich.quelle
TL; DR
Öffnen Sie Ihre Protokolldatei im Anhänge- Modus:
Dann können Sie es sicher abschneiden mit:
Einzelheiten
Bei einer Bourne-ähnlichen Shell gibt es drei Möglichkeiten, wie eine Datei zum Schreiben geöffnet werden kann. In write-only (
>
), read + write (<>
) oder append (und write-only,>>
) Modus.In den ersten beiden merkt sich der Kernel Ihre aktuelle Position (von Ihnen meine ich die offene Dateibeschreibung) , die von allen Dateideskriptoren geteilt wird, die sie dupliziert oder geerbt haben, indem sie von abgezweigt wurden, auf der Sie die Datei geöffnet haben) Datei.
Wenn Sie das tun:
log
ist im schreibgeschützten Modus von der Shell für die Standardausgabe von geöffnetcmd
.cmd
Wenn Sie in ihre Standardausgabe schreiben, schreiben Sie an die aktuelle Cursorposition, die in der geöffneten Dateibeschreibung enthalten ist sie für diese Datei freigeben.Wenn Sie zum Beispiel
cmd
anfänglich schreibenzzz
, befindet sich die Position bei Byte-Offset 4 in der Datei und beim nächsten Malcmd
oder die untergeordneten Elemente in die Datei geschrieben werden, werden die Daten dort geschrieben, unabhängig davon, ob die Datei im Intervall gewachsen oder geschrumpft ist .Wenn die Datei verkleinert wurde, z. B. wenn sie mit einem abgeschnitten wurde
und
cmd
schreibtxx
, diejenigenxx
geschrieben wird bei Offset4
, und die ersten drei Zeichen durch NUL - Zeichen ersetzt werden.Das bedeutet, dass Sie eine Datei, die nur im Schreibmodus geöffnet wurde (und dies gilt auch für Lesen + Schreiben ), nicht abschneiden können Datei (diese Dateien, mit Ausnahme von OS / X, belegen normalerweise keinen Speicherplatz auf der Festplatte, sondern werden zu spärlichen Dateien).
Stattdessen (und Sie werden feststellen, dass die meisten Anwendungen dies tun, wenn sie in Protokolldateien schreiben), sollten Sie die Datei im Anhänge- Modus öffnen :
oder
wenn Sie mit einer leeren Datei beginnen möchten.
Im Anhänge-Modus werden alle Schreibvorgänge am Ende der Datei ausgeführt, unabhängig davon, wo sich der letzte Schreibvorgang befand:
Das ist auch sicherer, als hätten zwei Prozesse versehentlich die Datei geöffnet (zum Beispiel, wenn Sie zwei Instanzen desselben Daemons gestartet haben), so dass sich deren Ausgabe nicht gegenseitig überschreibt.
Auf neueren Versionen von Linux, können Sie die aktuelle Position überprüfen und ob ein Dateideskriptor in geöffnet war append - Modus an , indem Sie
/proc/<pid>/fdinfo/<fd>
:Oder mit:
Diese Flags entsprechen den O ..._-Flags, die an den
open
Systemaufruf übergeben wurden.(
O_APPEND
ist 0x400 oder oktal 02000)So ist die Shell
>>
die Datei mit öffnetO_WRONLY|O_APPEND
(und 0.100.000 hier ist O_LARGEFILE, die diese Frage nicht relevant ist) , während>
istO_WRONLY
nur (und<>
istO_RDWR
nur).Wenn Sie Folgendes tun:
Um nach Dateien zu suchen, die mit geöffnet sind
O_APPEND
, finden Sie die meisten Protokolldateien, die derzeit auf Ihrem System zum Schreiben geöffnet sind.quelle
:
(Doppelpunkt) in: >
?:
. Ohne einen Befehl variiert das Verhalten zwischen den Shells.Wenn ich das richtig verstehe,
tee
scheint das ein vernünftiger Ansatz zu sein:quelle
Als schnelle Lösung können Sie ein Protokoll mit Rotation verwenden (zum Beispiel tägliche Rotation):
und leiten Sie die Protokollierung darauf um
./my_app >> log$date.log
quelle
Dies ist ein Problem, das seit langem mit syslog (in allen Varianten) behoben wurde. Es gibt jedoch zwei Tools, mit denen Sie Ihr spezielles Problem mit minimalem Aufwand lösen können.
Die erste, portablere, aber weniger vielseitige Lösung ist der Logger (ein Muss für jede Administratoren-Toolbox). Es ist ein einfaches Dienstprogramm, das Standardeingaben in syslog kopiert. (Weitergeben des Geldes und Drehen von Dateien zum Problem von logrotate und syslog machen)
Die zweite, elegantere, aber weniger tragbare Lösung ist syslog-ng, mit der nicht nur Protokollnachrichten von den Standard-Syslog-Sockets akzeptiert werden, sondern auch Programme ausgeführt werden können, deren Ausgabe über den Logger gefiltert wird. (Ich habe diese Funktion noch nicht verwendet, aber sie sieht perfekt für das aus, was Sie tun möchten.)
quelle