Learn python with socratica [My notes] - part 15- Logging

Lesson 17

Introduction

logging就是记录的意思,也就是生成日志的一种方式。在程序运行过程中,logging模块可以记录所有的一切【按需记录】。这对于开发者来说很重要,好的代码如果发生错误,就直接知道在哪发生了什么问题。

Functions

logging帮助程序员把重要的信息写入文件或者其他形式的输出,这些信息更多的是代码的执行部分和代码的问题。每个logging都有一个等级,一共5个内建的等级,包括:Debug,Info,Warning,Error,critical。开发者也可以自己创建新的等级。

  	import logging
    dir(logging)

	output:
    ['BASIC_FORMAT',
     'BufferingFormatter',
     'CRITICAL',
     'DEBUG',
     'ERROR',
     'FATAL',
     'FileHandler',
     'Filter',
     'Filterer',
     'Formatter',
     'Handler',
     'INFO',
     'LogRecord',
     'Logger',
     'LoggerAdapter',
     'Manager',
     'NOTSET',
     'NullHandler',
     'PercentStyle',
     'PlaceHolder',
     'RootLogger',
     'StrFormatStyle',
     'StreamHandler',
     'StringTemplateStyle',
     'Template',
     'WARN',
     'WARNING',
     '_STYLES',
     '_StderrHandler',
     '__all__',
     '__author__',
     '__builtins__',
     '__cached__',
     '__date__',
     '__doc__',
     '__file__',
     '__loader__',
     '__name__',
     '__package__',
     '__path__',
     '__spec__',
     '__status__',
     '__version__',
     '_acquireLock',
     '_addHandlerRef',
     '_checkLevel',
     '_defaultFormatter',
     '_defaultLastResort',
     '_handlerList',
     '_handlers',
     '_levelToName',
     '_lock',
     '_logRecordFactory',
     '_loggerClass',
     '_nameToLevel',
     '_releaseLock',
     '_removeHandlerRef',
     '_showwarning',
     '_srcfile',
     '_startTime',
     '_warnings_showwarning',
     'addLevelName',
     'atexit',
     'basicConfig',
     'captureWarnings',
     'collections',
     'critical',
     'currentframe',
     'debug',
     'disable',
     'error',
     'exception',
     'fatal',
     'getLevelName',
     'getLogRecordFactory',
     'getLogger',
     'getLoggerClass',
     'handlers',
     'info',
     'io',
     'lastResort',
     'log',
     'logMultiprocessing',
     'logProcesses',
     'logThreads',
     'makeLogRecord',
     'os',
     'raiseExceptions',
     'root',
     'setLogRecordFactory',
     'setLoggerClass',
     'shutdown',
     'sys',
     'threading',
     'time',
     'traceback',
     'warn',
     'warning',
     'warnings',
     'weakref']

logging的功能还是比较复杂的,这节课主要以基本的日志为主,其他的形式需要萌新们自己实验。

  	import logging
    help(logging.basicConfig)
	
	output:
    Help on function basicConfig in module logging:
    
    basicConfig(**kwargs)
        Do basic configuration for the logging system.
        
        This function does nothing if the root logger already has handlers
        configured. It is a convenience method intended for use by simple scripts
        to do one-shot configuration of the logging package.
        
        The default behaviour is to create a StreamHandler which writes to
        sys.stderr, set a formatter using the BASIC_FORMAT format string, and
        add the handler to the root logger.
        
        A number of optional keyword arguments may be specified, which can alter
        the default behaviour.
        
        filename  Specifies that a FileHandler be created, using the specified
                  filename, rather than a StreamHandler.
        filemode  Specifies the mode to open the file, if filename is specified
                  (if filemode is unspecified, it defaults to 'a').
        format    Use the specified format string for the handler.
        datefmt   Use the specified date/time format.
        style     If a format string is specified, use this to specify the
                  type of format string (possible values '%', '{', '$', for
                  %-formatting, :meth:`str.format` and :class:`string.Template`
                  - defaults to '%').
        level     Set the root logger level to the specified level.
        stream    Use the specified stream to initialize the StreamHandler. Note
                  that this argument is incompatible with 'filename' - if both
                  are present, 'stream' is ignored.
        handlers  If specified, this should be an iterable of already created
                  handlers, which will be added to the root handler. Any handler
                  in the list which does not have a formatter assigned will be
                  assigned the formatter created in this function.
        
        Note that you could specify a stream created using open(filename, mode)
        rather than passing the filename and mode in. However, it should be
        remembered that StreamHandler does not close its stream (since it may be
        using sys.stdout or sys.stderr), whereas FileHandler closes its stream
        when the handler is closed.
        
        .. versionchanged:: 3.2
           Added the ``style`` parameter.
        
        .. versionchanged:: 3.3
           Added the ``handlers`` parameter. A ``ValueError`` is now thrown for
           incompatible arguments (e.g. ``handlers`` specified together with
           ``filename``/``filemode``, or ``filename``/``filemode`` specified
           together with ``stream``, or ``handlers`` specified together with
           ``stream``.



    import logging
    logging.basicConfig(filename="./log.out")
    logger = logging.getLogger()
    
    logger.info("first")
    print(logger.level)
	
	output:
    30


这里会生成一个日志文件在当前目录下, 30代表着什么呢?在logging的等级制度里,分为:NOTSET-0,DEBUG-10,INFO-20,WARNING-30,ERROR-40,CRITICAL-50。30就代表当前的日志等级是basicConfig默认的WARNING。此时,我们做一个改动:

	import logging
    logging.basicConfig(filename="./log.out",
                       level = logging.DEBUG)
    logger = logging.getLogger()
    
    logger.info("first")
    print(logger.level)

	output:
    10

这里,理论上会打印出10,但是出错了,暂时找不出原因。如果打开log.out,内容如下:INFO:root:first.

New Format

根据自己的需要改写日志的格式,python提供了很多的信息模块,举个例子:

 	import logging
    LOG_FORMAT="%(levelname) %(asctime)s - %(massage)s"
    logging.basicConfig(filename="./log.out",
                       level = logging.DEBUG,
                       format = LOG_FORMAT)
    logger = logging.getLogger()
    
    logger.info("first")

如果打开日志,会发现多了一行新的日志,格式会改为:INFO Y-M-D H-M-S-MS - first。如果想要每次都重写日志,则需要加入filemode

   import logging
   LOG_FORMAT="%(levelname) %(asctime)s - %(massage)s"
   logging.basicConfig(filename="./log.out",
                      level = logging.DEBUG,
                      format = LOG_FORMAT,
                      filemode = 'w')
   logger = logging.getLogger()
   
   logger.info("second")

此时的输出日志就只有second这一行了。这里还需要注意一点,只有当前等级之上的message才会被写入日志:

   import logging
   LOG_FORMAT="%(levelname) %(asctime)s - %(massage)s"
   logging.basicConfig(filename="./log.out",
                      level = logging.DEBUG,
                      format = LOG_FORMAT,
                      filemode = 'w')
   logger = logging.getLogger()
   
   # Test Massages
   logger.debug("This is a harmless debug message.")
   logger.info("Just some useful info.")
   logger.warning("Warning!")
   logger.error("Did you just try to divide by zero?")
   logger.critical("The entire internet is down!")

运行之后,所有的massage都会在日志里出现。但是如果把basicConfig的level改成ERROR,那么之后存在最后两条。

Example

如何运用日志更好地调试代码呢:

    import logging
    import math
    
    LOG_FORMAT="%(levelname) %(asctime)s - %(massage)s"
    logging.basicConfig(filename="./mathlog.out",
                       level = logging.DEBUG,
                       format = LOG_FORMAT,
                       filemode = 'w')
    logger = logging.getLogger()
    
    def quadratic_formula(a,b,c):
        """Return the solutions to the equation ax^2 + bx + c = 0."""
        logger.info("quafratic_formula({0},{1},{2})".format(a,b,c))
        
        # compute the discriminant
        logger.debug("# Compute the discriminant")
        disc = b**2 - 4*a*c
        
        # compute the two roots
        logger.debug("# Compute the two roots")
        root1 = (-b + math.sqrt(disc)) / (2*a)
        root2 = (-b - math.sqrt(disc)) / (2*a)
        
        # Return the roots
        logger.debug("# Return the roots")
        return (root1, root2)
    
    roots = quadratic_formula(1,0,-4)
    print(roots)
    
	output:
    (2.0, -2.0)

如果打开日志文件,一共四行:

  • INFO
  • DEBUG- # Compute the discriminant
  • DEBUG- # Compute the two roots
  • DEBUG- # return the roots

下面举一个错误例子:

   	import logging
    import math
    
    LOG_FORMAT="%(levelname) %(asctime)s - %(massage)s"
    logging.basicConfig(filename="./mathlog.out",
                       level = logging.DEBUG,
                       format = LOG_FORMAT,
                       filemode = 'w')
    logger = logging.getLogger()
    
    def quadratic_formula(a,b,c):
        """Return the solutions to the equation ax^2 + bx + c = 0."""
        logger.info("quafratic_formula({0},{1},{2})".format(a,b,c))
        
        # compute the discriminant
        logger.debug("# Compute the discriminant")
        disc = b**2 - 4*a*c
        
        # compute the two roots
        logger.debug("# Compute the two roots")
        root1 = (-b + math.sqrt(disc)) / (2*a)
        root2 = (-b - math.sqrt(disc)) / (2*a)
        
        # Return the roots
        logger.debug("# Return the roots")
        return (root1, root2)
    
    # error: c=-4 -> c=1
    roots = quadratic_formula(1,0,1)
    print(roots)
	
	output:
    ---------------------------------------------------------------------------
    
    ValueError                                Traceback (most recent call last)
    
    <ipython-input-15-d0549ea89a68> in <module>()
         27 
         28 # error: c=-4 -> c=1
    ---> 29 roots = quadratic_formula(1,0,1)
         30 print(roots)

    <ipython-input-15-d0549ea89a68> in quadratic_formula(a, b, c)
         19     # compute the two roots
         20     logger.debug("# Compute the two roots")
    ---> 21     root1 = (-b + math.sqrt(disc)) / (2*a)
         22     root2 = (-b - math.sqrt(disc)) / (2*a)
         23 

    ValueError: math domain error

出错,因此计算到math.sqrt时因为根号下不能为负,所以报错。如果打开此时的日志文件,可以发现一共有三行:

  • INFO
  • DEBUG- # Compute the discriminant
  • DEBUG- # Compute the two roots

最后一行即为出错的地方,这也就是我们平时DEBUG时候的方式。在代码中添加logging可以更好地找出错误所在,也可以提高代码的可读性。

Youtube source:
https://www.youtube.com/watch?v=bY6m6_IIN94&list=PLi01XoE8jYohWFPpC17Z-wWhPOSuh8Er-

你可能感兴趣的:(Learn,python,with,socratica,Learn,python,with,socratica,[My,notes])