2017-12-21 2 views
0

Ich weiß, dass ähnliche Fragen gefragt worden sind, aber ich konnte nichts finden, das diese bestimmte Situation anspricht.Filterausgabe geschrieben durch T-Stück zur Datei, aber nicht ausgegeben durch T-Stück zur Konsole geschrieben

Ich habe eine Reihe von verschiedenen Python-Skripten, die die logging Bibliothek verwenden (die auf stderr druckt). Diese Skripte werden von einem Bash-Skript aneinandergereiht, das sie sequentiell aufruft und über cron eingeplant ist. Am Ende jedes Laufs sendet das Bash-Skript eine Zusammenfassung der verschiedenen Beendigungscodes per E-Mail und soll verschiedene andere Logging-Nachrichten enthalten (dh wenn es eine critical Level Logging-Vorkommen gibt, sollte es zu dem kommen, was ich anrufe "Cron-Protokoll").

Da der Python-Code selbst ziemlich ausführlich in seiner Protokollierung ist, möchte ich nicht versehentlich ein 5-10MB-Protokoll per E-Mail senden, und ich möchte nur bestimmte Ausgabe, um es in das Cron-Protokoll zu machen. Ich möchte tee verwenden, um die stderr Protokollierung von Python zu filtern, und nur direkte insbesondere Nachrichten an die Cron-Protokoll, aber alle Nachrichten sollten es immer noch auf die Konsole machen.

Für Reproduzierbarkeit, sage ich das folgende Bash-Skript haben:

#!/bin/bash 

LOGPFX="BASH" # if a log msg has this term, put it in CRONLOG 
CRONLOG="cronlog.txt" 

exec 2> >(grep ${LOGPFX} | tee -a ${CRONLOG}) 

# run 
python test.py 

Und hier sind die Inhalte von test.py:

import logging 

def get_logger(): 
    logger = logging.getLogger("testlog") 
    logger.setLevel(logging.INFO) 
    lformat = "%(asctime)s - %(levelname)s - %(module)s - %(funcName)s - %(message)s" 

    handler = logging.StreamHandler() 
    handler.setLevel(logging.INFO) 
    handler.setFormatter(logging.Formatter(lformat)) 

    logger.addHandler(handler) 
    return logger 

if __name__ == '__main__': 
    logger = get_logger() 
    logger.info("Should not appear in console but not cronlog.txt") 
    logger.info("[BASH INFO] Should appear in both") 

Die "[BASH INFO] Should appear in both" Nachricht hat erfolgreich machen zum cron log , aber das Problem besteht darin, dass die erste Protokollierungsnachricht in der Konsolenausgabe vollständig weggelassen wird. Wie kann ich diese Nachrichten filtern, so dass diejenigen, die die grep übergeben, es an die Konsole und das Protokoll machen, während alle anderen es nur an die Konsole schaffen?

Ich weiß, dass dies die Linie ist, die sich ändern muss:

exec 2> >(grep ${LOGPFX} | tee -a ${CRONLOG}) 

Inhalt von cronlog.txt:

$ cat cronlog.txt 
2017-12-21 08:19:39,267 - INFO - test - <module> - [BASH INFO] Should appear in both 

ich auch diese Version der bash getestet haben:

#!/bin/bash 

LOGPFX="BASH" 
CRONLOG="cronlog.txt" 

ftee() { 
    echo "I FOUND THIS: ${1}" 
    echo "$1" >> ${CRONLOG} 
} 

exec 2> >(grep ${LOGPFX} | ftee) 2>&1 

# run 
python test.py 

, die alles ordnungsgemäß an die Konsole leitet, aber nicht die richtige Nachricht in das Protokoll schreibt (Die "I FOUND THIS: ${1}" Linie druckt eine leere Zeichenkette)

+0

'ftee' offensichtlich gebrochen ist - siehe [BashFAQ # 1] (http: //mywiki.wooledge .org/BashFAQ/001) als Anleitung zum Lesen von stdin, vs. der Befehlszeile (die es ab sofort liest, obwohl auf seiner Kommandozeile nichts übergeben wurde). –

Antwort

1

tee schreiben an einen anderen Prozess Substitution (die die grep vor dem Schreiben der Fall ist) den Trick:

# all-caps variable names are used for variables with meaning to the shell 
# don't use them for names you assign yourself. 
logpfx="BASH" # if a log msg has this term, put it in CRONLOG 
cronlog="cronlog.txt" 

exec 3>&2 # backup original stderr on FD 3 
exec 2> >(tee -a >(grep "$logpfx" >"$cronlog")) 

Beachten Sie, dass vor die Log-Mailing, Sie sollte sicher sein, den Dateideskriptor zu schließen und es flush zu lassen. Somit wird nach dem Inhalt Sammeln Sie protokollieren möchten und vor E-Mail zu senden, möchten Sie laufen:

exec 2>&3 # restore backup of original FD 3, so tee and grep can exit 
+0

Das ist perfekt!Vielen Dank – Tgsmith61591

+0

Sollte es zuerst '2> & 3' sein (um stderr zu einem anderen Dateideskriptor zu sichern) und dann' 3> & 2' am Ende? Es scheint jetzt rückwärts, aber das könnte mein eigenes schlechtes Verständnis sein. – Tgsmith61591

+0

'3> & 2' macht FD3 zu einer Kopie von FD2. Die Umkehrung -' 2> & 3' - würde stderr (FD2) auf eine FD3 umleiten, die nicht wirklich offen ist. –

Verwandte Themen