Hoe lees ik stdout van een subprocess in, zonder te wachten tot het subproces termineerd?
Ik heb een Python programma dat een ander proces start.
Dat andere proces genereert heel veel output. Met veel bedoel ik 1 terrabyte.
Van die output wil ik de laatste 100 megabyte op schijf bewaren.
Ik kan niet voorspellen wat de laatste 100 mb is, en ik moet dus permanent de laatste 100 mb bij houden, bij voorkeur in handzame files van 10 mb per stuk.
Het hoeft niet precies 100 mb te zijn, 50 of 200 is net zo goed, als ik maar een flink stuk van het einde heb.
Hoe doe ik dat?
Ik had zelf het idee om de Python logging module te gebruiken, die zorgt in ieder geval voor het opslaan in files en het roteren van die files. Dat werkt op zich als een trein, maar ik krijg de output van mijn subprocess er niet in geperst. De subprocess module die ik gebruik wil een pipe of een file object hebben om stdout naar toe te sturen. Ik dacht dat ik het prachtig voor elkaar had, maar het werkt niet.
Tijd voor wat code:
Het probleem is dat mijn StdWrapper geen echt file object is.
Specifiek omdat Popen gebruik maakt van de .fileno() functie van file-objects.
Ik zie niet in hoe ik daar om heen kan. Ik kan die functie wel aanmaken, maar daarmee geeft hij nog geen geldige file handle terug.
Iemand een oplossing?
Het alternatief is een pipe gebruiken. Ik denk dat ik dan een tweede thread moet openen die in een loop uit die pipe probeert te lezen. Dat is een oplossing die ik liever niet gebruik, het voelt als te ingewikkeld voor dit simpele probleem, en lezen uit pipes is altijd maar gedoe.
PS. Ik ken Popen.communicate(), het grote probleem dat die wacht tot het subprocess klaar is, en in de tussentijd alles in je geheugen probeert op te slaan, wat in mijn geval geen optie is (tenzij iemand een paar terrabyte ram over heeft). De handleiding waarschuwt er specifiek voor om deze functie niet te gebruiken als je veel output hebt. Wat je dan wel moet doen vermelden ze niet.
PS2. Als het echt niet anders gaat dan maak ik wel een extra proces aan dat stdin naar een logfile weg schrijft en dan pipe ik het daar wel door. Ter leringe ende vermaeke zou ik echter graag een nette Python oplossing zien.
Ik heb een Python programma dat een ander proces start.
Dat andere proces genereert heel veel output. Met veel bedoel ik 1 terrabyte.
Van die output wil ik de laatste 100 megabyte op schijf bewaren.
Ik kan niet voorspellen wat de laatste 100 mb is, en ik moet dus permanent de laatste 100 mb bij houden, bij voorkeur in handzame files van 10 mb per stuk.
Het hoeft niet precies 100 mb te zijn, 50 of 200 is net zo goed, als ik maar een flink stuk van het einde heb.
Hoe doe ik dat?
Ik had zelf het idee om de Python logging module te gebruiken, die zorgt in ieder geval voor het opslaan in files en het roteren van die files. Dat werkt op zich als een trein, maar ik krijg de output van mijn subprocess er niet in geperst. De subprocess module die ik gebruik wil een pipe of een file object hebben om stdout naar toe te sturen. Ik dacht dat ik het prachtig voor elkaar had, maar het werkt niet.
Tijd voor wat code:
Python:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| class StdWrapper(): def __init__(self, logger): self.logger = logger def fileno(self): return -1 class StdOutWrapper(StdWrapper): def write(self, msg): self.logger.INFO(msg) class StdErrWrapper(StdWrapper): def write(self, msg): self.logger.ERROR(msg) logger = logging.getLogger() subprocess.Popen("echo hoi", stdout=StdOutWrapper(logger), stderr=StdErrWrapper(logger)) |
Het probleem is dat mijn StdWrapper geen echt file object is.
Specifiek omdat Popen gebruik maakt van de .fileno() functie van file-objects.
Ik zie niet in hoe ik daar om heen kan. Ik kan die functie wel aanmaken, maar daarmee geeft hij nog geen geldige file handle terug.
Iemand een oplossing?
Het alternatief is een pipe gebruiken. Ik denk dat ik dan een tweede thread moet openen die in een loop uit die pipe probeert te lezen. Dat is een oplossing die ik liever niet gebruik, het voelt als te ingewikkeld voor dit simpele probleem, en lezen uit pipes is altijd maar gedoe.
PS. Ik ken Popen.communicate(), het grote probleem dat die wacht tot het subprocess klaar is, en in de tussentijd alles in je geheugen probeert op te slaan, wat in mijn geval geen optie is (tenzij iemand een paar terrabyte ram over heeft). De handleiding waarschuwt er specifiek voor om deze functie niet te gebruiken als je veel output hebt. Wat je dan wel moet doen vermelden ze niet.
PS2. Als het echt niet anders gaat dan maak ik wel een extra proces aan dat stdin naar een logfile weg schrijft en dan pipe ik het daar wel door. Ter leringe ende vermaeke zou ik echter graag een nette Python oplossing zien.
This post is warranted for the full amount you paid me for it.