[py]access日志入mysql-通过flask前端展示
pymysql组装sql入库日志
pymysql模块的用法
采集这些指标(metirc)都是linux环境,会用到mysql,做为数据的存储,我用docker来启动
docker run \
-p 3306:3306 \
-v /data/mysql:/var/lib/mysql \
-v /etc/localtime:/etc/localtime \
--name mysql5 \
--restart=always \
-e MYSQL_ROOT_PASSWORD=123456 \
-d mysql:5.6.23 \
--character-set-server=utf8 \
--collation-server=utf8_general_ci
create database mem;
create table mem_used(used int, time int)
- 时间格式
>>> import time
>>> time.time()
1516860432.386474
- 入库后是整形,db自动处理, 也可以入库前int(time).
MySQL [mem]> select * from mem_used;
+-----------+------------+
| used | time |
+-----------+------------+
| 628658176 | 1516842082 |
| 628813824 | 1516842083 |
| 628936704 | 1516842084 |
| 628936704 | 1516842085 |
...
一个用法实例, 获取指标(通过psutil模块直接获取到已使用的内存) 也可以自己算出.
import psutil
import time
import pymysql as ms
con = ms.connect(host='127.0.0.1', user='root', passwd='123456', db='mem')
con.autocommit(True)
cur = con.cursor()
while True:
used = psutil.virtual_memory().used
sql = 'insert into mem_used values(%s,%s)' % (used / 1024 / 1024, int(time.time())) ## Mb
cur.execute(sql)
time.sleep(1)
- %s可以接受任意类型的值
后面会将db操作封装成模块.
说下本次的任务
- 本次的任务是将apache的access.log的(ip+状态)+出现次数, 入库到mysql里做分析. 分析网站访问的top10
- 日志样式如下, 以空格分隔 arr[0] arr[8] 分别是ip和状态码
61.159.140.123 - - [23/Aug/2014:00:01:42 +0800] "GET /favicon.ico HTTP/1.1" 404 \ "-" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.66 Safari/537.36 LBBROWSER" "-"
通过pymysql模块操作mysql数据库
将结果放在res={}一个大的字典里. 核心统计思路如下. 如果字典无key,则value初始化为1; 如果字典有key,则 以key对应的value +1
- 为何是这种格式,取决于echarts数据格式所需. 通常是找到一个合适的图,对图中数据胸有程序,即可以看到它需要一些什么数据,在看下echarts代码,看下需要什么格式的数据, 然后后端组装, json.dumps后返回.
res[(ip, status)] = res.get((ip, status), 0) + 1
- 对字典的值排序
- 遍历日志文件,获取到一个大的字典如下
res = {('182.145.101.123', '200'): 302, ('139.205.220.131', '404'): 1, ('119.146.75.13', '304'): 10, ('59.39.103.85', '200'): 56, ... }
- 对字典排序 转成 列表 后插入
print sorted(res.items(), key=lambda x: x[1], reverse=True)
[(('123.174.51.164', '200'), 6930), (('117.63.146.40', '200'), 1457), (('118.112.143.148', '404'), 1336), (('111.85.34.165', '200'), 1325), ...]
- 对排序后的列表(字典),字符串拼接sql,并插入数据库
for i in sorted(res.items(), key=iambda x: x[1], reverse=True):
sql = "insert into iog vaiues ('%s','%s','%s')" % (i[0][0], i[0][1], i[1])
db.execute(sql)
代码组织
入库代码
log2db.py
#!/usr/bin/env python
# coding=utf-8
from dbutils import DB
# 连接mysql
db = DB(
host="127.0.0.1",
user="root",
passwd="",
db="logtest"
)
# 日志处理成一个大的指定格式的字典(已统计好出现的次数) ((ip, status), count)
res = {}
with open('log.txt') as f:
for line in f:
if line == "\n":
continue
arr = line.split(" ")
ip = arr[0]
status = arr[8]
res[(ip, status)] = res.get((ip, status), 0) + 1
# 组合sql,执行sql入库日志
for l in sorted(res.items(), key=lambda x: x[1], reverse=True):
# {('192.168.1.1',404): 1000,('192.168.1.1',403): 3000,('192.168.1.1',200): 2000,}
sql = "insert into log values ('%s','%s','%s')" % (l[0][0], l[0][1], l[1])
db.execute(sql)
dbutils.py
#!/usr/bin/env python
# coding=utf-8
import pymysql as ms
class DB:
def __init__(self, host, user, passwd, db):
self.host = host
self.user = user
self.passwd = passwd
self.db = db
self.connect()
def connect(self):
self.conn = ms.connect(
host=self.host,
user=self.user,
passwd=self.passwd,
db=self.db
)
self.conn.autocommit(True)
self.cursor = self.conn.cursor()
def execute(self, sql):
try:
self.cursor.execute(sql)
except Exception as e:
self.cursor.close()
self.conn.close()
self.connect()
return self.execute(sql)
else:
return self.cursor
# def query(self,tables):
# sql = 'select * from users'
# self.cursor.execute(sql)
# return self.cursor.fetchall()
下载实例日志: https://github.com/lannyMa/flask_info/blob/master/demo5/log.txt
执行脚本入库
python log2db.py
结果查看
入库完成后, flask前端展示+echarts
将入库的日志通过flask前端展示
难点是找图形的数据模型,即json数据格式. 后端返回. 所以当一幅图出来后,要对其上面有啥数据,啥数据是后端返回的,要胸有成竹, 通过代码+浏览器f12conson.log打印出来.
echarts官网上去看最简单实例的教程,用flask展示出来
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ECharts</title>
<!-- 引入 echarts.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/4.0.2/echarts.min.js"></script>
</head>
<body>
<!-- 为ECharts准备一个具备大小(宽高)的Dom -->
<div id="main" style="width: 600px;height:400px;"></div>
<script type="text/javascript">
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
// 指定图表的配置项和数据
var option = {
title: {
text: 'ECharts 入门示例'
},
tooltip: {},
legend: {
data: ['销量']
},
xAxis: {
data: ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"]
},
yAxis: {},
series: [{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
</script>
</body>
</html>
flask启动展示
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('demo.html')
if __name__ == '__main__':
app.run(debug=True)
先找一个合适的echarts图,观察它所需的接口数据格式,后设计接口
它的源码如下
option = {
title : {
text: '某站点用户访问来源',
subtext: '纯属虚构',
x:'center'
},
tooltip : {
trigger: 'item',
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
legend: {
orient: 'vertical',
left: 'left',
data: ['直接访问','邮件营销','联盟广告','视频广告','搜索引擎']
},
series : [
{
name: '访问来源',
type: 'pie',
radius : '55%',
center: ['50%', '60%'],
data:[
{value:335, name:'直接访问'},
{value:310, name:'邮件营销'},
{value:234, name:'联盟广告'},
{value:135, name:'视频广告'},
{value:1548, name:'搜索引擎'}
],
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
下载后,修改echarts-pie.html源码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>ECharts</title>
<!-- 引入 echarts.js -->
<script src="/static/jquery.min.js"></script>
<script src="/static/echarts.min.js"></script>
</head>
<body>
<!-- 为ECharts准备一个具备大小(宽高)的Dom画布 -->
<div id="main" style="width: 600px;height:400px;"></div>
<script type="text/javascript">
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
// 指定图表的配置项和数据
var option = {
title: {
text: '某站点用户访问来源',
{# subtext: '纯属虚构',#}
x: 'center'
},
tooltip: {
trigger: 'item',
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
toolbox: {
feature: {
saveAsImage: {
show: true
}
}
},
legend: {
orient: 'vertical',
left: 'left',
{# data: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索引擎']#}
},
series: [
{
name: '访问来源',
type: 'pie',
radius: '55%',
center: ['50%', '60%'],
{# data: [#}
{# {value: 335, name: '直接访问'},#}
{# {value: 310, name: '邮件营销'},#}
{# {value: 234, name: '联盟广告'},#}
{# {value: 135, name: '视频广告'},#}
{# {value: 1548, name: '搜索引擎'}#}
{# ],#}
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
//使用jq去访问api获取得到数据.
$.getJSON('/piedata', function (res) {
option.legend.data = res.legend
option.series[0].data = res.data
// 使用刚指定的配置项和数据显示图表-绑定数据
myChart.setOption(option);
})
</script>
</body>
</html>
我们知道了前端js需要的数据所需要的数据格式后,就从后端构造这样的api,供前端调用
- api需返回数据的格式
{"data": [{"name": 200, "value": 49691}, {"name": 206, "value": 32}, {"name": 301, "value": 2}, {"name": 304, "value": 7584}, {"name": 403, "value": 1}, {"name": 404, "value": 3858}], "legend": [200, 206, 301, 304, 403, 404]}
- js访问接口方法
$.getJSON('/piedata', function (res) {
option.legend.data = res.legend
option.series[0].data = res.data
myChart.setOption(option); //获取后直接绑定
})
设计top10状态码的api
- 目标是
即访问
http://127.0.0.1:5000/piedata
返回json数据:
{"data": [{"name": 200, "value": 49691}, {"name": 206, "value": 32}, {"name": 301, "value": 2}, {"name": 304, "value": 7584}, {"name": 403, "value": 1}, {"name": 404, "value": 3858}], "legend": [200, 206, 301, 304, 403, 404]}
- 查库后得到的结果
- 用sql语句做数据汇聚,查出status 和 对应的总数, 按照状态码总数来排序
select status,sum(count) from log group by status;
查询结果如下
- flask写api
- cur.fetchall返回的结果,需对其遍历,重组一定格式的数据
((200, Decimal('49691')), (206, Decimal('32')), (301, Decimal('2')), (304, Decimal('7584')), (403, Decimal('1')), (404, Decimal('3858')))
@app.route("/piedata")
def piedata():
sql = "select status,sum(count) from log group by status";
cur = db.execute(sql)
# 构造前端所需的数据结构
res = {
'legend': [],
'data': []
}
for c in cur.fetchall():
code = c[0]
count = int(c[1])
res['legend'].append(code)
res['data'].append({
'name': code,
'value': count
})
print(res)
return json.dumps(res)
- 重组后数据格式如下
{'data': [{'name': 200, 'value': 49691}, {'name': 206, 'value': 32}, {'name': 301, 'value': 2}, {'name': 304, 'value': 7584}, {'name': 403, 'value': 1}, {'name': 404, 'value': 3858}], 'legend': [200, 206, 301, 304, 403, 404]}
- 通过json模块处理后返回给将这批数据返回给前端
最终访问
实现前端html展示
@app.route("/")
def index():
return render_template("echarts-pie.html")
最终效果:
小结
[py]access日志入mysql-通过flask前端展示的更多相关文章
- 日志分析平台ELK之前端展示kibana
之前的博客一直在聊ELK集群中的存储.日志收集相关的组件的配置,但通常我们给用户使用不应该是一个黑黑的shell界面,通过接口去查询搜索:今天我们来了ELK中的前端可视化组件kibana:kibana ...
- ELK之收集日志到mysql数据库
写入数据库的目的是持久化保存重要数据,比如状态码.客户端浏览器版本等,用于后期按月做数据统计等. 环境准备 linux-elk1:10.0.0.22,Kibana ES Logstash Nginx ...
- 实时统计每天pv,uv的sparkStreaming结合redis结果存入mysql供前端展示
最近有个需求,实时统计pv,uv,结果按照date,hour,pv,uv来展示,按天统计,第二天重新统计,当然了实际还需要按照类型字段分类统计pv,uv,比如按照date,hour,pv,uv,typ ...
- elk收集分析nginx access日志
elk收集分析nginx access日志 首先elk的搭建按照这篇文章使用elk+redis搭建nginx日志分析平台说的,使用redis的push和pop做队列,然后有个logstash_inde ...
- legend2---开发日志6(后端和前端如何相互配合(比如php,js,元素状态和数据改变))
legend2---开发日志6(后端和前端如何相互配合(比如php,js,元素状态和数据改变)) 一.总结 一句话总结:php给元素初始状态,js根据这个状态做初始化和后续变化,使用vue真的很方便( ...
- spring boot(13)-logback和access日志
logback logback出自log4j的作者,性能和功能相比log4j作出了一些改进,而配置方法和log4j类似,是spring boot的默认日志组件.在application.propert ...
- nginx access 日志位置
nginx access 日志位置 /var/log/nginx tail -f access.log
- Spring Boot (16) logback和access日志
Spring Boot 内部采用的是Commons Logging进行日志记录,但是在底层为Java Util Logging.Log4J2.Logback等日志框架提供了默认配置. logback ...
- [PHP] PHP-FPM的access日志error日志和slow日志
PHP-FPM的错误日志建议打开,这样可以看到PHP的错误信息:一般是这个配置路径 /etc/php/7.3/fpm/pool.d/www.conf,日志目录如果需要自己建立PHP目录,一定要把权限赋 ...
随机推荐
- 树莓派上 安装并 运行opencv
1.先安装依赖项 OpenCV 2.2以后版本需要使用Cmake生成makefile文件,因此需要先安装cmake. sudo apt-get install build-essential sudo ...
- GitHub上整理的一些工具【转载】
技术站点 Hacker News:非常棒的针对编程的链接聚合网站 Programming reddit:同上 MSDN:微软相关的官方技术集中地,主要是文档类 infoq:企业级应用,关注软件开发领域 ...
- 剑指offer——49
丑数 因子只含2,3,5的数称为丑数. 怎么求第K大的丑数呢.K可以为10^7 最简单的做法是,对每个数判断是否为丑数. 复杂度为O( n * log(n) ),理论上是不行的. uglys[i] 来 ...
- 【Python系列】Python3获取控制台输入
""" 接收控制台的输入 How old are you? 18 How tall are you ? 180 How much do you weigh? 50 So ...
- 浏览器缓存机制介绍 + 常用 http 状态码
浏览器缓存分为两种, 强制缓存 与 协商缓存, https://www.pass4lead.com/300-209.htmlhttps://www.pass4lead.com/300-320.ht ...
- 关于windows下基于php7.0.2下编写的第一个扩展
网上的教程是比较多的,但是基于php7+windows的教程非常之少,通过几天的摸索及参考很多资料,终于发现如下可以运行. php7要求使用vc2015,同时安装sdk,我使用的是8.1的window ...
- 关于spring中的事件体系
在客户这边上班,平时做开发的时候用到了一个客户自己写的一个开发框架,和spring类似,就是功能少一点,提供了依赖注入,事件体系,任务执行等常用的功能,还提供了一个桥接器,可以把spring中的bea ...
- FPAG结构 组成 工作原理 开发流程(转)
FPGA组成.工作原理和开发流程 备注:下面的描述基于ALTERA系列的FPGA芯片,而且是第一次学习FPGA,其中的一部分内容是参考一些资料总结的,个人独特的分析和见解还偏少. 1. FPGA概述 ...
- 【POJ2154】Color Pólya定理+欧拉函数
[POJ2154]Color 题意:求用$n$种颜色染$n$个珠子的项链的方案数.在旋转后相同的方案算作一种.答案对$P$取模. 询问次数$\le 3500$,$n\le 10^9,P\le 3000 ...
- 【POJ2409】Let it Bead Pólya定理
[POJ2409]Let it Bead 题意:用$m$种颜色去染$n$个点的环,如果两个环在旋转或翻转后是相同的,则称这两个环是同构的.求不同构的环的个数. $n,m$很小就是了. 题解:在旋转$i ...