Python 解析日志之命名元组

  • Post category:Python

Python中的“命名元组”(NamedTuple)是一个类工厂,可以为一个类生成一个带字段名的元组子类。与普通元组相比,“命名元组”多了字段名和可读性。

而解析日志是一项常见的任务。在Python中,可以使用“命名元组”来存储日志记录,使代码更加规范、易读、易维护。

以下是Python 解析日志之命名元组使用方法的完整攻略,包括定义命名元组、创建命名元组实例、为命名元组设值等具体步骤。

1. 定义命名元组

可以使用collections模块中的namedtuple函数来定义命名元组。

from collections import namedtuple

LogRecord = namedtuple('LogRecord', ['timestamp', 'level', 'message'])

上述代码定义了一个名为LogRecord的命名元组,包含3个字段:timestamplevelmessage

2. 创建命名元组实例

可以使用namedtuple返回的类来创建命名元组实例。

log_record = LogRecord('2022-06-10 15:30:05', 'INFO', 'Application started')

上述代码创建了一个名为log_record的命名元组实例,并为其设定了3个字段的值。

3. 访问命名元组字段

可以使用.操作符来访问命名元组的字段,与普通元组相比,字段名更加易读。

print(log_record.timestamp)
print(log_record.level)
print(log_record.message)

上述代码分别访问了命名元组实例的timestamplevelmessage字段,并将它们分别打印出来。

4. 为命名元组设值

命名元组是不可变的,不能直接修改已有实例的值,但是可以使用_replace方法重新创建一个实例。

log_record = log_record._replace(message='Application stopped')

上述代码使用_replace方法创建了一个新的命名元组实例,并将message字段指定为了新的值。原有的实例并没有改变,依然保持不可变性。

示例1:解析Nginx的日志记录

from collections import namedtuple

LogRecord = namedtuple('LogRecord', ['remote_addr', 'datetime', 'request', 'status', 'response_length', 'referer', 'user_agent'])

log_line = '192.168.1.1 - - [10/Jun/2022:14:59:22 +0800] "GET / HTTP/1.1" 200 235 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36"'

remote_addr, _, _, datetime, request, status, response_length, referer, user_agent = log_line.split('" "')
datetime = datetime[1:]
status, response_length = status.split(), response_length.split()[0]
log_record = LogRecord(remote_addr, datetime, request, status, response_length, referer, user_agent)

print(log_record.remote_addr)
print(log_record.datetime)
print(log_record.request)
print(log_record.status)
print(log_record.response_length)
print(log_record.referer)
print(log_record.user_agent)

上述代码将一个Nginx日志记录解析成了一个包含7个字段的命名元组实例。

示例2:解析Jenkins的日志记录

from collections import namedtuple

LogRecord = namedtuple('LogRecord', ['timestamp', 'level', 'component', 'message'])

log_line = '2022-06-10 15:47:22,543 INFO jenkins.InitReactorRunner$1#onAttained: Completed initialization'
timestamp, level, component, message = log_line.split(' ', 3)
timestamp = timestamp + "." + log_line.split(',')[1].split()[0]
log_record = LogRecord(timestamp, level, component, message)

print(log_record.timestamp)
print(log_record.level)
print(log_record.component)
print(log_record.message)

上述代码将一个Jenkins日志记录解析成了一个包含4个字段的命名元组实例。注意到了字段个数和名称的变化。