Flask + echarts 轻松搞定 nginx 日志可视化(上)

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 最近,线上的业务系统不太稳定,需要分析下访问情况,能拿到的数据只有 nginx 服务器的访问日志,不过难不倒我,用合适的工具,分分钟做出图形化展示,看看怎么做的吧

思路

nginx 访问日志,记录了每次客户端请求,其中包括 ip、时间、使用的客户端等信息

通过解析每行数据,提取这些信息,然后对信息进行整理,并做一些必要的统计

最后将统计数据展示出来,可以直观地感知数据中蕴含的问题

基本思路就是这样,不过知道和做到之间地距离还有很远,为了达到目标,需要一些工具做支持

由于数据是 nginx 访问日志,所有不需要爬取,从服务器上下载就好

整理处理过程,除了 python 本身一些功能外,还离不开 pandas 的支持

最后数据展示部分,用的是 Flask + echarts,从头写,确实很有挑战,不过今天我们利用 TurboWay 同学的框架 bigdata_practice,就能轻松搞定

闲话少叙,开始吧

数据处理

下载到 nginx 访问日志,从 nginx 配置文件中可以查看日志存放地址,另外,本文源码中有附带示例日志文件,可下载使用

日志文件为文本文件,每行记录一条访问情况,例如:

124.64.19.27 - - [04/Sep/2020:03:21:12 +0800] "POST /api/hb.asp HTTP/1.1" 200 132 "http://erp.example.com/mainframe/main.html" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36" "-"

读取文本文件的行,实现比较简单,这里只对提取字段和通过 ip 确定省份做下说明

提取

提取字段的方法如下:

import re
obj = re.compile(r'(?P<ip>.*?)- - \[(?P<time>.*?)\] "(?P<request>.*?)" (?P<status>.*?) (?P<bytes>.*?) "(?P<referer>.*?)" "(?P<ua>.*?)"')
result = obj.match(line)
# print(result.group("time"))
# ip处理
ip = result.group("ip").split(",")[0].strip() # 如果有两个ip,取第一个ip
# 状态码处理
status = result.group("status")  # 状态码
# 时间处理
time = result.group("time").replace(" +0800", "") # 提取时间,并去掉时区信息
t = datetime.datetime.strptime(time, "%d/%b/%Y:%H:%M:%S")  # 格式化
# request处理
request = result.group("request")
a = request.split()[1].split("?")[0]  # 提取请求 url,去掉查询参数
# user_agent处理
ua = result.group("ua")
if "Windows NT" in ua:
    u = "windows"
elif "iPad" in ua:
    u = "ipad"
elif "Android" in ua:
    u = "android"
elif "Macintosh" in ua:
    u = "mac"
elif "iPhone" in ua:
    u = "iphone"
else:
    u = "其他设备"
# refer处理
referer = result.group("referer")

代码看着长,其实逻辑很简单,核心是提取信息的正则表达式,利用了命名分组的方式,匹配后,可以通过命名来提取数据

对提取出的数据,需要处理一下,比如请求时间,采用的是类似 UTC 时间格式,需要去掉时区,并转换为 datatime 类型

另外就是的客户端的处理,根据关键字,判断客户端类型

将提取的信息,存入一个 词典 对象中,即每行对于一个 词典 对象,最后将一个个对象追加到一个 列表 对象中,带进一步处理

获取用户省份

为了后面对访问者所在区域进行分析,需要对一些字段做处理,例如将 ip 转换为省份信息

转换主要利用的是百度的 ip 定位服务

百度的 ip 定位服务,通过认证,可以获得每日 3 万次的免费配额

通过提供的 api 可以获取 ip 地址所在的省名称

考虑到查询效率和配额限制问题,最好对 ip 定位的结果做个缓存:

import requests
import os
ak = "444ddf895 ... a5ad334ee" # 百度 ak 需申请
# ip 定位方法
def ip2province(ip):
    province = ipCache.get(ip, None)
    if province is None:
        url = f"https://api.map.baidu.com/location/ip?ak={ak}&ip={ip}&coor=bd09ll"
        try:
            province = json.loads(requests.get(url).text)['address'].split('|')[1]
            ipCache[ip] = province
            # 这里就需要写入
            with open("ip_cache.txt","a") as f:
                f.write(ip + "\t" + province + "\n")
            return province
        except Exception as e:
            return "未知"
    else:
        return province
# 初始化缓存
ipCache = {}
if os.path.exists("ip_cache.txt"):
    with open("ip_cache.txt", "r") as f:
        data = f.readline()
        while data:
            ip, province = data.strip().split("\t")
            ipCache[ip] = province
            data = f.readline()
  • 首先需要申请一个百度 app key
  • 合成请求,通过 requests  get,得到响应,从中提取到 ip 对应的省份信息
  • 对应地址缓存,将没有缓存的结果存入 ipCache 词典对象,并写入 ip_cache.txt 文件,下次启动时,用缓存文件中的内容初始化 ipCache 词典对象
  • 在每次需要获取 ip 对应地址时,先检查缓存,如果没有才通过 api 获取

数据分析

数据分析,就是对提取到的特征数据做统计加工,利用的是强大的 pandas

通过数据处理过程,我们可以得到处理好的 列表 对象,列表对象很容易创建为 pandas 的 DataFrame

接着,利用 pandas 的统计功能,将原始数据转换为可以展示用的分析数据

最后将数据存入 Excel 文件

def analyse(lst):
    df = pd.DataFrame(lst)  # 创建 DataFrame
    # 统计省份
    province_count_df = pd.value_counts(df['province']).reset_index().rename(columns={"index": "province", "province": "count"})
    # 统计时段
    hour_count_df = pd.value_counts(df['hour']).reset_index().rename(columns={"index": "hour", "hour": "count"}).sort_values(by='hour')
    # 统计客户端
    ua_count_df = pd.value_counts(df['ua']).reset_index().rename(columns={"index": "ua", "ua": "count"})
    # 数据存储
    to_excel(province_count_df, 'data.xlsx', sheet_name='省份')
    to_excel(hour_count_df, 'data.xlsx', sheet_name='按时')
    to_excel(ua_count_df, 'data.xlsx', sheet_name='客户端')
def to_excel(dataframe, filepath, sheet_name):
    if os.path.exists(filepath):j
        excelWriter = pd.ExcelWriter(filepath, engine='openpyxl')
        book = load_workbook(excelWriter.path)
        excelWriter.book = book
        dataframe.to_excel(excel_writer=excelWriter,sheet_name=sheet_name,index=None, header=None)
        excelWriter.close()
    else:
        dataframe.to_excel(filepath, sheet_name=sheet_name, index=None, header=None)
  • analyse 方法,接受一个 列表 对象,即在数据整理部分得到的数据
  • 将数据创建为 DataFrame,利用 pandas 的 value_counts 方法对对应字段数据进行统计,注意,value_counts 会做去重处理,从而统计出每个值出现的个数
  • 因为 value_counts 处理的结果,是一个 Series 对象,索引为不重复的值,所以在用 reset_index 方法处理一下,将索引转换为一个正常列,并对列名做了替换,以便后续处理更方便
  • 由于 value_counts 后的结果是按统计数量从多到少排列的,对应按时间的统计有些奇怪,所以利用 sort_values 方法,按时间列做了重新排序
  • to_excel 方法是为了将数据导出为 excel,可以支持导入不同 sheet,以便做数据展示

数据分析部分,可以从不同的角度对数据进行统计分析,最终将需要展示的数据存入 Excel,当然根据需要也可以存入其他数据库


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
打赏
0
0
0
0
14
分享
相关文章
ELK实现nginx、mysql、http的日志可视化实验
通过本文的步骤,你可以成功配置ELK(Elasticsearch, Logstash, Kibana)来实现nginx、mysql和http日志的可视化。通过Kibana,你可以直观地查看和分析日志数据,从而更好地监控和管理系统。希望这些步骤能帮助你在实际项目中有效地利用ELK来处理日志数据。
190 90
要统计Nginx的客户端IP,可以通过分析Nginx的访问日志文件来实现
要统计Nginx的客户端IP,可以通过分析Nginx的访问日志文件来实现
306 3
Hadoop-06-Hadoop集群 历史服务器配置 超详细 执行任务记录 JobHistoryServer MapReduce执行记录 日志聚合结果可视化查看
Hadoop-06-Hadoop集群 历史服务器配置 超详细 执行任务记录 JobHistoryServer MapReduce执行记录 日志聚合结果可视化查看
88 1
Tensorboard可视化学习笔记(一):如何可视化通过网页查看log日志
关于如何使用TensorBoard进行数据可视化的教程,包括TensorBoard的安装、配置环境变量、将数据写入TensorBoard、启动TensorBoard以及如何通过网页查看日志文件。
484 0
nginx error日志 client intended to send too large body: 1434541 bytes 如何处理?
【8月更文挑战第27天】nginx error日志 client intended to send too large body: 1434541 bytes 如何处理?
584 6
在Linux中,如何统计ip访问情况?分析 nginx 访问日志?如何找出访问页面数量在前十位的ip?
在Linux中,如何统计ip访问情况?分析 nginx 访问日志?如何找出访问页面数量在前十位的ip?