简体   繁体   English

如何使用日志记录 Python 模块写入文件?

[英]How to write to a file, using the logging Python module?

How can I use thelogging module in Python to write to a file?如何使用 Python 中的日志记录模块写入文件? Every time I try to use it, it just prints out the message.每次我尝试使用它时,它都会打印出消息。

An example of using logging.basicConfig rather than logging.fileHandler()使用logging.basicConfig而不是logging.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")

logger = logging.getLogger('urbanGUI')

In order, the five parts do the following:这五个部分依次执行以下操作:

  1. set the output file ( filename=logname )设置输出文件( filename=logname
  2. set it to append rather than overwrite ( filemode='a' )将其设置为追加而不是覆盖( filemode='a'
  3. determine the format of the output message ( format=... )确定输出消息的格式( format=...
  4. determine the format of the output time ( datefmt='%H:%M:%S' )确定输出时间的格式( datefmt='%H:%M:%S'
  5. and determine the minimum message level it will accept ( level=logging.DEBUG ).并确定它将接受的最低消息级别( level=logging.DEBUG )。

Taken from the " logging cookbook ":取自“ 日志记录食谱”:

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

And you're good to go.你可以走了。

PS Make sure to read the logging HOWTO as well. PS 请务必阅读日志记录 HOWTO

Here is two examples, one print the logs (stdout) the other write the logs to a file:这是两个示例,一个打印日志(stdout),另一个将日志写入文件:

import logging
import sys

logger = logging.getLogger()
logger.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s | %(levelname)s | %(message)s')

stdout_handler = logging.StreamHandler(sys.stdout)
stdout_handler.setLevel(logging.DEBUG)
stdout_handler.setFormatter(formatter)

file_handler = logging.FileHandler('logs.log')
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(formatter)


logger.addHandler(file_handler)
logger.addHandler(stdout_handler)

With this example, all logs will be printed and also be written to a file named logs.log在此示例中,所有日志都将被打印并写入名为 logs.log 的文件

Use example:使用示例:

logger.info('This is a log message!')
logger.error('This is an error message.')

List of all built-in logging handlers https://docs.python.org/3/library/logging.handlers.html所有内置日志记录处理程序的列表https://docs.python.org/3/library/logging.handlers.html

I prefer to use a configuration file.我更喜欢使用配置文件。 It allows me to switch logging levels, locations, etc without changing code when I go from development to release.当我从开发到发布时,它允许我在不更改代码的情况下切换日志记录级别、位置等。 I simply package a different config file with the same name, and with the same defined loggers.我只是用相同的名称打包了一个不同的配置文件,并使用相同的定义记录器。

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

Here is my code for the log config file这是我的日志配置文件代码

#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

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

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

here's a simpler way to go about it.这是一种更简单的方法。 this solution doesn't use a config dictionary and uses a rotation file handler, like so:此解决方案不使用配置字典并使用旋转文件处理程序,如下所示:

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

or like so:或者像这样:

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

the handlers variable needs to be an iterable. handlers 变量需要是可迭代的。 logpath+filename and debug_level are just variables holding the respective info. logpath+filename 和 debug_level 只是保存各自信息的变量。 of course, the values for the function params are up to you.当然,函数参数的值取决于你。

the first time i was using the logging module i made the mistake of writing the following, which generates an OS file lock error (the above is the solution to that):我第一次使用日志记录模块时犯了以下错误,这会产生操作系统文件锁定错误(以上是解决方案):

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

http://docs.python.org/library/logging.handlers.html#filehandler http://docs.python.org/library/logging.handlers.html#filehandler

The FileHandler class, located in the core logging package, sends logging output to a disk file.位于核心logging包中的FileHandler类将日志记录输出发送到磁盘文件。

This example should work fine.这个例子应该可以正常工作。 I have added streamhandler for console.我为控制台添加了流处理程序。 Console log and file handler data should be similar.控制台日志和文件处理程序数据应该相似。

    # 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, 
import logging

from datetime import datetime

filename = datetime.now().strftime("%d-%m-%Y %H-%M-%S")#Setting the filename from current date and time
logging.basicConfig(filename=filename, filemode='a',
                    format="%(asctime)s, %(msecs)d %(name)s %(levelname)s [ %(filename)s-%(module)s-%(lineno)d ]  : %(message)s",
                    datefmt="%H:%M:%S",
                    level=logging.DEBUG)
  • asctime时间

    %(asctime)s %(asctime)s

    Human-readable time when the LogRecord was created.创建 LogRecord 的人类可读时间。 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).默认情况下,格式为“2003-07-08 16:49:45,896”(逗号后面的数字是时间的毫秒部分)。

  • created创建

    %(created)f %(创建)f

    Time when the LogRecord was created (as returned by time.time()).创建 LogRecord 的时间(由 time.time() 返回)。

  • exc_info exc_info

    You shouldn't need to format this yourself.您不需要自己格式化。

    Exception tuple (à la sys.exc_info) or, if no exception has occurred, None.异常元组(à la sys.exc_info),或者,如果没有发生异常,则无。

  • filename文件名

    %(filename)s %(文件名)s

    Filename portion of pathname.路径名的文件名部分。

  • funcName函数名

    %(funcName)s %(funcName)s

    Name of function containing the logging call.包含日志调用的函数的名称。

  • levelname级别名称

    %(levelname)s %(级别名)s

    Text logging level for the message ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL').消息的文本记录级别('DEBUG'、'INFO'、'WARNING'、'ERROR'、'CRITICAL')。

  • levelno等级号

    %(levelno)s %(levelno)s

    Numeric logging level for the message (DEBUG, INFO, WARNING, ERROR, CRITICAL).消息的数字日志记录级别(DEBUG、INFO、WARNING、ERROR、CRITICAL)。

  • lineno线诺

    %(lineno)d %(亚麻)d

    Source line number where the logging call was issued (if available).发出记录调用的源行号(如果可用)。

  • message信息

    %(message)s %(消息)s

    The logged message, computed as msg % args.记录的消息,计算为 msg % args。 This is set when Formatter.format() is invoked.这是在调用 Formatter.format() 时设置的。

  • module模块

    %(module)s %(模块)s

    Module (name portion of filename).模块(文件名的名称部分)。

  • msecs毫秒

    %(msecs)d %(毫秒)d

    Millisecond portion of the time when the LogRecord was created.创建 LogRecord 时的毫秒部分。

  • msg味精

    You shouldn't need to format this yourself.您不需要自己格式化。

    The format string passed in the original logging call.在原始日志记录调用中传递的格式字符串。 Merged with args to produce message, or an arbitrary object (see Using arbitrary objects as messages).与 args 合并以生成消息或任意对象(请参阅将任意对象用作消息)。

  • name姓名

    %(name)s %(姓名)s

    Name of the logger used to log the call.用于记录呼叫的记录器的名称。

  • pathname路径名

    %(pathname)s %(路径名)s

    Full pathname of the source file where the logging call was issued (if available).发出日志调用的源文件的完整路径名(如果可用)。

  • process过程

    %(process)d %(进程)d

    Process ID (if available).进程 ID(如果可用)。

  • processName进程名

    %(processName)s %(进程名)s

    Process name (if available).进程名称(如果可用)。

  • relativeCreated相对创建

    %(relativeCreated)d %(相对创建)d

    Time in milliseconds when the LogRecord was created, relative to the time the logging module was loaded.创建 LogRecord 的时间(以毫秒为单位),相对于加载日志记录模块的时间。

  • stack_info堆栈信息

    You shouldn't need to format this yourself.您不需要自己格式化。

    Stack frame information (where available) from the bottom of the stack in the current thread, up to and including the stack frame of the logging call which resulted in the creation of this record.当前线程中堆栈底部的堆栈帧信息(如果可用),直到并包括导致创建此记录的日志记录调用的堆栈帧。

  • thread线

    %(thread)d %(线程)d

    Thread ID (if available).线程 ID(如果可用)。

  • threadName线程名

    %(threadName)s %(线程名)s

    Thread name (if available).线程名称(如果可用)。

Head over to official python3 page for more info regarding logging.前往官方python3 页面了解有关日志记录的更多信息。

import sys
import logging

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

Format Description 格式说明

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

Normal way of calling 正常的通话方式

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

Output 输出量

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

Using Dict, Call values 使用Dict,调用值

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

Output 输出量

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!

use negar module ... 使用negar模块...

github negar module github negar模块

install negar ... 安装negar ...

python3 -m pip install negar

code

from negar import log

# method one

def x():
    text = 'hello world!'
    return text

log('\'x\' function return value is '+'\''+str(x())+'\'')

# method two

def y():
    text = 'hello world!'
    return text

log(text = '\'y\' function return value is '+'\''+str(x())+'\'' , save = 'function-log.txt' , size = 1)

result 结果

结果

Although it is an old question, for people reaching this question these days, you can also use dictConfig .虽然这是一个老问题,但对于现在遇到这个问题的人来说,你也可以使用dictConfig For example, for a file with info level and above :例如,对于具有信息级别及以上的文件:

logging.config.dictConfig({
    'version': 1,
    'formatters': {
        'default': {
            'format': '[%(asctime)s] %(message)s',
        }
    },
    'handlers': {
        'info': {
            'level': logging.INFO,
            'class': 'logging.FileHandler',
            'filename': 'info.log',
        },
    },
    "root": {
        "level": logging.INFO,
        "handlers": ["info"]
    }
})

Or another example to be more specific, with rotating file and in a specific directory :或者另一个更具体的例子,使用旋转文件并在特定目录中:

today = datetime.date.today()
folder = './log'
Path(folder).mkdir(parents=True, exist_ok=False) # Create folder if not exists
logging.config.dictConfig({
        ...
        'info': {
            'level': logging.INFO,
            'class': 'logging.handlers.TimedRotatingFileHandler',
            'filename': f'{folder}/info-{today.month:02}-{today.year}.log',
            # Roll over on the first day of the weekday
            'when': 'W0',
            # Roll over at midnight
            'atTime': datetime.time(hour=0),
            # Number of files to keep.
            'backupCount': 8
        },
        ...

best and clean method.最好和干净的方法。

    ds = datetime.now().strftime("%Y%m%d_%H%M%S")
    try:
        # py39 有force参数指定可能强制除去之前的handler,这里使用兼容写法,0708
        logging.getLogger().removeHandler(logging.getLogger().handlers[0])
        logging.getLogger().removeHandler(logging.getLogger().handlers[0])
    except:
        pass
    logging.basicConfig(
        # force=
        level=logging.INFO,
        format="%(asctime)s [%(levelname)s] %(message)s",
        handlers=[
            logging.FileHandler('log_%s_%s_%s.log' % (ds, create_net, os.path.basename(dataset_path))),
            logging.StreamHandler(sys.stdout)
        ]
    )
    logging.info('start train')

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM