Dateien herunterladen und in einem Verzeichnis ablegen

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.
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Meine Lösung sieht nun so aus. Es scheint zu funktionieren. Bitte schaut einmal drüber. Wie bringe ich das Logging und das exception handling zusammen? Wie baue ich die Meldung logger.error('error message') in die entsprechenden Funktionen ein? Ist die Idee richtig?

Code: Alles auswählen

def initialize_logger():
    logger = logging.getLogger('Data warehouse')
    logger.setLevel(logging.DEBUG)
    newpath = 'log'                                  <=== ist die Zeile eine gute Idee
    if not os.path.exists(newpath):
        os.makedirs(newpath)
        handler = logging.FileHandler(os.path.join("log", str(datetime.date.today())+'.log'))
        handler.setLevel(logging.DEBUG)
        formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        handler.setFormatter(formatter)
        logger.addHandler(handler)
        
         # 'application' code
        logger.debug('debug message')
        logger.info('info message')
        logger.warn('warn message')
        logger.error('error message')
        logger.critical('critical message')
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

ich möchte

Code: Alles auswählen

handler = logging.FileHandler('log/2017-4-4.log') durch 
handler = logging.Filehandler("log", str(datetime.date.today()), '{}.log') ersetzen
Was mache ich falsch?
BlackJack

@aaron: 1. Schreibst Du `FileHandler` mit einem kleinen 'h'.

2.: Übergibst Du drei Argumente die so von `FileHandler` nicht erwartet werden:

Code: Alles auswählen

In [6]: logging.FileHandler("log", str(datetime.date.today()), '{}.log')
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-6-e702480fc016> in <module>()
----> 1 logging.FileHandler("log", str(datetime.date.today()), '{}.log')

/usr/lib/python2.7/logging/__init__.pyc in __init__(self, filename, mode, encoding, delay)                                                                      
    895             self.stream = None
    896         else:
--> 897             StreamHandler.__init__(self, self._open())
    898 
    899     def close(self):

/usr/lib/python2.7/logging/__init__.pyc in _open(self)
    916             stream = open(self.baseFilename, self.mode)
    917         else:
--> 918             stream = codecs.open(self.baseFilename, self.mode, self.encoding)
    919         return stream
    920 

/usr/lib/python2.7/codecs.pyc in open(filename, mode, encoding, errors, buffering)
    879             # Force opening of the file in binary mode
    880             mode = mode + 'b'
--> 881     file = __builtin__.open(filename, mode, buffering)
    882     if encoding is None:
    883         return file

ValueError: mode string must begin with one of 'r', 'w', 'a' or 'U', not '2017-04-04b'
Das sieht extrem nach herum raten aus in dem Du wahllos Teile aus Code zusammenkopierst der etwas ähnliches macht(e) in der Hoffnung das da schon irgendwie etwas sinnvolles heraus kommt. So funktioniert programmieren aber nicht. Hier fehlen absolute Grundlagen über Zeichenketten und Funktionsaufrufe. Was hat Dich denn dazu gebracht diese drei Argumente zu übergeben? Welche Argumente erwartet `FileHandler` denn? Und welche übergibst Du und was denkst Du bedeutet das dann?
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Vielen Dank für die Antwort.
1. Ich möchte erstens überprüfen, ob ein Verzeichnis log schon existiert und wenn nein, dann soll ein Verzeichnis erstellt werden.
2. Ich möchte das jede Datei das Datum des aktuellen Tages trägt.

Aus der Python Dokumentation ist folgendes zu lesen.
class logging.FileHandler(filename, mode='a', encoding=None, delay=False)
Das heißt, daß ich als erstes Argument den Filenamen übergeben muß. Wenn ich das richtig verstehe, dann muß ich vorher den Filenamen als Strin zusammen bauen und dann an FileHandler übergeben.
Benutzeravatar
Kebap
User
Beiträge: 687
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

aaron hat geschrieben:Das heißt, daß ich als erstes Argument den Filenamen übergeben muß. Wenn ich das richtig verstehe, dann muß ich vorher den Filenamen als Strin zusammen bauen und dann an FileHandler übergeben.
Das ist korrekt, es wird genau ein String mit dem Dateinamen erwartet und nicht drei. Vielleicht hast du mal bei print gesehen, dass man einfach mehrere Strings mit Kommas getrennt angeben kann und dann werden sie quasi zu einem zusammengefügt. Das funktioniert aber nicht überall.
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Die Funktionen scheinen jetzt zu funktionieren. Bitte schaut einmal drüber. es geht bestimmt besser.

Code: Alles auswählen

def generate_logfile():
    return os.path.join("log", str(datetime.date.today())+'.log')

def create_logdir():
    logdir = generate_logfile()
    if not os.path.exists(os.path.dirname(logdir)):
        os.makedirs(os.path.dirname(logdir))

def initialize_logger():
    logfile = generate_logfile()
    print(logfile)
    logdir = create_logdir()
    logger = logging.getLogger('Data warehouse')
    logger.setLevel(logging.DEBUG)
    handler = logging.FileHandler(logfile)
    handler.setLevel(logging.DEBUG)
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(m»
    handler.setFormatter(formatter)
    logger.addHandler(handler)

    # 'application' code
    logger.debug('debug message')
    logger.info('info message')
    logger.warn('warn message')
    logger.error('error message')
    logger.critical('critical message')
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@aaron: den Dateinamen mehrfach zu erzeugen, ist ein Fehler, da da ja nicht unbedingt den selben Namen ergeben muß.
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Bitte erkläre mir genau was ich falsch gemacht habe. Ich kann dir jetzt nicht folgen.
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Denk mal darueber nach was passiert, wenn du generate_logfile() um 23:59:59:9999 aufrufst, und dann zwei Millisekunden spaeter schon wieder.

Und mit einem einfachen, alten Trick kannst du das Problem beheben!
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Danke für die Antwort.
den Dateinamen mehrfach zu erzeugen, ist ein Fehler, da da ja nicht unbedingt den selben Namen ergeben muß.
Denk mal darüber nach was passiert, wenn du generate_logfile() um 23:59:59:9999 aufrufst, und dann zwei Millisekunden später schon wieder.
Es werden zwei Logfiles mit unterschiedlichem Inhalt und verschiedenen Namen bedingt durch das neue Datum sein. Hier kann ich noch keinen Fehler erkennen. Geht es vielleicht ein wenig genauer? Vielleicht ein Code schnipsel oder einen Hinweis in der Dokumentation?
BlackJack

@aaron: Es geht ja nicht um zwei Logdateien sondern um *eine* Logdatei für die Du diese Funktion mehr als einmal aufrufst, und bei *einer* Datei möchte man doch eher immer den gleichen Namen haben, also auch nur einmal die Funktion zum erstellen des Namens aufrufen.
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

@aaron der Fehler liegt darin, dass du zwei unterschiedliche Programmteile hast, die momentan nur zufaellig funktionieren, weil du implizite Annahmen darueber machst, dass sie *NICHT* von dem veraenderlichen Teil abhaengen. Natuerlich ist das *jetzt* kein Fehler. Aber in einer nicht allzu fernen Zukunft, in welcher du feststellst, dass dein Filesystem mit tausenden Dateien pro Verzeichnis ins stocken geraet, moechtest du vielleicht ein Schema "basisverzeichnis/datums-verzeichnis/datum-und-zeitstempel.log" verwenden. Du passt also deine generate_logfile-Funktion an, und alles scheint zu funktionieren. Bis es das eben *nicht* mehr tut, weil du einmal das Verzeichnis mit Datum "gestern" anlegst, aber dann in eine Datei mit Datum "heute" schreiben moechtest. Und BUMM.

Stattdessen generiere *einmal* den Logfile-Namen, und reiche ihn in create_logdir als Argument rein. Dann kannst du sicher sein, dass die Aenderungen an generate_logfile keine solchen negativen Effekte haben koennen.

Und in einer Dokumentation steht das nicht. Das hat was mit dem nachdenken darueber zu tun, welche Konsequenzen der eigene Code entfaltet, und diese Szenarien dann zu behandeln bzw. zu veraendern, so dass sie gar nicht erst auftreten. Das ist schlicht "Programmieren".
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Ich habe jetzt die Funktion generate_logfile geändert. Ich verstehe immer noch nicht, wie ich das Ergebnis aus generate_logfile an create_logdir übergeben kann. Ich habe folgendes versucht.

Code: Alles auswählen

def generate_logfile():
    logfile = os.path.join("log", str(datetime.date.today())+'.log')
    print(logfile)

def create_logdir(logfile):
    if not os.path.exists(os.path.dirname(logfile)):
        os.makedirs(os.path.dirname(logfile))
Als Fehlermeldung bekomme ich

Code: Alles auswählen

Traceback (most recent call last):
  File "TickDataCsv.py", line 118, in <module>
    main()
  File "TickDataCsv.py", line 110, in main
    create_logdir(logfile)
NameError: global name 'logfile' is not defined
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich bin ehrlich gesagt ein bisschen sprachlos. Und das passiert nicht so oft.

Code: Alles auswählen

def eine_funktion():
      return "was"
      
def eine_andere_funktion(ein_argument):
      print(ein_argument)

eine_variable = eine_funktion()
eine_andere_funktion(eine_variable)
Du wirst schon programmieren lernen muessen. Die Chancen sich ein funktionsfaehiges Programm zu erraten liegen schlechter als bei 6 aus 49.
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Jetzt bitte von noch einmal von vorn.
Mit der ersten Funktion generiere ich das Logfile. In der zweiten Funktion rufe ich mit der Zeile logdir = generate_logfile() die Funktion nochmals auf. Das soll nicht sein, sondern das Ergebnis aus der ersten Funktion soll als Argument übergeben werden.Ich möchte die Ergebnisse beider Funktion in einer 3. Funktion weiter verwenden. Ich würde das gern verstehen. Aktuell ist es so, da? ich die beiden Funktionen in der 3. Funktion nochmals aufrufe. Ich lasse durch die 3. Funktion die funktionen a und 2 ausführen. Jetzt bitte einmal für ein Erstklässler.

Code: Alles auswählen

def generate_logfile():
    return os.path.join("log", str(datetime.date.today())+'.log')

def create_logdir():
    logdir = generate_logfile()
    if not os.path.exists(os.path.dirname(logdir)):
        os.makedirs(os.path.dirname(logdir))
        
def initialize_logger():
    logfile = generate_logfile()
    print(logfile)
    logdir = create_logdir()
    logger = logging.getLogger('Data warehouse')
    logger.setLevel(logging.DEBUG)
    handler = logging.FileHandler(logfile)
    handler.setLevel(logging.DEBUG)
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(m»
    handler.setFormatter(formatter)
    logger.addHandler(handler)

    # 'application' code
    logger.debug('debug message')
    logger.info('info message')
    logger.warn('warn message')
    logger.error('error message')
    logger.critical('critical message')
Zuletzt geändert von aaron am Mittwoch 5. April 2017, 16:01, insgesamt 1-mal geändert.
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du erzeugst einen Log-File-Namen, und gibst den zurueck. Das hast du schon (generate_logfile).

Du speicherst dir den Namen in einer Variablen, und den gibst du weiter an all die anderen Dinge, die ihn brauchen:

Code: Alles auswählen

def generate_logfile():
    ...
    
def ensure_logdir_exists(logfilename):
     ....
     
def initialize_logger():
      logfile_name = generate_logfile()
      ensure_logdir_exists(logfile_name)
      ...
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@aaron: jetzt hast Du wieder den funktionierenden Zustand gezeigt. Und vom funktionierenden zum kaputten Zustand hast Du mehr geändert, als eigentlich nötig wäre. Die Frage ist, warum hast Du das gemacht? Irgendetwas hast Du Dir ja dabei gedacht. Um Dir helfen zu können, wäre es gut, was Du Dir dabei gedacht hast, weil wie es generell richtig ist, hat __deets__ ja schon geschrieben.
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Der Code sieht jetzt so aus. Es funktioniert die Funktion def ensure_logdir_exits(logfilename): nocht nicht. Mir ist nicht klar, wie die Argumentübergabe an die Funktion def ensure_logdir_exits(logfilename): erfolgt.

Code: Alles auswählen

def generate_logfile():
    return os.path.join("log", str(datetime.date.today())+'.log')

def ensure_logdir_exits(logfilename):
    if not os.path.exists(os.path.dirname(logfilename)):
        os.makedirs(os.path.dirname(logfilename))

def initialize_logger():
    logfile_name = generate_logfile()
    print(logfile_name)
    ensure_logdir_exists(logfile_name)
    logger = logging.getLogger('Data download')
    logger.setLevel(logging.DEBUG)
    handler = logging.FileHandler(logfile_name)
    handler.setLevel(logging.DEBUG)
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    handler.setFormatter(formatter)
    logger.addHandler(handler)

    # 'application' code
    logger.debug('debug message')
    logger.info('info message')
    logger.warn('warn message')
    logger.error('error message')
    logger.critical('critical message')
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@aaron: wenn Du eine Fehlermeldung erhältst, sagt sie Dir, was Du falsch machst.
aaron
User
Beiträge: 92
Registriert: Donnerstag 1. Dezember 2016, 23:10

Sorry die Fehlermeldung:

Code: Alles auswählen

Traceback (most recent call last):
  File "TickDataCsv.py", line 115, in <module>
    main()
  File "TickDataCsv.py", line 108, in main
    initialize_logger()
  File "TickDataCsv.py", line 22, in initialize_logger
    ensure_logdir_exists(logfile_name)
NameError: global name 'ensure_logdir_exists' is not defined
Antworten