Bagaimana cara menulis ke file, menggunakan modul Python logging?

128

Bagaimana saya bisa menggunakan modul logging dengan Python untuk menulis ke file? Setiap kali saya mencoba menggunakannya, itu hanya mencetak pesannya.

Takkun
sumber

Jawaban:

171

Contoh penggunaan logging.basicConfigdaripadalogging.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')

Secara berurutan, lima bagian tersebut melakukan hal berikut:

  1. atur file keluaran ( filename=logname)
  2. setel ke menambahkan daripada menimpa ( filemode='a')
  3. tentukan format pesan keluaran ( format=...)
  4. tentukan format waktu keluaran ( datefmt='%H:%M:%S')
  5. dan tentukan level pesan minimum yang akan diterima ( level=logging.DEBUG).
thegrinner
sumber
Bisakah nama file menjadi lokasi hdfs? Jika ya, bagaimana caranya?
Augmented Jacob
apakah mungkin untuk mengatur jalur file
neeraja
1
pastikan ini tidak di bawah if __name__ == '__main__':jika berjalan pada apache
Rami Alloush
@RamiAlloush bisakah Anda menjelaskan? Mengapa demikian? (rasa ingin tahu :))
notihs
@notihs, server tidak menjalankan file skrip secara langsung sehingga bagian di bawah if __name__ == '__main__':ini tidak dijalankan.
Rami Alloush
71

Diambil dari " buku masak logging ":

# 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)

Dan Anda siap untuk pergi.

PS Pastikan untuk membaca HOWTO logging juga.

Eli Bendersky
sumber
4
Untuk menjawab pertanyaan pertama Anda, silakan lihat judul pertanyaan yang saya ajukan. Saya telah memeriksa tautan yang Anda berikan dan itu membantu. Saya telah menyalin kode yang Anda berikan kepada saya dan apakah saya salah berasumsi bahwa saya akan berhasil menggunakan logger.info ("message") dan logger.warning ("message")? Saya dapat menulis ke file menggunakan logger.warning, namun logger.info tampaknya tidak menulis ke file tersebut.
Takkun
Coba hapus panggilan setLevel. Membaca dokumen penangan sepertinya semua pesan diproses secara default.
thegrinner
2
Saya dapat menulis ke file hanya dengan menggunakan logger.warning("message"), tidak dapat menggunakan logger.info("message")atau logger.debug("message"). Itu agak mengganggu.
m3nda
3
Contoh kode yang ditulis @EliBendersky kehilangan 1 langkah jika Anda ingin menulis pesan info / debug. Logger itu sendiri membutuhkan level lognya sendiri untuk dikonfigurasi untuk menerima level pesan logging tersebut, misalnya logger.setLevel(logging.DEBUG). Logger dapat dikonfigurasi dengan banyak penangan; tingkat yang dikonfigurasi di pencatat menentukan pesan log tingkat keparahan mana yang akan dikirim ke setiap penangannya, & tingkat yang disetel di penangan menentukan tingkat mana yang akan diproses oleh penangan. Perhatikan bahwa mereka yang ingin mencetak pesan info hanya perlu menyetelnya ke INFOlogger dan handler.
uji coba
Saya telah memperbarui sampel untuk dilakukan logger.setLevel(logging.DEBUG)- terima kasih atas komentarnya
Eli Bendersky
13

Saya lebih suka menggunakan file konfigurasi. Ini memungkinkan saya untuk mengganti level logging, lokasi, dll tanpa mengubah kode ketika saya beralih dari pengembangan ke rilis. Saya hanya mengemas file konfigurasi yang berbeda dengan nama yang sama, dan dengan logger yang didefinisikan sama.

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()

Ini kode saya untuk file konfigurasi log

#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
Bill Kidd
sumber
1
Penamaan file dengan tanggal membutuhkan dua kali lipat %%dalam Python 3. misalnyatime.strftime("%%Y%%m%%D")
AH
9

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

logging.basicConfig(filename='/path/to/your/log', level=....)
Gryphius
sumber
1
Ini menghemat log di file, itu bagus. Bagaimana jika bersama-sama dengan ini, saya juga ingin memasukkan output ke terminal?
Rishabh Agrahari
loggingDokumentasi modul resmi memungkinkan untuk ini. Anda bahkan dapat memilih log apa yang masuk ke terminal dan mana yang masuk ke dalam file, dan banyak lagi aplikasi menarik. docs.python.org/3/howto/…
Daniel Hernandez
4

inilah cara yang lebih sederhana untuk melakukannya. solusi ini tidak menggunakan kamus konfigurasi dan menggunakan penangan file rotasi, seperti:

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')

atau seperti ini:

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')

variabel penangan harus iterable. logpath + nama file dan debug_level hanyalah variabel yang menyimpan info masing-masing. tentu saja, nilai untuk parameter fungsi terserah Anda.

pertama kali saya menggunakan modul logging saya membuat kesalahan dengan menulis berikut ini, yang menghasilkan kesalahan kunci file OS (di atas adalah solusi untuk itu):

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))

dan Bob adalah pamanmu!

pdp
sumber
0
import sys
import logging

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

Contoh ini seharusnya bekerja dengan baik. Saya telah menambahkan streamhandler untuk konsol. Data log konsol dan penangan file harus serupa.

    # 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, 
muthukumar
sumber
0

Deskripsi Format

#%(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. 

Cara menelepon yang normal

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')

Keluaran

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

Menggunakan Dict, nilai panggilan

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

Keluaran

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!
sim
sumber