Python线上环境使用日志的及配置文件


Posted in Python onJuly 28, 2019

目录

  • 瞎比比
  • 与 print 相比 logging 有什么优势?
  • 基础用法
  • 保存到文件
  • 多模块使用 logging
  • 使用配置文件配置 logging

瞎比比

这篇文章其实早在一个月之前就写好了。奈何,加班猛如虎,真的怕了。直至今天才幸运地有了个双休,赶紧排版一下文章发布了。以下为正文。 在初学 Python 的时候,我们使用

print("hello world")

输出了我们的第一行代码。在之后的日子里,便一直使用 print 进行调试(当然,还有 IDE 的 debug 模式)。但是,当你在线上运行 Python 脚本的时候,你并不可能一直守着你的运行终端。可是如果不守着的话,每当出现 bug ,错误又无从查起。这个时候,你需要对你的调试工具进行更新换代了,这里我推荐一个优雅的调试工具 logging。

与 print 相比 logging 有什么优势?

那既然我推荐这个工具,它凭什么要被推荐呢?且来看看它有什么优势:

  • 可以输出到多处,例如:在输出到控制台的同时,可以保存日志到日志文件里面,或者保存到其他远程服务器
  • 可以设置日志等级,DEBUG、INFO、ERROR等,在不同的环境(调试环境、线上环境)使用不同的等级来过滤日志,使用起来很方便
  • 配置灵活,可保存到配置文件,格式化输出

基础用法

下面涉及到的代码我都省略了导包部分,详见源码(后台回复 logging 获取源码)

base_usage.py

logging.basicConfig(level=log_level, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
logger.info("Log level info")
logger.debug("Log level debug")
logger.warning("Log level warning")
# 捕获异常,并打印出出错行数
try:
  raise Exception("my exception")
except (SystemExit, KeyboardInterrupt):
  raise
except Exception:
  logger.error("there is an error =>", exc_info=True)

level为日志等级,分为:

FATAL:致命错误
CRITICAL:特别糟糕的事情,如内存耗尽、磁盘空间为空,一般很少使用
ERROR:发生错误时,如IO操作失败或者连接问题
WARNING:发生很重要的事件,但是并不是错误时,如用户登录密码错误
INFO:处理请求或者状态变化等日常事务
DEBUG:调试过程中使用DEBUG等级,如算法中每个循环的中间状态

foamat可以格式化输出,其参数有如下:

%(levelno)s:打印日志级别的数值
%(levelname)s:打印日志级别的名称
%(pathname)s:打印当前执行程序的路径,其实就是sys.argv[0]
%(filename)s:打印当前执行程序名
%(funcName)s:打印日志的当前函数
%(lineno)d:打印日志的当前行号
%(asctime)s:打印日志的时间
%(thread)d:打印线程ID
%(threadName)s:打印线程名称
%(process)d:打印进程ID
%(message)s:打印日志信息

捕获异常,以下两行代码都具有相同的作用

logger.exception(msg,_args)
logger.error(msg,exc_info = True,_args)

保存到文件,并输出到命令行

这个用法直接 copy 使用就行

import logging
# 写入文件
import logging
logger = logging.getLogger(__name__)
logger.setLevel(level=logging.INFO)
handler = logging.FileHandler("info.log")
handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.info("Log level info")
logger.debug("Log level debug")
logger.warning("Log level warning")
# 写入文件,同时输出到屏幕
import logging
logger = logging.getLogger(__name__)
logger.setLevel(level = logging.INFO)
handler = logging.FileHandler("info.log")
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("Log level info")
logger.debug("Log level debug")
logger.warning("Log level warning")

多模块使用 logging

被调用者的日志格式会与调用者的日志格式一样 main.py

# -*- coding: utf-8 -*-
__auth__ = 'zone'
__date__ = '2019/6/17 下午11:46'
'''
公众号:zone7

小程序:编程面试题库

'''
import os
import logging
from python.logging_model.code import sub_of_main
logger = logging.getLogger("zone7Model")
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)
console.setFormatter(formatter)
logger.addHandler(handler)
logger.addHandler(console)
sub = sub_of_main.SubOfMain()
logger.info("main module log")
sub.print_some_log()
sub_of_main.py
# -*- coding: utf-8 -*-
__auth__ = 'zone'
__date__ = '2019/6/17 下午11:47'
'''

公众号:zone7

小程序:编程面试题库

'''
import logging
module_logger = logging.getLogger("zone7Model.sub.module")
class SubOfMain(object):
  def __init__(self):
    self.logger = logging.getLogger("zone7Model.sub.module")
    self.logger.info("init sub class")
  def print_some_log(self):
    self.logger.info("sub class log is printed")

def som_function():
  module_logger.info("call function some_function")

使用配置文件配置 logging

这里分别给出了两种配置文件的使用案例,都分别使用了三种输出,输出到命令行、输出到文件、将错误信息独立输出到一个文件

log_cfg.json
{
  "version":1,
  "disable_existing_loggers":false,
  "formatters":{
    "simple":{
      "format":"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
    }
  },
  "handlers":{
    "console":{
      "class":"logging.StreamHandler",
      "level":"DEBUG",
      "formatter":"simple",
      "stream":"ext://sys.stdout"
    },
    "info_file_handler":{
      "class":"logging.handlers.RotatingFileHandler",
      "level":"INFO",
      "formatter":"simple",
      "filename":"info.log",
      "maxBytes":10485760,
      "backupCount":20,
      "encoding":"utf8"
    },
    "error_file_handler":{
      "class":"logging.handlers.RotatingFileHandler",
      "level":"ERROR",
      "formatter":"simple",
      "filename":"errors.log",
      "maxBytes":10485760,
      "backupCount":20,
      "encoding":"utf8"
    }
  },
  "loggers":{
    "my_module":{
      "level":"ERROR",
      "handlers":["info_file_handler2"],
      "propagate":"no"
    }
  },
  "root":{
    "level":"INFO",
    "handlers":["console","info_file_handler","error_file_handler"]
  }
}

通过 json 文件读取配置:

import json
import logging.config
import os
def set_log_cfg(default_path="log_cfg.json", default_level=logging.INFO, env_key="LOG_CFG"):
  path = default_path
  value = os.getenv(env_key, None)
  if value:
    path = value
  if os.path.exists(path):
    with open(path, "r") as f:
      config = json.load(f)
      logging.config.dictConfig(config)
  else:
    logging.basicConfig(level=default_level)
def record_some_thing():
  logging.info("Log level info")
  logging.debug("Log level debug")
  logging.warning("Log level warning")
if __name__ == "__main__":
  set_log_cfg(default_path="log_cfg.json")
  record_some_thing()
log_cfg.yaml
version: 1
disable_existing_loggers: False
formatters:
    simple:
      format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
handlers:
  console:
      class: logging.StreamHandler
      level: DEBUG
      formatter: simple
      stream: ext://sys.stdout
  info_file_handler:
      class: logging.handlers.RotatingFileHandler
      level: INFO
      formatter: simple
      filename: info.log
      maxBytes: 10485760
      backupCount: 20
      encoding: utf8
  error_file_handler:
      class: logging.handlers.RotatingFileHandler
      level: ERROR
      formatter: simple
      filename: errors.log
      maxBytes: 10485760
      backupCount: 20
      encoding: utf8
loggers:
  my_module:
      level: ERROR
      handlers: [info_file_handler]
      propagate: no
root:
  level: INFO
  handlers: [console,info_file_handler,error_file_handler]

通过 yaml 文件读取配置:

import yaml
import logging.config
import os
def set_log_cfg(default_path="log_cfg.yaml", default_level=logging.INFO, env_key="LOG_CFG"):
  path = default_path
  value = os.getenv(env_key, None)
  if value:
    path = value
  if os.path.exists(path):
    with open(path, "r") as f:
      config = yaml.load(f)
      logging.config.dictConfig(config)
  else:
    logging.basicConfig(level=default_level)
def record_some_thing():
  logging.info("Log level info")
  logging.debug("Log level debug")
  logging.warning("Log level warning")
if __name__ == "__main__":
  set_log_cfg(default_path="log_cfg.yaml")
  record_some_thing()

总结

以上所述是小编给大家介绍的Python线上环境使用日志的及配置文件,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Python 相关文章推荐
用Python编写一个国际象棋AI程序
Nov 28 Python
Python使用MYSQLDB实现从数据库中导出XML文件的方法
May 11 Python
Python读取网页内容的方法
Jul 30 Python
spyder常用快捷键(分享)
Jul 19 Python
Python实现将照片变成卡通图片的方法【基于opencv】
Jan 17 Python
python字符串的方法与操作大全
Jan 30 Python
利用Python批量提取Win10锁屏壁纸实战教程
Mar 27 Python
pandas系列之DataFrame 行列数据筛选实例
Apr 12 Python
python如何查看微信消息撤回
Nov 27 Python
python pandas cumsum求累计次数的用法
Jul 29 Python
python  logging日志打印过程解析
Oct 22 Python
Python使用grequests并发发送请求的示例
Nov 05 Python
Django 实现admin后台显示图片缩略图的例子
Jul 28 #Python
处理python中多线程与多进程中的数据共享问题
Jul 28 #Python
在django中图片上传的格式校验及大小方法
Jul 28 #Python
python之生产者消费者模型实现详解
Jul 27 #Python
python单线程下实现多个socket并发过程详解
Jul 27 #Python
如何使用python操作vmware
Jul 27 #Python
利用python计算windows全盘文件md5值的脚本
Jul 27 #Python
You might like
桌面中心(四)数据显示
2006/10/09 PHP
判断是否为指定长度内字符串的php函数
2010/02/16 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(十一)
2014/06/25 PHP
CI框架中cookie的操作方法分析
2014/12/12 PHP
thinkphp备份数据库的方法分享
2015/01/04 PHP
php实现通用的信用卡验证类
2015/03/24 PHP
微信接口生成带参数的二维码
2017/07/31 PHP
laravel 去掉index.php伪静态的操作方法
2019/10/12 PHP
学习jquery必备 api中英文对照的chm手册 下载
2007/05/03 Javascript
js键盘上下左右键怎么触发function(实例讲解)
2013/12/14 Javascript
轻松使用jQuery双向select控件Bootstrap Dual Listbox
2015/12/13 Javascript
常常会用到的截取字符串substr()、substring()、slice()方法详解
2015/12/16 Javascript
AngularJS中过滤器的使用与自定义实例代码
2016/09/17 Javascript
Require.JS中的几种define定义方式示例
2017/06/01 Javascript
json字符串传到前台input的方法
2018/08/06 Javascript
JavaScript this指向相关原理及实例解析
2020/07/10 Javascript
vue操作dom元素的3种方法示例
2020/09/20 Javascript
vue3+typeScript穿梭框的实现示例
2020/12/29 Vue.js
python网络编程学习笔记(三):socket网络服务器
2014/06/09 Python
以一段代码为实例快速入门Python2.7
2015/03/31 Python
在Python的一段程序中如何使用多次事件循环详解
2017/09/07 Python
ubuntu系统下使用pm2设置nodejs开机自启动的方法
2018/05/12 NodeJs
Python反射和内置方法重写操作详解
2018/08/27 Python
使用Django简单编写一个XSS平台的方法步骤
2019/03/25 Python
Python 如何操作 SQLite 数据库
2020/08/17 Python
python如何对链表操作
2020/10/10 Python
纽约手袋品牌:KARA
2018/03/18 全球购物
Tessabit日本:集世界奢侈品和设计师品牌的意大利精品买手店
2020/01/07 全球购物
介绍一下grep命令的使用
2012/06/28 面试题
社团招新策划书
2014/02/04 职场文书
党员公开承诺事项
2014/03/25 职场文书
怎样写家长意见
2015/06/04 职场文书
JavaScript如何利用Promise控制并发请求个数
2021/05/14 Javascript
深入理解redis中multi与pipeline
2021/06/02 Redis
MySQL中rank() over、dense_rank() over、row_number() over用法介绍
2022/03/23 MySQL
Win10开机修复磁盘错误怎么跳过?Win10关闭开机磁盘检查的方法
2022/09/23 数码科技