术→技巧, 研发

使用Python解析Nginx日志

钱魏Way · · 15 次浏览

最近看了眼Nginx的日志,发现个人博客的日志上有很多爬虫在抓数据,还有在扫描漏洞的,搞不明白普普通通的一个个人博客得罪了谁。于是决定做一个简单的Nginx日志解析工具来稍微分析下数据。

Nginx的格式

Nginx日志对于统计、系统服务排错很有用。Nginx日志主要分为两种:access_log(访问日志)和error_log(错误日志)。通过访问日志我们可以得到用户的IP地址、浏览器的信息,请求的处理时间等信息。错误日志记录了访问出错的信息,可以帮助我们定位错误的原因。本文将详细描述一下如何配置Nginx日志。

access_log

访问日志主要记录客户端的请求。客户端向Nginx服务器发起的每一次请求都记录在这里。客户端IP,浏览器信息,referer,请求处理时间,请求URL等都可以在访问日志中得到。当然具体要记录哪些信息,你可以通过log_format指令定义。

Nginx预定义了名为combined日志格式,如果没有明确指定日志格式默认使用该格式:

log_format combined '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent"';

如果不想使用Nginx预定义的格式,可以通过log_format指令来自定义。下面是log_format指令中常用的一些变量:

字段 含义 示例
占位符
body_bytes_sent 响应body字节数 3650
bytes_sent 响应总字节数 175
host IP或域名(不包括端口) 10.10.10.14
http_host IP或域名(包括端口) 10.10.10.14:81
http_referer referer信息 http://10.10.10.14/
http_user_agent UA信息 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.90 Safari/537.36
http_x_forwarded_for XFF信息 192.168.1.1
remote_addr 客户端地址 10.10.10.1
remote_user 客户端认证用户名 admin
request 请求URI和协议 GET /favicon.ico HTTP/1.1
request_body 请求的body
request_length 请求长度 571
request_method 请求方法 GET
request_time 请求处理时间 0.000
response_body 返回的body
response_header_data 响应头数据
schema 协议 http
server_name 虚拟主机名称
server_port 服务器端口
server_protocol 服务器协议
ssl_cipher 交换数据中的算法
ssl_protocol SSL协议版本
status 返回状态码 404
time_local 时间戳 16/Jun/2019:23:29:50 -0400
upstream_addr 后端提供服务地址
upstream_connect_time 与服务器连接所花费的时间
upstream_response_time 后端处理时间
upstream_status upstream状态 200

以下为一个默认记录格式下的请求记录:

123.6.49.9 - - [28/Dec/2023:00:26:02 +0800] "GET /aic-bic.html HTTP/2.0" 200 16923 "http://baidu.com/" "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Mobile Safari/537.36"

error_log

Nginx 的 error.log 记录了服务器在运行过程中遇到的错误和异常信息,这些信息对于管理员来说是非常重要的调试和排查工具。error.log 中包含的信息通常可以帮助管理员了解服务器的状态和运行情况,以及定位问题所在。下面是 error.log 中常见的几类信息:

  • 启动和关闭信息:log 中会记录服务器的启动和关闭信息,包括启动时间、运行时间、关闭原因等。这些信息对于管理员来说是了解服务器状态的重要参考。
  • 请求处理错误:如果服务器在处理请求时出现错误,log 会记录相关的错误信息,包括请求的 URL、客户端 IP、错误类型等。这些信息可以帮助管理员定位问题所在,如请求超时、请求大小超出限制等。
  • 连接和网络错误:如果服务器在处理连接或网络时出现错误,log 会记录相关的错误信息,如不能连接到后端服务器、连接超时等。这些信息可以帮助管理员找到网络问题所在。
  • 服务器错误:如果服务器本身出现错误,如内存不足、磁盘满了等,log 会记录相应的错误信息。这些信息可以帮助管理员及时发现并解决服务器问题。
  • 安全问题:如果服务器受到攻击或发现安全问题,log 也会记录相关信息,如恶意请求、攻击尝试等。这些信息对于管理员来说是保护服务器安全的重要参考。

需要注意的是,error.log 记录的信息可能会包含敏感信息,如客户端 IP、请求 URL 等,因此需要妥善保护日志文件的访问权限,以免被未授权的用户查看或利用。

Python解析Nginx日志

这次要解析的主要是针对access.log进行解析,解析日志代码如下:

import re
import pandas as pd

with open('data/www.biaodianfu.com.access.log', 'r') as file:
    logs = file.readlines()
    log_pattern = r'(\d+\.\d+\.\d+\.\d+) - (.+?) \[(.+?)\] "(.+?)" (\d+) (\d+) "(.+?)" "(.+?)"'
    parsed_logs = []
    for log in logs:
        match = re.match(log_pattern, log)
        if match:
            parsed_logs.append(match.groups())
    df = pd.DataFrame(parsed_logs, columns=['ip', 'remote_user', 'time_local', 'request', 'status', 'body_bytes_sent',
                                            'http_referer', 'user_agent'])
    df['time_local'] = pd.to_datetime(df['time_local'], format='%d/%b/%Y:%H:%M:%S %z').dt.tz_localize(None)
    df[['method', 'path', 'protocol']] = df['request'].str.split(' ', n=2, expand=True)


    def judge_request_type(path):
        if path:
            path = path.split('?')[0]
            if path.endswith(('.jpg', '.jpeg', '.png', '.gif', '.svg')):
                return '图片'
            elif path.endswith(('/feed')):
                return 'Feed'
            elif path.endswith(('.html', '.php')):
                return '网页'
            elif path.endswith('.js'):
                return 'JavaScript文件'
            elif path.endswith('.css'):
                return 'CSS文件'
            elif path.endswith(('.woff2', '.ttf')):
                return '字体'
            else:
                return '其他'
        else:
            return '首页'


    df['request_type'] = df['path'].apply(judge_request_type)

    # 调整显示设置
    # pd.set_option('display.max_columns', 10)
    # pd.set_option('display.max_rows', 50)
    # pd.set_option('display.width', 1000)
    # pd.set_option('display.max_colwidth', 50)
    # print(df.head())

    df.to_excel('nginx-log.xlsx')

这段代码的主要逻辑是定义了一个正则表达式 log_pattern,用于匹配 Nginx 日志的各个字段,并将它们作为一个元组添加到 parsed_logs 列表中。然后将数据转换为Pandas的DataFrame,再进行一些逻辑上的处理。然后保存到Excel中。由于数据量较少后续统计在Excel中进行。

One Reply to “使用Python解析Nginx日志”

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注