Python Logging
一、简介
Python的logging模块提供了一种灵活的方式来记录日志信息。使用logging模块,你可以将日志记录到文件、控制台、syslog等不同的目标中,还可以根据日志级别过滤日志信息。logging模块还支持多个日志处理器和多个日志过滤器,可以根据需要自定义日志记录方式。
1.1 功能
logger:日志器,用于记录日志信息。logger对象可以有多个,每个logger对象可以有多个handler对象,用于将日志记录发送到不同的目标。logger对象还可以设置日志级别、过滤器等属性,用于控制日志记录的行为。
formatter:格式化器,用于将LogRecord对象转换为字符串。logging模块中提供了多种格式化器,如BasicFormatter、Formatter等。
handler:处理器,用于将日志记录发送到不同的目标,如文件、控制台、syslog等。logging模块中提供了多种处理器,如StreamHandler、FileHandler、SysLogHandler等。
getLogger()方法:用于获取logger对象。如果多次调用getLogger()方法并传入相同的名称,将返回同一个logger对象。如果不传入名称,则返回root logger对象。
getChild()方法:用于创建子logger对象。子logger对象的名称是父logger对象的名称加上一个后缀,后缀由getChild()方法的参数指定。子logger对象继承了父logger对象的所有属性,如日志级别、过滤器、处理器等。子logger对象还可以设置自己的属性,如日志级别、过滤器、处理器等。
1.2 用途
- 可以定义多种级别,按需记录
如:debug,info,warning,error,critical - 可以配置多套日志方式,记录到多个文件中
如:根据需求记录到多个文件中,app.log, task.log - 可以配置不同的Handler,控制日志以什么载体记录
如:log文件,stdout,elasticsearch等
二、文本格式
日志具体以什么载体展示取决于formatter参数,例如:
formatter = logging.Formatter(“%(asctime)s %(levelname)s %(message)s”,“%Y-%m-%d %H:%M:%S”)
import logging
import json
from logging.handlers import RotatingFileHandler
# 获取logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# 日志格式
formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s","%Y-%m-%d %H:%M:%S")
# 根据业务的不同日志,定义不同的handler
ansible_handler = RotatingFileHandler('/tmp/ansible.log', maxBytes=100000000, backupCount=100)
ansible_handler.setLevel(logging.DEBUG)
ansible_handler.setFormatter(formatter)
task_handler = RotatingFileHandler('/tmp/task.log', maxBytes=100000000, backupCount=100)
task_handler.setLevel(logging.INFO)
task_handler.setFormatter(formatter)
app_handler = RotatingFileHandler('/tmp/app.log', maxBytes=100000000, backupCount=100)
app_handler.setLevel(logging.INFO)
app_handler.setFormatter(formatter)
# 方法用于创建子记录器,从而更好地组织你的日志信息。子记录器会继承父记录器的配置,但是你可以为它们单独设置日志级别、处理器等。
logger.getChild('ansible').addHandler(ansible_handler)
logger.getChild('task').addHandler(task_handler)
logger.getChild('app').addHandler(app_handler)
# 获取子记录器
ansibleLogger = logger.getChild('ansible')
taskLogger = logger.getChild('task')
appLogger = logger.getChild('app')
# 写入日志
ansibleLogger.info('这是ansible运行日志')
taskLogger.info('这是后端任务运行日志')
appLogger.info('这是主程序运行日志')
运行日志
yuehua@yuehuadeMacBook-Pro ~$ cat /tmp/app.log
2023-03-21 17:11:29 INFO 这是主程序运行日志
yuehua@yuehuadeMacBook-Pro ~$ cat /tmp/task.log
2023-03-21 17:11:29 INFO 这是后端任务运行日志
yuehua@yuehuadeMacBook-Pro ~$ cat /tmp/ansible.log
2023-03-21 17:11:29 INFO 这是ansible运行日志
三、JSON格式
可以定义一个JsonFormatter类,继承logging.Formatter类,重写format
然后将 formatter 指向这个类的实例对象
import logging
import json
from logging.handlers import RotatingFileHandler
# 获取logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# 日志格式(JSON)
class JsonFormatter(logging.Formatter):
def format(self, record):
data = {
'timestamp': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(record.created)),
'level': record.levelname,
'message': record.getMessage(),
'module': record.module,
'line': record.lineno,
'function': record.funcName,
'logger': record.name,
}
return json.dumps(data)
formatter = JsonFormatter()
# 根据业务的不同日志,定义不同的handler
ansible_handler = RotatingFileHandler('/tmp/ansible.log', maxBytes=100000000, backupCount=100)
ansible_handler.setLevel(logging.DEBUG)
ansible_handler.setFormatter(formatter)
task_handler = RotatingFileHandler('/tmp/task.log', maxBytes=100000000, backupCount=100)
task_handler.setLevel(logging.INFO)
task_handler.setFormatter(formatter)
app_handler = RotatingFileHandler('/tmp/app.log', maxBytes=100000000, backupCount=100)
app_handler.setLevel(logging.INFO)
app_handler.setFormatter(formatter)
# 方法用于创建子记录器,从而更好地组织你的日志信息。子记录器会继承父记录器的配置,但是你可以为它们单独设置日志级别、处理器等。
logger.getChild('ansible').addHandler(ansible_handler)
logger.getChild('task').addHandler(task_handler)
logger.getChild('app').addHandler(app_handler)
# 获取子记录器
ansibleLogger = logger.getChild('ansible')
taskLogger = logger.getChild('task')
appLogger = logger.getChild('app')
# 写入日志
ansibleLogger.info('这是ansible运行日志')
taskLogger.info('这是后端任务运行日志')
appLogger.info('这是主程序运行日志')
运行日志
yuehua@yuehuadeMacBook-Pro ~$ cat /tmp/app.log
{"timestamp": "2023-03-21 17:29:44", "level": "INFO", "message": "\u8fd9\u662f\u4e3b\u7a0b\u5e8f\u8fd0\u884c\u65e5\u5fd7", "module": "wlwlwl1", "line": 55, "function": "<module>", "logger": "__main__.app"}
yuehua@yuehuadeMacBook-Pro ~$ cat /tmp/ansible.log
{"timestamp": "2023-03-21 17:29:44", "level": "INFO", "message": "\u8fd9\u662fansible\u8fd0\u884c\u65e5\u5fd7", "module": "wlwlwl1", "line": 53, "function": "<module>", "logger": "__main__.ansible"}
yuehua@yuehuadeMacBook-Pro ~$ cat /tmp/task.log
{"timestamp": "2023-03-21 17:29:44", "level": "INFO", "message": "\u8fd9\u662f\u540e\u7aef\u4efb\u52a1\u8fd0\u884c\u65e5\u5fd7", "module": "wlwlwl1", "line": 54, "function": "<module>", "logger": "__main__.task"}
四、ES
定义一个 ElasticsearchHandler 的处理器,继承 logging.Handler 类,将业务日志的handler指向这个ElasticsearchHandler的实例对象,并在初始化的时候,传入一个索引名称。
import logging
import json
import time
from elasticsearch import Elasticsearch
from elasticsearch.helpers import bulk
es = Elasticsearch("http://localhost:9200")
class ElasticsearchHandler(logging.Handler):
def __init__(self, index_name):
super().__init__()
self.index_name = index_name
def emit(self, record):
log = {
'timestamp': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(record.created)),
'level': record.levelname,
'message': record.getMessage(),
'module': record.module,
'line': record.lineno,
'function': record.funcName,
'logger': record.name,
}
es.index(index=self.index_name, body=log)
# 获取logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# 根据业务的不同日志,定义不同的handler
ansible_handler = ElasticsearchHandler('ansible')
ansible_handler.setLevel(logging.DEBUG)
task_handler = ElasticsearchHandler('task')
task_handler.setLevel(logging.INFO)
app_handler = ElasticsearchHandler('app')
app_handler.setLevel(logging.INFO)
# 方法用于创建子记录器,从而更好地组织你的日志信息。子记录器会继承父记录器的配置,但是你可以为它们单独设置日志级别、处理器等。
logger.getChild('ansible').addHandler(ansible_handler)
logger.getChild('task').addHandler(task_handler)
logger.getChild('app').addHandler(app_handler)
# 通过子记录器获取日志对象
ansibleLogger = logger.getChild('ansible')
taskLogger = logger.getChild('task')
appLogger = logger.getChild('app')
ansibleLogger.info('这是ansible运行日志')
taskLogger.info('这是后端任务运行日志')
appLogger.info('这是主程序运行日志')
获取日志
{
"took": 4,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "ansible",
"_type": "_doc",
"_id": "ymKhA4cBiDjJ60c3P1Wo",
"_score": 1.0,
"_source": {
"timestamp": "2023-03-21 18:05:10",
"level": "INFO",
"message": "\u8fd9\u662fansible\u8fd0\u884c\u65e5\u5fd7",
"module": "wlwlwl1",
"line": 50,
"function": "<module>",
"logger": "__main__.ansible"
}
}
]
}
}