阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

高阶应用-日志

244次阅读
没有评论

共计 7592 个字符,预计需要花费 19 分钟才能阅读完成。

一、Log 简介

logging 模块是 Python 内置的标准模块,主要用于输出运行日志,可以设置输出日志的等级、日志保存路径、日志文件回滚等;相比 print,具备如下优点:

通过 log 的分析,可以方便用户了解系统或软件、应用的运行情况;如果你的应用 log 足够丰富,也可以分析以往用户的操作行为、类型喜好、地域分布或其他更多信息;如果一个应用的 log 同时也分了多个级别,那么可以很轻易地分析得到该应用的健康状况,及时发现问题并快速定位、解决问题,补救损失。

二、Log 的用途

不管是使用何种编程语言,日志输出几乎无处不再。总结起来,日志大致有以下几种用途:

  • 问题追踪:通过日志不仅仅包括我们程序的一些 bug,也可以在安装配置时,通过日志可以发现问题。
  • 状态监控:通过实时分析日志,可以监控系统的运行状态,做到早发现问题、早处理问题。
  • 安全审计:审计主要体现在安全上,通过对日志进行分析,可以发现是否存在非授权的操作

三、Log 等级

  • DEBUG 最详细的日志信息,典型应用场景是 问题诊断
  • INFO 信息详细程度仅次于 DEBUG,通常只记录关键节点信息,用于确认一切都是按照我们预期的那样进行工作
  • WARNING 当某些不期望的事情发生时记录的信息(如,磁盘可用空间较低),但是此时应用程序还是正常运行的
  • ERROR 由于一个更严重的问题导致某些功能不能正常运行时记录的信息 如 IO 操作失败或者连接问题
  • CRITICAL 当发生严重错误,导致应用程序不能继续运行时记录的信息

四、日志记录级别

​ logging 模块的重点在于生成和处理日志消息。每条消息由一些文本和指示其严重性的相关级别组成。级别包含符号名称和数字值。

级别 描述
CRITICAL 50 关键错误 / 消息
ERROR 40 错误
WARNING 30 警告消息
INFO 20 通知消息
DEBUG 10 调试
NOTSET 0 无级别

五、Log 模块的四大组件

  • Loggers

    提供应用程序代码直接使用的接口

  • Handlers

    用于将日志记录发送到指定的目的位置

    • 内置处理器

      logging 模块提供了一些处理器,可以通过各种方式处理日志消息。使用 addHandler()方法将这些处理器添加给 Logger 对象。另外还可以为每个处理器配置它自己的筛选和级别

      • handlers.DatagramHandler(host,port):发送日志消息给位于制定 host 和 port 上的 UDP 服务器
      • handlers.FileHandler(filename):将日志消息写入文件 filename
      • handlers.HTTPHandler(host, url):使用 HTTP 的 GET 或 POST 方法将日志消息上传到一台 HTTP 服务器
      • handlers.RotatingFileHandler(filename):将日志消息写入文件 filename。如果文件的大小超出 maxBytes 制定的值,那么它将被备份为 filename1
  • Filters

    提供更细粒度的日志过滤功能,用于决定哪些日志记录将会被输出(其它的日志记录将会被忽略)

  • Formatters

    用于控制日志信息的最终输出格式

六、记录器

​ 记录器负责管理日志消息的默认行为,包括日志记录级别、输出目标位置、消息格式以及其它基本细节。

关键字参数 描述
filename 将日志消息附加到指定文件名的文件
filemode 指定用于打开文件模式
format 用于生成日志消息的格式字符串
datefmt 用于输出日期和时间的格式字符串
level 设置记录器的级别
stream 提供打开的文件,用于把日志消息发送到文件。

七、format 日志消息格式

格式 描述
%(name)s 记录器的名称
%(levelno)s 数字形式的日志记录级别
%(levelname)s 日志记录级别的文本名称
%(filename)s 执行日志记录调用的源文件的文件名称
%(pathname)s 执行日志记录调用的源文件的路径名称
%(funcName)s 执行日志记录调用的函数名称
%(module)s 执行日志记录调用的模块名称
%(lineno)s 执行日志记录调用的行号
%(created)s 执行日志记录的时间
%(asctime)s 日期和时间
%(msecs)s 毫秒部分
%(thread)d 线程 ID
%(threadName)s 线程名称
%(process)d 进程 ID
%(message)s 记录的消息

八、logging

  • 简单使用 - 控制台查看

    示例

    import logging
    s = '0'
    n = int(s)
    logging.info('n = %d' % n)
    print(10 / n)

    logging.info()就可以输出一段文本

    配置级别

    import logging
    logging.basicConfig(level=logging.INFO)

    输出结果

    $ python err.py
    INFO:root:n = 0
    Traceback (most recent call last):
    File "err.py", line 8, in <module>
    print(10 / n)
    ZeroDivisionError: division by zero

    说明:

    这就是 logging 的好处,它允许你指定记录信息的级别,有 debuginfowarningerror 等几个级别,当我们指定 level=INFO 时,logging.debug就不起作用了。同理,指定 level=WARNING 后,debuginfo 就不起作用了。这样一来,你可以放心地输出不同级别的信息,也不用删除,最后统一控制输出哪个级别的信息。

    logging的另一个好处是通过简单的配置,一条语句可以同时输出到不同的地方,比如 console 和文件

  • logging 进阶使用 - 控制台查看

    配置 logging 基本的设置,然后在控制台输出日志

    import logging
    logging.basicConfig(level = logging.INFO,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    logger = logging.getLogger(__name__)
    logger.info("Start print log")
    logger.debug("Do something")
    logger.warning("Something maybe fail.")
    logger.info("Finish")

    运行时,控制台输出

    2088-10-09 19:11:19,434 - __main__ - INFO - Start print log
    2088-10-09 19:11:19,434 - __main__ - WARNING - Something maybe fail.
    2088-10-09 19:11:19,434 - __main__ - INFO - Finish

    将 logger 的级别改为 DEBUG,再观察一下输出结果

    logging.basicConfig(level = logging.DEBUG,format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    

    控制台输出,可以发现,输出了 debug 的信息

    2088-10-09 19:12:08,289 - __main__ - INFO - Start print log
    2088-10-09 19:12:08,289 - __main__ - DEBUG - Do something
    2088-10-09 19:12:08,289 - __main__ - WARNING - Something maybe fail.
    2088-10-09 19:12:08,289 - __main__ - INFO - Finish
  • 将日志写入到文件

    设置 logging,创建一个 FileHandler,并对输出消息的格式进行设置,将其添加到 logger,然后将日志写入到指定的文件中

    示例

    import logging
    logger = logging.getLogger(__name__)
    logger.setLevel(level = logging.INFO)
    handler = logging.FileHandler("log.txt")
    handler.setLevel(logging.INFO)
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    handler.setFormatter(formatter)
    logger.addHandler(handler)
    logger.info("Start print log")
    logger.debug("Do something")
    logger.warning("Something maybe fail.")
    logger.info("Finish")

    log.txt 中日志数据为

    2088-10-09 19:01:13,263 - __main__ - INFO - Start print log
    2088-10-09 19:01:13,263 - __main__ - WARNING - Something maybe fail.
    2088-10-09 19:01:13,263 - __main__ - INFO - Finish
  • 将日志同时输出到屏幕和日志文件

    logger 中添加 StreamHandler,可以将日志输出到屏幕上

    import logging
    logger = logging.getLogger(__name__)
    logger.setLevel(level = logging.INFO)
    handler = logging.FileHandler("log.txt")
    handler.setLevel(logging.INFO)
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    handler.setFormatter(formatter)
    console = logging.StreamHandler()
    console.setLevel(logging.INFO)
    logger.addHandler(handler)
    logger.addHandler(console)
    logger.info("Start print log")
    logger.debug("Do something")
    logger.warning("Something maybe fail.")
    logger.info("Finish")

    可以在 log.txt 文件和控制台中看到

    2088-10-09 19:20:46,553 - __main__ - INFO - Start print log
    2088-10-09 19:20:46,553 - __main__ - WARNING - Something maybe fail.
    2088-10-09 19:20:46,553 - __main__ - INFO - Finish

九、Django 中配置输出到文件

  • 配置 setting.py 配置文件
LOGGING = {'version': 1,
'disable_existing_loggers': True,
'formatters': {# 日志格式
'standard': {'format': '%(asctime)s [%(threadName)s:%(thread)d] [%(name)s:%(lineno)d] [%(module)s:%(funcName)s] [%(levelname)s]- %(message)s'}
},
'filters': {# 过滤器
},
'handlers': {# 处理器
'null': {'level': 'DEBUG',
'class': 'logging.NullHandler',
},
'debug': {# 输出到文件
'level':'DEBUG',
'class':'logging.handlers.RotatingFileHandler',
'filename': os.path.join(BASE_DIR, "log",'debug.log'), # 日志输出文件
'maxBytes':1024*1024*5, # 文件大小
'backupCount': 5, # 备份份数
'formatter':'standard', # 使用哪种 formatters 日志格式
},
'console':{# 输出到控制台
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'standard',
},
},
'loggers': {# logging 管理器
'django': {'handlers': ['console'],
'level': 'DEBUG',
'propagate': False
},
'django.request': {'handlers': ['debug'],
'level': 'ERROR',
'propagate': True,
},
}
}

说明:把所有的 debug 信息输出到控制台,把 error 级别错误信息输出到文件。当然要先在 django 网站创建我设置的日志目录:log,要不然会出错。

解析:

  • formatters:配置打印日志格式
  • handler:用来定义具体处理日志的方式,可以定义多种,”default” 就是默认方式,”console” 就是打印到控制台方式
  • loggers: 用来配置用那种 handlers 来处理日志,比如你同时需要输出日志到文件、控制台

十、Django 配置邮件发送错误信息

  • 关闭 Debug 模式

    关闭调试模式,调试模式响应速度相对有些慢。关闭调试模式可以加快访问速度,而且可以避免敏感的调试信息泄漏

    打开 settings.py 文件,把 DEBUG 设置 False。接着还需要设置 ALLOWED_HOSTS (被运行的主机),如果这个设置的话,会提示错误。偷懒的人可以设置为 ALLOWED_HOSTS = [’*’] 但这种不建议,不够安全。应该根据自己的域名来设置。设置为 ALLOWED_HOSTS = [‘xxx.com’]

  • 动态设置 Debug 模式

    为了方便我开发和生产部署,不想每次都手动修改 DEBUG 这个值, 导入 socket 模块,根据 ip 地址来设置。判断是否是 127 开头的 IP 地址

    import socket
    if socket.gethostbyname(socket.gethostname())[:3]=='127':
    DEBUG = True
    else:
    DEBUG = False
    ALLOWED_HOSTS = ['*']
  • 完整的代码

    import socket
    # 根据 IP 地址判断是否是开发环境
    if socket.gethostbyname(socket.gethostname())[:3]=='127':
    DEBUG = True
    else:
    DEBUG = False
    ALLOWED_HOSTS = ['*'] # 设置允许访问的主机
    # 管理员邮箱
    ADMINS = (('xialigang','793390457@qq.com'),
    )
    # 非空链接,却发生 404 错误,发送通知 MANAGERS
    SEND_BROKEN_LINK_EMAILS = True
    MANAGERS = ADMINS
    # Email
    EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
    EMAIL_HOST = 'smtp.1000phone.com' # QQ 邮箱 SMTP 服务器
    EMAIL_HOST_USER = 'xialigang@1000phone.com' # 我的邮箱帐号
    EMAIL_HOST_PASSWORD = '******' # 密码
    DEFAULT_FROM_EMAIL = SERVER_EMAIL = EMAIL_HOST_USER # 设置发件人
    #logging 日志配置
    LOGGING = {'version': 1,
    'disable_existing_loggers': True,
    'formatters': {# 日志格式
    'standard': {'format': '%(asctime)s [%(threadName)s:%(thread)d] [%(name)s:%(lineno)d] [%(module)s:%(funcName)s] [%(levelname)s]- %(message)s'}
    },
    'filters': {# 过滤器
    'require_debug_false': {'()': 'django.utils.log.RequireDebugFalse',
    }
    },
    'handlers': {# 处理器
    'null': {'level': 'DEBUG',
    'class': 'logging.NullHandler',
    },
    'mail_admins': {# 发送邮件通知管理员
    'level': 'ERROR',
    'class': 'django.utils.log.AdminEmailHandler',
    'filters': ['require_debug_false'], # 仅当 DEBUG = False 时才发送邮件
    'include_html': True,
    },
    'debug': {# 记录到日志文件(需要创建对应的目录,否则会出错)
    'level':'DEBUG',
    'class':'logging.handlers.RotatingFileHandler',
    'filename': os.path.join(BASE_DIR, "log",'debug.log'), # 日志输出文件
    'maxBytes':1024*1024*5, # 文件大小
    'backupCount': 5, # 备份份数
    'formatter':'standard', # 使用哪种 formatters 日志格式
    },
    'console':{# 输出到控制台
    'level': 'DEBUG',
    'class': 'logging.StreamHandler',
    'formatter': 'standard',
    },
    },
    'loggers': {# logging 管理器
    'django': {'handlers': ['console','debug'], # 控制台输出并写入 debug 文件
    'level': 'DEBUG',
    'propagate': False
    },
    'django.request': {'handlers': ['debug','mail_admins'],
    'level': 'ERROR',
    'propagate': True,
    },
    # 对于不在 ALLOWED_HOSTS 中的请求不发送报错邮件
    'django.security.DisallowedHost': {'handlers': ['null'],
    'propagate': False,
    },
    }
    }

    注意:如果发送失败 注意查看 debug 是否关闭为 False

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-05-26发表,共计7592字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中