Python logging 模块和使用经验
记录下常用的一些东西,每次用总是查文档有点小麻烦。 py2.7
日志应该是生产应用的重要生命线,谁都不应该掉以轻心
有益原则
级别分离
日志系统通常有下面几种级别,看情况是使用
- FATAL - 导致程序退出的严重系统级错误,不可恢复,当错误发生时,系统管理员需要立即介入,谨慎使用。
- ERROR - 运行时异常以及预期之外的错误,也需要立即处理,但紧急程度低于FATAL,当错误发生时,影响了程序的正确执行。需要注意的是这两种级别属于服务自己的错误,需要管理员介入,用户输入出错不属于此分类。
- WARN - 预期之外的运行时状况,表示系统可能出现问题。对于那些目前还不是错误,然而不及时处理也会变成错误的情况,也可以记为WARN,如磁盘过低。
- INFO - 有意义的事件信息,记录程序正常的运行状态,比如收到请求,成功执行。通过查看INFO,可以快速定位WARN,ERROR, FATAL。INFO不宜过多,通常情况下不超过TRACE的10%。
- DEBUG - 与程序运行时的流程相关的详细信息以及当前变量状态。
- TRACE - 更详细的跟踪信息。DEBUG和TRACE这两种规范由项目组自己定义,通过该种日志,可以查看某一个操作每一步的执行过程,可以准确定位是何种操作,何种参数,何种顺序导致了某种错误的发生
单独目录
日志最好放到单独的日志目录,例如 /var/logs/
下,按照应用分成不同的目录,或者是文件。日志不要放在应用目录下,那样不利于自动化部署和应用升级,备份等。
日志分类
诊断日志,统计日志,审计日志等等,不同用途等日志存储到不同的文件中,方面后面的查询,分析。
日志格式
不管是web日志,还是应用日志,最好有一个比较统一的格式(例如时间格式),方面日志的查询,入库,和分析。还有一些应用统一使用json的日志格式,也挺好的。
不好的做法
- 日志中含有用户敏感信息
- 线上程序中使用 print
- 生产环境使用 debug 级别日志 ��
日志切分
日志可以按照每天,每周或者是文件的大小,切分之后压缩。一方面容易按时间回溯,另一方面可以减少磁盘空间,对于很久之前的日志,可以传输到远程服务器,或者是删除。
Python 日志
好习惯
- root级别的设置: 日志格式, 有利于标准化
- class 中设置logger
self.logger = logging.getLogger(type(self).__name__)
- 模块,文件中设置 logger
logger = logging.getLogger(__name__)
- 使用JSON YAML等格式来配置logging,感觉比使用代码或者 ini格式看起来更方面
- 错误日志是比较特殊的日志,因为它需要更多的信息,例如错误产生的上下文,还有错误堆栈等信息。可以通过
python logging context pypi
关键词google一些信息,或者自己设计一个 logging handler 来实现。
实际问题
- 简单的小应用中,单个日志文件,同时还要打印控制台
import logging
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s',
datefmt='%m-%d %H:%M',
filename='/temp/myapp.log',
filemode='w')
console = logging.StreamHandler()
console.setLevel(logging.INFO)
formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
console.setFormatter(formatter)
# add the handler to the root logger
logging.getLogger('').addHandler(console)
- 记录 Exception 的trace 信息(很有用哦)
try:
open('/path/to/does/not/exist', 'rb')
except (SystemExit, KeyboardInterrupt):
raise
except Exception, e:
logger.error('Failed to open file', exc_info=True)
- ini 格式例子
这里用了第三方的一个handler,ConcurrentRotatingFileHandler, 实现多进程安全
[loggers]
keys=root
[handlers]
keys=stream, rotatingFile, errorFile
[formatters]
keys=form01
[logger_root]
level=DEBUG
handlers=stream, rotatingFile, errorFile
[handler_stream]
class=StreamHandler
level=NOTSET
formatter=form01
args=(sys.stdout,)
[handler_errorFile]
class=FileHandler
level=ERROR
formatter=form01
args=('./logs/portal.log', 'a')
[handler_rotatingFile]
level=INFO
formatter=form01
class=handlers.ConcurrentRotatingFileHandler
args=('./logs/portal.log','a',50240000, 10)
[formatter_form01]
format=%(asctime)s %(name)s %(levelname)s %(message)s
datefmt=
class=logging.Formatter
引用
import logging
import logging.config
import cloghandler
logging.config.fileConfig(join(BASE_DIR, "conf/log.conf"))
logger = logging.getLogger(__name__)
默认会使用 root 这个logger,如果名称匹配就使用对应的logger。 一个logger也可以指定多个 handdler, 用来处理不同的日志级别等。
- 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": ["console"],
"propagate": "no"
}
},
"root": {
"level": "INFO",
"handlers": ["console", "info_file_handler", "error_file_handler"]
}
}
获取配置
import os
import json
import logging.config
def setup_logging(
default_path='logging.json',
default_level=logging.INFO,
env_key='LOG_CFG'
):
"""Setup logging configuration
"""
path = default_path
value = os.getenv(env_key, None)
if value:
path = value
if os.path.exists(path):
with open(path, 'rt') as f:
config = json.load(f)
logging.config.dictConfig(config)
else:
logging.basicConfig(level=default_level)
- 把日志格式化成json的工具
python-json-logger,logmatic json-logger增加的一些封装
import logging.handlers
from pythonjsonlogger import jsonlogger
import datetime
class JsonFormatter(jsonlogger.JsonFormatter, object):
def __init__(self,
fmt="%(asctime) %(name) %(processName) %(filename) %(funcName) %(levelname) %(lineno) %(module) %(threadName) %(message)",
datefmt="%Y-%m-%dT%H:%M:%SZ%z",
style='%',
extra={}, *args, **kwargs):
self._extra = extra
jsonlogger.JsonFormatter.__init__(self, fmt=fmt, datefmt=datefmt, *args, **kwargs)
def process_log_record(self, log_record):
# Enforce the presence of a timestamp
if "asctime" in log_record:
log_record["timestamp"] = log_record["asctime"]
else:
log_record["timestamp"] = datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S.%fZ%z")
if self._extra is not None:
for key, value in self._extra.items():
log_record[key] = value
return super(JsonFormatter, self).process_log_record(log_record)
参考
- Logging Cookbook 文档一定是要看的
- 日志最佳实践
- good-logging-practice-in-python
- Sentry 日志收集,分析系统,基于Python
- ConcurrentLogHandler 解决多进程日志同步问题
Python logging 模块和使用经验的更多相关文章
- python logging模块可能会令人困惑的地方
python logging模块主要是python提供的通用日志系统,使用的方法其实挺简单的,这块就不多介绍.下面主要会讲到在使用python logging模块的时候,涉及到多个python文件的调 ...
- python logging模块使用
近来再弄一个小项目,已经到收尾阶段了.希望加入写log机制来增加程序出错后的判断分析.尝试使用了python logging模块. #-*- coding:utf-8 -*- import loggi ...
- 读懂掌握 Python logging 模块源码 (附带一些 example)
搜了一下自己的 Blog 一直缺乏一篇 Python logging 模块的深度使用的文章.其实这个模块非常常用,也有非常多的滥用.所以看看源码来详细记录一篇属于 logging 模块的文章. 整个 ...
- (转)python logging模块
python logging模块 原文:http://www.cnblogs.com/dahu-daqing/p/7040764.html 1 logging模块简介 logging模块是Python ...
- Python logging 模块学习
logging example Level When it's used Numeric value DEBUG Detailed information, typically of interest ...
- python logging—模块
python logging模块 python logging提供了标准的日志接口,python logging日志分为5个等级: debug(), info(), warning(), error( ...
- Python logging模块无法正常输出日志
废话少说,先上代码 File:logger.conf [formatters] keys=default [formatter_default] format=%(asctime)s - %(name ...
- 0x03 Python logging模块之Formatter格式
目录 logging模块之Formatter格式 Formater对象 日志输出格式化字符串 LogRecoder对象 时间格式化字符串 logging模块之Formatter格式 在记录日志是,日志 ...
- 0x01 Python logging模块
目录 Python logging 模块 前言 logging模块提供的特性 logging模块的设计过程 logger的继承 logger在逻辑上的继承结构 logging.basicConfig( ...
随机推荐
- webstorm中github的配置
1.申请一个github账号,我这里的操作是已经有了账号的情况之下进行的. 打开webstorm,File-->settings,弹出settings框,输入git,得到以下界面,输入githu ...
- javaIO操作之字节输出流--OutputStream
OutputStream /** * <li>输出单个字节:public abstract void write(int b) throws IOException ; * <li& ...
- [LeetCode] Add Bold Tag in String 字符串中增添加粗标签
Given a string s and a list of strings dict, you need to add a closed pair of bold tag <b> and ...
- [LeetCode] Minesweeper 扫雷游戏
Let's play the minesweeper game (Wikipedia, online game)! You are given a 2D char matrix representin ...
- mybatis学习成长之路(一)
从小白开始学习,希望自己学习的过程可以帮助更多需要的人,参考网址:https://www.cnblogs.com/ysocean/p/7237499.html 1.mybatis的jar包下载地址:h ...
- pyqt5 动画学习(三) 指定控件的移动轨迹
这一篇来讲解自定义控件的移动轨迹 原理:我们采用QPainterPath先画一个弧线,然后加载一个物体让物体移动,设置100个关键帧,每个关键帧物体的坐标位置就是弧线的坐标位置,这样就能达到按照指定轨 ...
- [HNOI 2014]世界树
Description 题库链接 给出一棵 \(n\) 个节点的树, \(q\) 次询问,每次给出 \(k\) 个关键点.树上所有的点会被最靠近的关键点管辖,若距离相等则选编号最小的那个.求每个关键点 ...
- 51 nod 1495 中国好区间
1495 中国好区间 基准时间限制:0.7 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 阿尔法在玩一个游戏,阿尔法给出了一个长度为n的序列,他认为,一段好的区间,它的长度是& ...
- hdu 4453 splay
Looploop Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total S ...
- html5应用程序缓存
缓存概念: ------页面缓存: html.JS.CSS等,这些缓存资源是由于浏览器的行为而产生; ------数据缓存 ----------AppCache: Cache Manifest 操作 ...