Jak pisać do pliku, korzystając z modułu logującego w Pythonie?


128

Jak mogę użyć modułu logowania w Pythonie do zapisu do pliku? Za każdym razem, gdy próbuję go użyć, po prostu drukuje wiadomość.

Odpowiedzi:


173

Przykład użycia logging.basicConfigzamiastlogging.fileHandler()

logging.basicConfig(filename=logname,
                            filemode='a',
                            format='%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s',
                            datefmt='%H:%M:%S',
                            level=logging.DEBUG)

logging.info("Running Urban Planning")

self.logger = logging.getLogger('urbanGUI')

W kolejności pięć części wykonuje następujące czynności:

  1. ustaw plik wyjściowy ( filename=logname)
  2. ustaw go na dołączanie zamiast nadpisywania ( filemode='a')
  3. określić format komunikatu wyjściowego ( format=...)
  4. określić format czasu wyjściowego ( datefmt='%H:%M:%S')
  5. i określ minimalny poziom wiadomości, który zaakceptuje ( level=logging.DEBUG).

Czy nazwa pliku może być lokalizacją w formacie hdfs? Jeśli tak, w jaki sposób?
Augmented Jacob

czy można ustawić ścieżkę do pliku
neeraja

1
upewnij się, że to nie jest if __name__ == '__main__':włączone, jeśli działa na apache
Rami Alloush

@RamiAlloush, czy możesz to rozwinąć? Dlaczego? (ciekawość :))
informuje

@notihs, serwer nie uruchamia pliku skryptu bezpośrednio, więc sekcja poniżej if __name__ == '__main__':nie jest wykonywana.
Rami Alloush

71

Zaczerpnięte z „ książki kucharskiej logowania ”:

# create logger with 'spam_application'
logger = logging.getLogger('spam_application')
logger.setLevel(logging.DEBUG)
# create file handler which logs even debug messages
fh = logging.FileHandler('spam.log')
fh.setLevel(logging.DEBUG)
logger.addHandler(fh)

I jesteś gotowy.

PS Upewnij się, że przeczytałeś także HOWTO logowania .


4
Aby odpowiedzieć na pierwsze pytanie, spójrz na tytuł pytania, które zadałem. Przejrzałem podany przez Ciebie link i okazał się pomocny. Skopiowałem kod, który mi podałeś i czy błędnie założyłem, że będę mógł z powodzeniem korzystać z logger.info ("wiadomość") i logger.warning ("wiadomość")? Udało mi się pisać do pliku za pomocą logger.warning, jednak logger.info nie wydaje się zapisywać do pliku.
Takkun

Spróbuj usunąć wywołanie setLevel. Czytając dokumentację obsługi wygląda na to, że wszystkie wiadomości są przetwarzane domyślnie.
thegrinner

2
Mogę pisać do pliku tylko przy użyciu logger.warning("message"), nie mogę używać logger.info("message")ani logger.debug("message"). To trochę denerwujące.
m3nda

3
W przykładowym kodzie, który napisał @EliBendersky, brakuje 1 kroku, jeśli chcesz pisać informacje / komunikaty debugowania. Sam rejestrator wymaga skonfigurowania własnego poziomu dziennika, aby akceptował ten poziom komunikatów logowania, np logger.setLevel(logging.DEBUG). Rejestratory można skonfigurować z wieloma programami obsługi; poziom skonfigurowany w programie rejestrującym określa, które komunikaty dziennika poziomu ważności należy wysłać do każdego z jego programów obsługi, a poziomy ustawione w programach obsługi określają, które poziomy program obsługi będzie przetwarzać. Zauważ, że ci, którzy chcą drukować komunikaty informacyjne, muszą ustawić to na INFOzarówno w programie rejestrującym, jak i programie obsługi.
testworks

Zaktualizowałem próbkę do zrobienia logger.setLevel(logging.DEBUG)- dzięki za komentarze
Eli Bendersky

13

Wolę użyć pliku konfiguracyjnego. Pozwala mi przełączać poziomy rejestrowania, lokalizacje itp. Bez zmiany kodu, gdy przechodzę od etapu programowania do wydania. Po prostu pakuję inny plik konfiguracyjny o tej samej nazwie iz tymi samymi zdefiniowanymi rejestratorami.

import logging.config
if __name__ == '__main__':
    # Configure the logger
    # loggerConfigFileName: The name and path of your configuration file
    logging.config.fileConfig(path.normpath(loggerConfigFileName))

    # Create the logger
    # Admin_Client: The name of a logger defined in the config file
    mylogger = logging.getLogger('Admin_Client')

    msg='Bite Me'
    myLogger.debug(msg)
    myLogger.info(msg)
    myLogger.warn(msg)
    myLogger.error(msg)
    myLogger.critical(msg)

    # Shut down the logger
    logging.shutdown()

Oto mój kod dla pliku konfiguracyjnego dziennika

#These are the loggers that are available from the code
#Each logger requires a handler, but can have more than one
[loggers]
keys=root,Admin_Client


#Each handler requires a single formatter
[handlers]
keys=fileHandler, consoleHandler


[formatters]
keys=logFormatter, consoleFormatter


[logger_root]
level=DEBUG
handlers=fileHandler


[logger_Admin_Client]
level=DEBUG
handlers=fileHandler, consoleHandler
qualname=Admin_Client
#propagate=0 Does not pass messages to ancestor loggers(root)
propagate=0


# Do not use a console logger when running scripts from a bat file without a console
# because it hangs!
[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=consoleFormatter
args=(sys.stdout,)# The comma is correct, because the parser is looking for args


[handler_fileHandler]
class=FileHandler
level=DEBUG
formatter=logFormatter
# This causes a new file to be created for each script
# Change time.strftime("%Y%m%d%H%M%S") to time.strftime("%Y%m%d")
# And only one log per day will be created. All messages will be amended to it.
args=("D:\\Logs\\PyLogs\\" + time.strftime("%Y%m%d%H%M%S")+'.log', 'a')


[formatter_logFormatter]
#name is the name of the logger root or Admin_Client
#levelname is the log message level debug, warn, ect 
#lineno is the line number from where the call to log is made
#04d is simple formatting to ensure there are four numeric places with leading zeros
#4s would work as well, but would simply pad the string with leading spaces, right justify
#-4s would work as well, but would simply pad the string with trailing spaces, left justify
#filename is the file name from where the call to log is made
#funcName is the method name from where the call to log is made
#format=%(asctime)s | %(lineno)d | %(message)s
#format=%(asctime)s | %(name)s | %(levelname)s | %(message)s
#format=%(asctime)s | %(name)s | %(module)s-%(lineno) | %(levelname)s | %(message)s
#format=%(asctime)s | %(name)s | %(module)s-%(lineno)04d | %(levelname)s | %(message)s
#format=%(asctime)s | %(name)s | %(module)s-%(lineno)4s | %(levelname)-8s | %(message)s

format=%(asctime)s | %(levelname)-8s | %(lineno)04d | %(message)s


#Use a separate formatter for the console if you want
[formatter_consoleFormatter]
format=%(asctime)s | %(levelname)-8s | %(filename)s-%(funcName)s-%(lineno)04d | %(message)s

1
Nazwanie pliku datą wymaga podwójnego %%w Pythonie 3. np.time.strftime("%%Y%%m%%D")
AH

9

http://docs.python.org/library/logging.html#logging.basicConfig

logging.basicConfig(filename='/path/to/your/log', level=....)

1
To zapisuje logi w pliku, to dobrze. Co jeśli razem z tym chciałbym, żeby logował też wyjścia na terminalu?
Rishabh Agrahari,

Oficjalna loggingdokumentacja modułu na to pozwala. Możesz nawet wybrać, które dzienniki mają trafiać do terminala, a które do pliku, i wiele innych interesujących aplikacji. docs.python.org/3/howto/…
Daniel Hernandez,

4

oto prostszy sposób na zrobienie tego. to rozwiązanie nie używa słownika konfiguracyjnego i używa programu obsługi pliku rotacji, jak na przykład:

import logging
from logging.handlers import RotatingFileHandler

logging.basicConfig(handlers=[RotatingFileHandler(filename=logpath+filename,
                     mode='w', maxBytes=512000, backupCount=4)], level=debug_level,
                     format='%(levelname)s %(asctime)s %(message)s', 
                    datefmt='%m/%d/%Y%I:%M:%S %p')

logger = logging.getLogger('my_logger')

lub tak:

import logging
from logging.handlers import RotatingFileHandler

handlers = [
            RotatingFileHandler(filename=logpath+filename, mode='w', maxBytes=512000, 
                                backupCount=4)
           ]
logging.basicConfig(handlers=handlers, level=debug_level, 
                    format='%(levelname)s %(asctime)s %(message)s', 
                    datefmt='%m/%d/%Y%I:%M:%S %p')

logger = logging.getLogger('my_logger')

zmienna handlers musi być iterowalna. logpath + filename i debug_level to po prostu zmienne przechowujące odpowiednie informacje. oczywiście wartości parametrów funkcji zależą od Ciebie.

gdy pierwszy raz korzystałem z modułu logowania, popełniłem błąd, pisząc następujący komunikat, który generuje błąd blokady pliku systemu operacyjnego (powyższy sposób rozwiązuje ten problem):

import logging
from logging.handlers import RotatingFileHandler

logging.basicConfig(filename=logpath+filename, level=debug_level, format='%(levelname)s %(asctime)s %(message)s', datefmt='%m/%d/%Y
 %I:%M:%S %p')

logger = logging.getLogger('my_logger')
logger.addHandler(RotatingFileHandler(filename=logpath+filename, mode='w', 
                  maxBytes=512000, backupCount=4))

a Bob jest twoim wujem!



0
import sys
import logging

from util import reducer_logfile
logging.basicConfig(filename=reducer_logfile, format='%(message)s',
                    level=logging.INFO, filemode='w')

0

Ten przykład powinien działać dobrze. Dodałem streamhandler dla konsoli. Dane dziennika konsoli i programu obsługi plików powinny być podobne.

    # MUTHUKUMAR_TIME_DATE.py #>>>>>>>> file name(module)

    import sys
    import logging
    import logging.config
    # ================== Logger ================================
    def Logger(file_name):
        formatter = logging.Formatter(fmt='%(asctime)s %(module)s,line: %(lineno)d %(levelname)8s | %(message)s',
                                      datefmt='%Y/%m/%d %H:%M:%S') # %I:%M:%S %p AM|PM format
        logging.basicConfig(filename = '%s.log' %(file_name),format= '%(asctime)s %(module)s,line: %(lineno)d %(levelname)8s | %(message)s',
                                      datefmt='%Y/%m/%d %H:%M:%S', filemode = 'w', level = logging.INFO)
        log_obj = logging.getLogger()
        log_obj.setLevel(logging.DEBUG)
        # log_obj = logging.getLogger().addHandler(logging.StreamHandler())

        # console printer
        screen_handler = logging.StreamHandler(stream=sys.stdout) #stream=sys.stdout is similar to normal print
        screen_handler.setFormatter(formatter)
        logging.getLogger().addHandler(screen_handler)

        log_obj.info("Logger object created successfully..")
        return log_obj
    # =======================================================


MUTHUKUMAR_LOGGING_CHECK.py #>>>>>>>>>>> file name
# calling **Logger** function
file_name = 'muthu'
log_obj =Logger(file_name)
log_obj.info("yes   hfghghg ghgfh".format())
log_obj.critical("CRIC".format())
log_obj.error("ERR".format())
log_obj.warning("WARN".format())
log_obj.debug("debug".format())
log_obj.info("qwerty".format())
log_obj.info("asdfghjkl".format())
log_obj.info("zxcvbnm".format())
# closing file
log_obj.handlers.clear()

OUTPUT:
2019/07/13 23:54:40 MUTHUKUMAR_TIME_DATE,line: 17     INFO | Logger object created successfully..
2019/07/13 23:54:40 MUTHUKUMAR_LOGGING_CHECK,line: 8     INFO | yes   hfghghg ghgfh
2019/07/13 23:54:40 MUTHUKUMAR_LOGGING_CHECK,line: 9 CRITICAL | CRIC
2019/07/13 23:54:40 MUTHUKUMAR_LOGGING_CHECK,line: 10    ERROR | ERR
2019/07/13 23:54:40 MUTHUKUMAR_LOGGING_CHECK,line: 11  WARNING | WARN
2019/07/13 23:54:40 MUTHUKUMAR_LOGGING_CHECK,line: 12    DEBUG | debug
2019/07/13 23:54:40 MUTHUKUMAR_LOGGING_CHECK,line: 13     INFO | qwerty
2019/07/13 23:54:40 MUTHUKUMAR_LOGGING_CHECK,line: 14     INFO | asdfghjkl
2019/07/13 23:54:40 MUTHUKUMAR_LOGGING_CHECK,line: 15     INFO | zxcvbnm

Thanks, 

0

Opis formatu

#%(name)s       Name of the logger (logging channel).
#%(levelname)s  Text logging level for the message ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL').
#%(asctime)s    Human-readable time when the LogRecord was created. By default this is of the form ``2003-07-08 16:49:45,896'' (the numbers after the comma are millisecond portion of the time).
#%(message)s    The logged message. 

Normalny sposób dzwonienia

import logging
#logging.basicConfig(level=logging.INFO)
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
logger.info('Start reading database')
# read database here
records = {'john': 55, 'tom': 66}
logger.debug('Records: %s', records)
logger.info('Updating records ...')
# update records here
logger.info('Finish updating records')

Wynik

INFO:__main__:Start reading database
DEBUG:__main__:Records: {'john': 55, 'tom': 66}
INFO:__main__:Updating records ...
INFO:__main__:Finish updating records

Używając funkcji Dict, Call wartości

import logging
import logging.config
import otherMod2

def main():
    """
    Based on http://docs.python.org/howto/logging.html#configuring-logging
    """
    dictLogConfig = {
        "version":1,
        "handlers":{
                    "fileHandler":{
                        "class":"logging.FileHandler",
                        "formatter":"myFormatter",
                        "filename":"config2.log"
                        }
                    },        
        "loggers":{
            "exampleApp":{
                "handlers":["fileHandler"],
                "level":"INFO",
                }
            },

        "formatters":{
            "myFormatter":{
                "format":"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
                }
            }
        }

    logging.config.dictConfig(dictLogConfig)

    logger = logging.getLogger("exampleApp")

    logger.info("Program started")
    result = otherMod2.add(7, 8)
    logger.info("Done!")

if __name__ == "__main__":
    main()

otherMod2.py

import logging
def add(x, y):
    """"""
    logger = logging.getLogger("exampleApp.otherMod2.add")
    logger.info("added %s and %s to get %s" % (x, y, x+y))
    return x+y

Wynik

2019-08-12 18:03:50,026 - exampleApp - INFO - Program started
2019-08-12 18:03:50,026 - exampleApp.otherMod2.add - INFO - added 7 and 8 to get 15
2019-08-12 18:03:50,027 - exampleApp - INFO - Done!
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.