Frage zu dateien lesen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Tobbel
User
Beiträge: 14
Registriert: Freitag 7. September 2012, 11:00

Hey ho!
Also ist mein erster Post, verzeiht mir bitte falls ich nicht immer genau das sage was ein erfahrenern progger schreiben würde ;)

Bin nun seit rund 2 Tagen an einem Problem dran und zwar:
Ich lese eine Status datei eines Überwachungsprogrammes ein ( evtl kennt das wer "Nagios"), dort such ich explizit nach einem text also

Code: Alles auswählen

status = open("status.dat", "r") 
	for line in status: 
	    if "plugin_output=OK" in line:
Das funktioniert auch einwandfrei, jetzt muss ich allerdings im raum der nächsten 25 Zeilen nachprüfen ob sich dort ein zweiter benötigter text befindet.

Also in Pseudocode:

Code: Alles auswählen

	status = open("status.dat", "r") 
	for line in status: 
	    if "plugin_output=" in line:
		if "text" in zeilen + 25:  #genau hier ist das Prob...
Hab schon mehrere Ansätze gehabt mit *.readline/s(), auch ein missglückter counter war dabei... und bevor ich nun anfang die anfangs datei in kleiner Datein zu splitten wollte ich nachfragen ob es eine elegante Lösung für meine Idee/Problem gibt :)

Was ich noch dazu sagen sollte , ich hab erst vor 2-3 Tagen mit Python angefangen, also sind mir syntax etc noch nicht ganz geläufig :)

Grüßle Tobbel
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo und willkommen im Forum!

So könntest du das angehen:

Code: Alles auswählen

with open("status.dat") as fp:
    match = None
    for index, line in enumerate(fp):
        if match is None:
            if line.startswith("plugin_output="):
                match = index
        elif match + 25 <= index:
            ....
Vielleicht verrätst du uns aber mal, was du eigentlich vor hast und postest eine Beispieldatei. Vielleicht lässt sich da noch einiges einfacher lösen.

Sebastian
Das Leben ist wie ein Tennisball.
Tobbel
User
Beiträge: 14
Registriert: Freitag 7. September 2012, 11:00

Das is schonmal ne idee, bin ich garnicht drauf gekommen es ersteinmal selber nen Index zu machen :roll:

Also zu der Datei:

Code: Alles auswählen

servicestatus {
        host_name=localhost
        service_description=Current Load
        modified_attributes=2
        check_command=check_load!5.0!4.0!3.0!10.0!6.0!4.0
        check_period=24x7
        notification_period=24x7
        check_interval=5.000000
        retry_interval=1.000000
        event_handler=
        has_been_checked=1
        should_be_scheduled=1
        check_execution_time=0.004
        check_latency=0.065
        check_type=0
        current_state=0
        last_hard_state=0
        last_event_id=19
        current_event_id=21
        current_problem_id=0
        last_problem_id=8
        current_attempt=1
        max_attempts=4
        state_type=1
        last_state_change=1347004244
        last_hard_state_change=1346916726
        last_time_ok=1347017144
        last_time_warning=0
        last_time_unknown=1346942507
        last_time_critical=1347004184
        plugin_output=OK - load average: 0.00, 0.00, 0.00 # <-- das ist das erste Anzeichen nach dem ich suche, danach sollen die weiteren zeilen geprüft werden
        long_plugin_output=
        performance_data=load1=0.000;5.000;10.000;0; load5=0.000;4.000;6.000;0; load15=0.000;3.000;4.000;0;
        last_check=1347017144
        next_check=1347017444
        check_options=0
        current_notification_number=0
        current_notification_id=0
        last_notification=0
        next_notification=0
        no_more_notifications=0
        notifications_enabled=1
        active_checks_enabled=1
        passive_checks_enabled=1
        event_handler_enabled=1
        problem_has_been_acknowledged=0   # <-- das hier muss nach OK abgefragt werden
        acknowledgement_type=0
        flap_detection_enabled=1
        failure_prediction_enabled=1
        process_performance_data=0
        obsess_over_service=0
        last_update=1347007258
        is_flapping=0
        percent_state_change=0.00
        scheduled_downtime_depth=1  # <-- das hier muss auch nach OK abgefragt werden
        __LB_SERVER=0;192.168.121.10
        __LB_PORT=0;7297
        __LB_CUSTOM=0;
        __LB=0;__lb
        }

Die Datei hat davon ca. 1000 abteilungen mit diesem
service..{
...
}

Un innerhalb dieser sparten muss ich die ergebnisse überprüfen,
danke auf jeden fall mal, ich werds so mal ausprobieren :)

Schlussendlich will ich eine Überprüfung machen ob eben ein servicestatus ein Problem, also ein nicht "OK", hat das weder das Attribut " scheduled_downtime_depth=1" noch "problem_has_been_acknowledged=1" hat.

Falls auch nur 1 service gefunden wird der das alles erfüllt soll ein befehl zum betreiben einer USB leuchte an ein Terminal gesendet werden, was kein problem darstellt :)
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Dein Ansatz mit den Zeilen ist viel zu kompliziert und zu fehleranfällig. Das kannst du doch alles prima in einem Dictionary abbilden:

(ungetestet)

Code: Alles auswählen

def parse(filename):
    with open(filename) as fp:
        obj = None
        
        for line in (l.strip() for l in fp):
            if line.endswith("{"):
                obj = {}
            elif line.startswith("}"):
                yield obj
                obj = None
            elif obj is not None and line:
                name, value = line.split("=", 1)
                obj[name] = value

for obj in parse("test.dat"):
    if (obj["plugin_output"].startswith("OK") and
        obj["problem_has_been_acknowledged"] == "1" and
        obj["scheduled_downtime_depth"] == "1"):
        ....
In obj steckt dann immer ein ganzes servicestatus-Object, auf dessen Elemente du einfach über den Namen zugreifen kannst.
Das Leben ist wie ein Tennisball.
Tobbel
User
Beiträge: 14
Registriert: Freitag 7. September 2012, 11:00

Ok, also vorneweg gesagt, mit obj usw. hab ich bisher noch nichts gemacht,aber so wie ich das vom lesen her verstehe :

der obere teil zerlegt die status.dat in kleine servicestatus teile, in denen ich dann weiter mit dem untern (ab "for obj..." ) arbeiten kann, soweit richtig hoffe ich ;)

Nun hab ich ncoh zwei Fragen:
1. wird jeder teil in einem neuen objekt gespeichert so dass python eine neue datei ( im bsp. test.dat) erstellt und dort zwischenspeichert um es später wieder zu ersetzen?
Oder dient das quasi als Wildcard und in dem "for obj.." teil wird nacheinander jedes servicestatus teil durchgearbeitet?

2. der Befehl "??.startswith("??")" bezieht sich dieser direkt auf den ersten Buchstaben/Zahl, wenn ja gibt es soetwas für quasi ??.inline("??") sodass auch davor noch ein WOrt stehen darf?


Danke das du mir so schnell hilfst, du rettest mir damit wahrscheinlich mein Wochenende :)
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

"obj" ist kein besonderes Feature, sondern nur ein schlecht gewählter Name. "items" oder "servicestatus" ist passender.

Zu 1: Wie kommst du darauf, dass eine neue Datei erstellt wird? Die bei parse angegebene Datei wird geöffnet und untersucht. die parse-Funktion ist ein Generator, welcher die servicestatus-Elemente liefert.

Zu 2: x in y

Hast du eigentlich das Tutorial oder dessen Übersetzung durchgearbeitet? Deine Fragen sind alles mehr oder weniger Grundlagen.
Das Leben ist wie ein Tennisball.
Tobbel
User
Beiträge: 14
Registriert: Freitag 7. September 2012, 11:00

Noch kein Online-Tutorial o.ä. gelesen, hab hier das Buch "Python 3 Object oriented Programming" von dusty phillips und die sache ist die, es wird gut erklärt wie die ganzen sachen funktioniern, jedoch kaum was zur syntax, zu befehlen, oder gar beispielen...

Daher hab ich mir die befehle usw. eher selber zusammengetragen, daher kenn ich auch noch nicht viele... dachte auch blöderweise das dass ein einfacheres Projekt ist bei dem ich nicht so weit in die Materie muss ;)

B2T:

okay, dann werd ichs mal probieren, danke auf jedenfall :)

Vielen dank ncoheinmal :)
Tobbel
User
Beiträge: 14
Registriert: Freitag 7. September 2012, 11:00

So nun meld ich mich nocheinmal ;)

Hab jetzt eine weile mit den möglichkeiten rumprobiert und muss leider sagen das ich mit dem zweiten Ansatz zu keinerlei ergebniss kam, bekomm egal was ich mach, ja auch nach google..., diesen Fehler:

Code: Alles auswählen

  File "lampe2.py", line 32, in <module>
    Main(sys.argv[1:])
  File "lampe2.py", line 22, in Main
    for obj in parse("status2.dat"):
  File "lampe2.py", line 11, in parse
    for line in (l.strip() for l in fp):
ValueError: I/O operation on closed file
mit dem zweiten Ansatz komm ich soweit durch, jedoch bekomm ich das "Zeilen-zählen" nicht gebacken...

zwei ansätze hatte ich, die aber entweder in beiden fällen fehlerlos liefen, aber mir nicht das gewünschte ergebnis lieferten...
das ist mein Code , Hilfe ist erwünscht, am liebsten für diese Variante :)

Code: Alles auswählen

#!/usr/bin/env python

import time
import commands
import sys

def Main(argv):
	i = 0
	while i < 1:
		OK = 0
		WARNING = 0
		CRITICAL = 0
		UNKNOWN = 0
		ACKNOW = 0
		SCHEDU = 0
		with open("/home/tweber/status.dat") as fp:
			match = None
			for index, line in enumerate(fp):
				if match is None:
					if "plugin_output=" in line:
						if "OK" in line:
							match = index
							okay = match
							OK = OK + 1
							match = None
	
						elif "WARNING" in line:
							match = index
							WARN = match
							WARNING= WARNING + 1
							match = None

						elif "CRITICAL" in line:
							match = index
							CRIT = match
							CRITICAL = CRITICAL + 1
							match = None
	
						elif "UNKNOWN" in line:
							match = index
							UNKN = match
							UNKNOWN = UNKNOWN + 1
							match = None

				elif WARN + 10 <= index: 
					if "problem_has_been_acknowledged=0" in line:
						print "AH2!"
						match = None 

		fp.close()
		i = i +1
		print "UNKNOWN" 
		print UNKNOWN  
		print "WARNING" 
		print WARNING 
		print "OK"	
		print OK
		print "CRITICAL"
		print CRITICAL 
#		print "SCHEDU"
#		print SCHEDU	
#		print "ACKNOW"
#		print ACKNOW

if __name__ == '__main__':
    Main(sys.argv[1:])
Grüßle, Tobi :)
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Hui... viel zu viel Copy und Paste Programmierung ;-) Hab leider keine Zeit da zu rezensieren.

Was war denn an EyDus Ansatz so magisch, dass Du den nicht weiter verfolgst?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Tobbel
User
Beiträge: 14
Registriert: Freitag 7. September 2012, 11:00

Hab jetzt eine weile mit den möglichkeiten rumprobiert und muss leider sagen das ich mit dem zweiten Ansatz zu keinerlei ergebniss kam, bekomm egal was ich mach, ja auch nach google..., diesen Fehler:
Nein magisch war sie nicht, nur leider hat es nicht funktioniert da bei mir der Parser nie startete, sondern sich immer mit der netten fehlermeldung verbschiedet hat, wie ich schon im vorherigen Post geschriebn habe...

Was meinst du mit zu viel copy/paste Programmierung, nur weil ich 3 Zeilen von EyDu kopiert habe und mir dann nicht die Mühe gemacht hab einen eigenen namen einzufügen?

mfg Tobi
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Tobbel hat geschrieben:Nein magisch war sie nicht, nur leider hat es nicht funktioniert da bei mir der Parser nie startete, sondern sich immer mit der netten fehlermeldung verbschiedet hat, wie ich schon im vorherigen Post geschriebn habe...
Dann zeig doch mal den Code dazu, nur die Fehlermeldung ist etwas wenig. Auf Grund des Fehlers würde ich vermuten, dass du die Datei irgendwo in der for-Schleife schließt oder dass die for-Schleife nicht im with-Block enthalten ist.
Tobbel hat geschrieben:Was meinst du mit zu viel copy/paste Programmierung, nur weil ich 3 Zeilen von EyDu kopiert habe und mir dann nicht die Mühe gemacht hab einen eigenen namen einzufügen?
Du hast da einige Blöcke, welche alle nahezu identisch aussehen. Da kann man viel zusammenfassen.
Das Leben ist wie ein Tennisball.
Tobbel
User
Beiträge: 14
Registriert: Freitag 7. September 2012, 11:00

Das geht nun leider nicht, hab nur die obrige Variante von der Arbeit mitgenommen, das mit dem parser liegt dort auf der festplatte ;)

realistisch gefragt: macht es sinn an meiner obigen idee festzuhalten, oder nicht? bzw ist es "einfacher" auf die andere methode?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Tobbel hat geschrieben:realistisch gefragt: macht es sinn an meiner obigen idee festzuhalten, oder nicht? bzw ist es "einfacher" auf die andere methode?
Gegenfrage: hältst du es für sinnvoll eine lange, unübersichtliche, mehr schlecht als recht programmierte, fehleranfällige, schwer zu erweiternde und gegen diverse Paradigmen verstoßende Funktion zu benutzen und eine robuste kurze Lösung zu verwerfen?
Das Leben ist wie ein Tennisball.
Tobbel
User
Beiträge: 14
Registriert: Freitag 7. September 2012, 11:00

Na wenn du es so sagst dann werde ich mich morgen mal deinem Vorschlag näher widmen und bei eventuellen mich hier wieder melden , vielen dank jedenfalls noch einmal :)
Tobbel
User
Beiträge: 14
Registriert: Freitag 7. September 2012, 11:00

So da bin ich wieder, saß nun den ganzen morgen dran und komm nicht weiter...
Zu Anfangs hatte ich KeyErrors, die sind nun weg aber hab nun keinerlei Erfolg....

Code: Alles auswählen

def auslesen(status):
	with open("/home/tweber/status.dat") as statuspart:
		servicestatus = None
        	for line in (l.strip(" ") for l in statuspart):
			if line.endswith("{", 1, len(line)):
				servicestatus = {}
								
			elif line.startswith("}", 0, len(line)):
				yield servicestatus
				servicestatus = None
			
			elif servicestatus is not None and line:
				name, value = line.split("=", 1)
				servicestatus["plugin_output"] = value 
				servicestatus["problem_has_been_acknowledged"] = value 
				servicestatus["scheduled_downtime_depth"] = value 
			
def Main(argv):
	print "hallo"
	for servicestatus in auslesen("/home/tweber/status.dat"):
		print "das hier?"
		if (servicestatus["plugin_output"].startswith("OK", 0, len(servicestatus["plugin_output"])) and   # oder "OK" in servicestatus["plugin_output"]
		servicestatus["problem_has_been_acknowledged"] == "0" and
		servicestatus["scheduled_downtime_depth"] == "0"):
			green()
		else:
			print "hallo?"			
			off()

if __name__ == "__main__":
    Main(sys.argv[1:])
green(), off() sind fehlerfreie codeteile, die jedoch nichts hiermit zu tun haben.


Wenn ich den Code ausführe kommt keinerlei Fehlermeldung, jedoch greift das Programm aber auch nicht in die bereiche die nach "for servicestatus in auslesen..." zu, bzw. kann mit dem variablen-namen servicestatus nichts anfangen, hatte auch schon versucht servicestatus zuvor als global zu definieren, machte jedoch keinen sinn da dies ja von "yield" übernommen wird, kann mir irgendjemand helfen? Ich steck hier echt fest und würde mich über einen Ratschlag sehr freuen :)

Bin mir auch nicht sicher ob das

Code: Alles auswählen

elif servicestatus is not None and line:
                                name, value = line.split("=", 1)
                                servicestatus["plugin_output"] = value 
                                servicestatus["problem_has_been_acknowledged"] = value 
                                servicestatus["scheduled_downtime_depth"] = value 

sinn macht, da von meinem Verständnis das ja eigentlich der Code "servicestatus[name]", so wie ihn EyDu gepostet hat, übernehmen müsste ...

Hilfe...
Gruß Tobi
Benutzeravatar
sparrow
User
Beiträge: 4195
Registriert: Freitag 17. April 2009, 10:28

So ein paar Print-Anweisungen könnten dir beim Debuggen helfen, damit du siehst wo was wirklich passiert.
Du stripst nur Leerzeichen weg. Warum? Das steht so auch nicht in dem Beispiel von EyDu. Dadurch bleiben aber ander Whitespaces drin. Eine Zeile endet mit \n, dann kannst du nicht mehr darauf testen ob eine Zeile mit } endet.
strip(), Danach sollte es funktionieren.

Und

Code: Alles auswählen

with open("/home/tweber/status.dat") as statuspart:
sollte

Code: Alles auswählen

sein with open(status) as statuspart:
sein.
Tobbel
User
Beiträge: 14
Registriert: Freitag 7. September 2012, 11:00

Super , vielen vielen Dank! Das hat es gebracht! Ich hatte halt "open" immer in Verwendung mit spezifischem Pfad oder Dateinamen gelesen/gesehen, aber nachdem das geändert war hat es funktioniert!

und das mit dem strip(" ") hatte ich irgendwo aufgeschnappt und ausprobiert, dass das, nun wo du es sagst, natürlich nicht alles stripped hab ich nun auch verstanden. Danke nocheinmal :)

Jedoch bekomme ich keines der erwünschten Ergebnisse, könnte das in Zusammnhang mit

Code: Alles auswählen

 servicestatus["plugin_output"] = value 
servicestatus["problem_has_been_acknowledged"] = value 
servicestatus["scheduled_downtime_depth"] = value 
anstatt

Code: Alles auswählen

 servicestatus[name] = value
zusammenhängen? Oder eher an Fehlern die sich woanders im Code verstecken?

Gruß Tobi
Zuletzt geändert von Tobbel am Montag 10. September 2012, 12:34, insgesamt 1-mal geändert.
Benutzeravatar
sparrow
User
Beiträge: 4195
Registriert: Freitag 17. April 2009, 10:28

Gibt es eigentlich noch andere Blöcke die in der Datei stehen können?

servicestatus { leitet gerade genauso einen neuen Servicestatus ein wie weißwurstgrütze {. Unter Umständen könnte es robuster sein, nicht nur auf eine abschließende { in einer Zeile zu schauen, sondern die ganze Zeile zu vergleichen. Ggf. muss man dann auch über ein Flag festhalten ob man sich gerade in dem korrekten Block befindet und ansonsten das schließende } ignorieren. //Edit: Das mit dem Flag ist natürlich Blödsinn, dafür kann man hier ja servicestatus verwenden, das dann nur in einem Block nicht None ist.

Aber wenn das nicht vorkommen kann, ist alles gut.
Tobbel
User
Beiträge: 14
Registriert: Freitag 7. September 2012, 11:00

Ja es gibt andere, die sind nur z.B. Hoststatus o.ä genannt ,jedoch ist der inhalt identisch und soll auch ausgewertet werden, daher ist das in diesem fall sogar gut :)

Habe eben noch meinen Beitrag von zuvor editiert, evtl weis jemand noch etwas darüber :)
Benutzeravatar
sparrow
User
Beiträge: 4195
Registriert: Freitag 17. April 2009, 10:28

Was glaubst du denn was die Zuweisungen dort machen?
Du setzt bei jeder Zeile deren Wert für drei verschiedene Schlüssel im Dictionary. Bei jeder Zeile. Egal welche kommt.
Der Code von EyDu hat hingegen für jede Zeile ein Schlüssel-Wert-Paar im Dictionary angelegt, über das man später sehr einfach an den Inhalt kommt.
Antworten