python日志logging配置

  • 为了方便ELK收集日志,将日志打印成json格式
  • 开发过程中,使用json格式不方便排查问题
  • 本文章使用python的logging模块,一步步增加配置,来说明每个组件作用

原始日志

  • python可以使用两种方式打印
  • python默认打印级别为'WARNING'
import logging

# 直接使用logging打印日志
logging.info('info') # 未打印
logging.warning('warning') # WARNING:root:warning
logging.error('error') # ERROR:root:error # 使用logger打印日志
logger = logging.getLogger('demo')
logger.info('info') # 未打印
logger.warning('warning') # WARNING:demo:warning
logger.error('error') # ERROR:demo:error

使用字典配置

  • version为固定字段,目前为1
  • 将级别设置为'INFO'
import logging
import logging.config def use_config():
"""配置日志行为"""
config = {"version": 1, "root": {"level": "INFO"}}
logging.config.dictConfig(config) use_config() # 直接使用logging打印日志
logging.info('info') # INFO:root:info
logging.warning('warning') # WARNING:root:warning
logging.error('error') # ERROR:root:error # 使用logger打印日志
logger = logging.getLogger('demo')
logger.info('info') # INFO:demo:info
logger.warning('warning') # WARNING:demo:warning
logger.error('error') # ERROR:demo:error

记录器

  • "loggers"为指定记录器
  • "root"实质上也是记录器,python默认的记录器
    • logging直接打印日志,相当于logging.getLogger('root')
    • 没有找到记录器名字的使用默认记录器(即'root')
import logging
import logging.config def use_config():
"""配置日志行为"""
config = {
"version": 1,
"root": {
"level": "WARNING"
},
"loggers": {
"demo": {
"level": "ERROR"
}
}
}
logging.config.dictConfig(config) use_config() # 直接使用logging打印日志
logging.info('info') # 未打印
logging.warning('warning') # WARNING:root:warning
logging.error('error') # ERROR:root:error # 使用logger打印日志
logger = logging.getLogger('demo')
logger.info('info') # 未打印
logger.warning('warning') # 未打印
logger.error('error') # ERROR:demo:error # 未找到记录器时,使用'root'记录器
logger2 = logging.getLogger('demo2')
logger2.info('info') # 未打印
logger2.warning('warning') # WARNING:demo2:warning
logger2.error('error') # ERROR:demo2:error

处理器及格式化器

  • "handlers"为处理器

    • 处理器有很多类型,可以打印屏幕、打印文件、发送邮件、发送http请求等,详情查看Useful Handlers官方文档
    • 记录器中可以指定多个处理器
    • 下面例子打印屏幕
  • "formatters"为格式化器
    • format:使用python内置格式化器格式化日志信息
import logging
import logging.config def use_config():
"""配置日志行为"""
config = {
"version": 1,
"root": {
"level": "INFO",
"handlers": ["console_handler"]
},
"handlers": {
"console_handler": {
"class": "logging.StreamHandler",
"formatter": "console_formatter",
"stream": "ext://sys.stdout"
}
},
"formatters": {
"console_formatter": {
"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
}
}
}
logging.config.dictConfig(config) use_config() logging.info('info') # 2022-10-25 20:16:59,073 - root - INFO - info
logging.warning('warning') # 2022-10-25 20:16:59,073 - root - WARNING - warning
logging.error('error') # 2022-10-25 20:16:59,074 - root - ERROR - error

自定义格式化器

  • 自定义格式化器继承logging.Formatter,重写format方法
  • 配置中,字段名使用"class"代表自定义格式化器
    • 填入导入该类的字符串,如下代码,在"log_demo.py"文件里的"MyFormatter",即为"log_demo.MyFormatter"
    • 类型导入会执行一遍代码,重复调用配置方法会添加多个处理器,导致打印多遍
    • record中有很多字段,这里不展示,自行打印查看
# log_demo.py
import logging
import logging.config class MyFormatter(logging.Formatter):
def format(self, record: logging.LogRecord) -> str:
"""重写日志格式化字符串"""
return f"[{record.name}] [{record.levelname}] {record.msg}" def use_config():
"""配置日志行为"""
config = {
"version": 1,
"root": {
"level": "INFO",
"handlers": ["console_handler"]
},
"handlers": {
"console_handler": {
"class": "logging.StreamHandler",
"formatter": "console_formatter",
"stream": "ext://sys.stdout"
}
},
"formatters": {
"console_formatter": {
"class": "log_demo.MyFormatter"
}
}
}
logging.config.dictConfig(config) if __name__ == "__main__":
"""
实例化MyFormatter类时,会执行一遍代码
将代码放在__main__里,否则会打印两遍
"""
use_config() logging.info('info') # [root] [INFO] info
logging.warning('warning') # [root] [WARNING] warning
logging.error('error') # [root] [ERROR] error

extra额外字段

  • 日志方法中有"extra"字段,丰富日志信息
  • 打印
import logging
import logging.config class MyFormatter(logging.Formatter):
def format(self, record: logging.LogRecord) -> str:
"""重写日志格式化字符串"""
for i in record.__dict__:
print(i, end=',')
print('')
return f"[{record.name}] [{record.levelname}] {record.msg}" def use_config():
"""配置日志行为"""
config = {
"version": 1,
"root": {
"level": "INFO",
"handlers": ["console_handler"]
},
"handlers": {
"console_handler": {
"class": "logging.StreamHandler",
"formatter": "console_formatter",
"stream": "ext://sys.stdout"
}
},
"formatters": {
"console_formatter": {
"class": "log_demo.MyFormatter"
}
}
}
logging.config.dictConfig(config) if __name__ == "__main__":
"""
实例化MyFormatter类时,会执行一遍代码
将代码放在__main__里,否则会打印两遍
"""
use_config() logging.info('info')
# name,msg,args,levelname,levelno,pathname,filename,module,exc_info,exc_text,stack_info,lineno,funcName,created,msecs,relativeCreated,thread,threadName,processName,process,
# [root] [INFO] info # extra增加了'a','b',可以看到record对象也增加了'a','b'两个字段
logging.info('extra info', extra={'a': 1, 'b': 2})
# name,msg,args,levelname,levelno,pathname,filename,module,exc_info,exc_text,stack_info,lineno,funcName,created,msecs,relativeCreated,thread,threadName,processName,process,a,b,
# [root] [INFO] extra info

最终代码

  • 增加环境变量"LOG_MODE",用来控制打印行为

    • 为"json"时,打印json格式字符串,提供给ELK收集
    • 为"text"时,打印成文本模式,方便开发时查看
  • json转换时加上"ensure_ascii=False",否则中文会被转换为ASCII

代码

import os
import json
import logging
import logging.config
from datetime import datetime, timezone, timedelta class JsonFormatter(logging.Formatter):
__TZ = timezone(timedelta(hours=+8)) def format(self, record: logging.LogRecord) -> str:
# ELK收集需要使用带时区的时间戳,key必须为"@timestamp"
create_time = datetime.fromtimestamp(record.created)
kv = {'@timestamp': create_time.astimezone(self.__TZ).isoformat()}
if len(record.args) > 0:
kv['message'] = record.msg % record.args
else:
kv['message'] = record.msg
# 报错信息
if record.exc_info:
kv['err_info'] = self.formatException(record.exc_info) for k in record.__dict__:
v = getattr(record, k)
# 其他类型json转换可能报错
if v is None or isinstance(v, (int, float, bool, str)):
kv[k] = v
else:
kv[k] = str(v)
return json.dumps(kv, ensure_ascii=False) def use_config():
"""配置日志行为"""
if os.environ.get('LOG_MODE') == "json":
format_data = {"class": "log_demo.JsonFormatter"}
else:
format_data = {
"format": "[%(asctime)s] [%(name)s] [%(levelname)s] %(message)s"
} config = {
"version": 1,
"root": {
"level": "INFO",
"handlers": ["console_handler"]
},
"handlers": {
"console_handler": {
"class": "logging.StreamHandler",
"formatter": "console_formatter",
"stream": "ext://sys.stdout"
}
},
"formatters": {
"console_formatter": format_data
}
} logging.config.dictConfig(config) if __name__ == "__main__":
use_config() logging.info('info')
logging.info('extra info', extra={'a': 1, 'b': 2})

text效果

# linux设置环境变量
export LOG_MODE=text
# windows设置环境变量
set LOG_MODE=text python log_demo.py
[2022-10-26 19:11:07,468] [root] [INFO] info
[2022-10-26 19:11:07,468] [root] [INFO] extra info

json效果

# linux设置环境变量
export LOG_MODE=json
# windows设置环境变量
set LOG_MODE=json python log_demo.py
{"@timestamp": "2022-10-26T20:10:42.168191+08:00", "message": "info", "name": "root", "msg": "info", "args": "()", "levelname": "INFO", "levelno": 20, "pathname": "e:\\Work\\Code\\TestCode\\everything\\log_demo.py", "filename": "log_demo.py", "module": "log_demo", "exc_info": null, "exc_text": null, "stack_info": null, "lineno": 66, "funcName": "<module>", "created": 1666786242.168191, "msecs": 168.19095611572266, "relativeCreated": 35.9044075012207, "thread": 22716, "threadName": "MainThread", "processName": "MainProcess", "process": 19576}
{"@timestamp": "2022-10-26T20:10:42.169210+08:00", "message": "extra info", "name": "root", "msg": "extra info", "args": "()", "levelname": "INFO", "levelno": 20, "pathname": "e:\\Work\\Code\\TestCode\\everything\\log_demo.py", "filename": "log_demo.py", "module": "log_demo", "exc_info": null, "exc_text": null, "stack_info": null, "lineno": 67, "funcName": "<module>", "created": 1666786242.1692102, "msecs": 169.21019554138184, "relativeCreated": 36.92364692687988, "thread": 22716, "threadName": "MainThread", "processName": "MainProcess", "process": 19576, "a": 1, "b": 2}

python日志logging配置的更多相关文章

  1. python 日志的配置,python对日志封装成类,日志的调用

    # python 日志的配置,python对日志封装成类,日志的调用 import logging # 使用logging模块: class CLog: # --------------------- ...

  2. django/python日志logging 的配置以及处理

    日志在程序开发中是少不了的,通过日志我们可以分析到错误在什么地方,有什么异常.在生产环境下有很大的用处.在java 开发中通常用 log4j,logback 等三方组件.那么在 django中是怎么处 ...

  3. Python日志(logging)模块,shelve,sys模块

    菜鸟学python第十七天 1.logging 模块 logging模块即日志记录模块 用途:用来记录日志 为什么要记录日志: 为了日后复查,提取有用信息 如何记录文件 直接打开文件,往里写东西 直接 ...

  4. Python日志logging

    logging 用于便捷记录日志且线程安全的模块 1.单文件日志 import logging logging.basicConfig(filename='log.log', format='%(as ...

  5. python 日志logging设置按天进行保存,保存近7天,过期日志自动清理

    参考文章(写的很详细):https://www.cnblogs.com/xujunkai/p/12364619.html 前言: 跑接口自动化或者其他程序运行时,如果只能保存一份log文件,可能会存在 ...

  6. python日志模块配置

    import logging logging.basicConfig(filename= 'out.log',filemode= 'w+', level= logging.DEBUG, format= ...

  7. [编程基础] Python日志记录库logging总结

    Python日志记录教程展示了如何使用日志记录模块在Python中进行日志记录. 文章目录 1 介绍 1.1 背景 1.2 Python日志记录模块 1.3 根记录器 2 Python logging ...

  8. 转 使用Python的logging.config.fileConfig配置日志

    Python的logging.config.fileConfig方式配置日志,通过解析conf配置文件实现.文件 logglogging.conf 配置如下: [loggers]keys=root,f ...

  9. python - django (logging 日志配置和简单使用)

    1. settings 配置 # 配置日志 LOGGING = { 'version': 1, 'disable_existing_loggers': True, 'formatters': { 's ...

  10. python logging 配置

    python logging 配置 在python中,logging由logger,handler,filter,formater四个部分组成,logger是提供我们记录日志的方法:handler是让 ...

随机推荐

  1. 【力扣】剑指 Offer II 092. 翻转字符

    题目 解题思路 一个很暴力的想法,在满足单调递增的前提下,使每一位分别取 1 或 0,去看看哪个结果小. 递归函数定义int dp(StringBuilder sb, int ind, int pre ...

  2. Coolify系列01- 从0到1超详细手把手教你上手Heroku 和 Netlify 的开源替代方案

    什么是Coolify 一款超强大的开源自托管 Heroku / Netlify 替代方案 coolLabs是开源.自托管和以隐私为中心的应用程序和服务的统称 为什么使用Coolify 只需单击几下即可 ...

  3. 1月9日内容总结——linux相关知识简介、虚拟化软件vmware、远程链接工具xshell

    目录 一.linux常见岗位 二.计算机的种类与服务器 三.服务器品牌 四.服务器内部组成 五.服务器磁盘阵列 六.linux简介 1.什么是linux 2.linux发展史 3.Linux系统的特点 ...

  4. Time Series Analysis (Best MSE Predictor & Best Linear Predictor)

    Time Series Analysis Best MSE (Mean Square Error) Predictor 对于所有可能的预测函数 \(f(X_{n})\),找到一个使 \(\mathbb ...

  5. Python实用代码片段(1)-rot13加密

    Python之禅:THIS.PY 你安装了python之后,能在Lib目录下找到一个this.py的文件,就是此处的内容. s = """Gur Mra bs Clgub ...

  6. python加密解密之AES

    def encrypt(self, params: str, key: str, iv: str) -> str: """加密""" ...

  7. JAVA虚拟机09---垃圾回收---经典垃圾回收器

    1.Serial收集器 1.1简介 Serial收集器是最基础.历史最悠久的收集器,曾经(在JDK 1.3.1之前)是HotSpot虚拟机新生代收集器的唯一选择   1.2使用算法 标记-复制算法 1 ...

  8. Listen 1音乐播放器

    Listen 1 Listen 1可以搜索和播放来自网易云音乐,QQ音乐,酷狗音乐,酷我音乐,Bilibili,咪咕音乐网站的歌曲,让你的曲库更全面.还支持歌单功能,你可以方便的播放,收藏和创建自己的 ...

  9. Windows服务安装小工具

    主要为了方便Windows服务的安装卸载,不需要使用CMD命令. 先给大家小工具的效果图: 使用此工具需要注意一下几点: 1.服务程序的.NET Framework版本: 2.服务名称与服务执行程序名 ...

  10. 【已解决】SQL2012启动时报错:cannot find one or more cpmponents

    下载Microsoft Visual Studio 2010 Shell(Isolate)-CHS安装即可 下载地址:Visual Studio 独立 Shell 下载及安装:点击同意许可,选择vs2 ...