pymysql组装sql入库日志

pymysql模块的用法

采集这些指标(metirc)都是linux环境,会用到mysql,做为数据的存储,我用docker来启动

  1. docker run \
  2. -p 3306:3306 \
  3. -v /data/mysql:/var/lib/mysql \
  4. -v /etc/localtime:/etc/localtime \
  5. --name mysql5 \
  6. --restart=always \
  7. -e MYSQL_ROOT_PASSWORD=123456 \
  8. -d mysql:5.6.23 \
  9. --character-set-server=utf8 \
  10. --collation-server=utf8_general_ci
  1. create database mem;
  2. create table mem_used(used int, time int)
  3. - 时间格式
  4. >>> import time
  5. >>> time.time()
  6. 1516860432.386474
  7. - 入库后是整形,db自动处理, 也可以入库前int(time).
  8. MySQL [mem]> select * from mem_used;
  9. +-----------+------------+
  10. | used | time |
  11. +-----------+------------+
  12. | 628658176 | 1516842082 |
  13. | 628813824 | 1516842083 |
  14. | 628936704 | 1516842084 |
  15. | 628936704 | 1516842085 |
  16. ...

一个用法实例, 获取指标(通过psutil模块直接获取到已使用的内存) 也可以自己算出.

  1. import psutil
  2. import time
  3. import pymysql as ms
  4. con = ms.connect(host='127.0.0.1', user='root', passwd='123456', db='mem')
  5. con.autocommit(True)
  6. cur = con.cursor()
  7. while True:
  8. used = psutil.virtual_memory().used
  9. sql = 'insert into mem_used values(%s,%s)' % (used / 1024 / 1024, int(time.time())) ## Mb
  10. cur.execute(sql)
  11. time.sleep(1)
  12. - %s可以接受任意类型的值

后面会将db操作封装成模块.

说下本次的任务

  • 本次的任务是将apache的access.log的(ip+状态)+出现次数, 入库到mysql里做分析. 分析网站访问的top10
  • 日志样式如下, 以空格分隔 arr[0] arr[8] 分别是ip和状态码
  1. 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

  1. - 为何是这种格式,取决于echarts数据格式所需. 通常是找到一个合适的图,对图中数据胸有程序,即可以看到它需要一些什么数据,在看下echarts代码,看下需要什么格式的数据, 然后后端组装, json.dumps后返回.
  2. res[(ip, status)] = res.get((ip, status), 0) + 1
  • 对字典的值排序
  1. - 遍历日志文件,获取到一个大的字典如下
  2. 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, ... }
  3. - 对字典排序 转成 列表 后插入
  4. print sorted(res.items(), key=lambda x: x[1], reverse=True)
  5. [(('123.174.51.164', '200'), 6930), (('117.63.146.40', '200'), 1457), (('118.112.143.148', '404'), 1336), (('111.85.34.165', '200'), 1325), ...]
  6. - 对排序后的列表(字典),字符串拼接sql,并插入数据库
  7. for i in sorted(res.items(), key=iambda x: x[1], reverse=True):
  8. sql = "insert into iog vaiues ('%s','%s','%s')" % (i[0][0], i[0][1], i[1])
  9. db.execute(sql)

代码组织

入库代码

log2db.py

  1. #!/usr/bin/env python
  2. # coding=utf-8
  3. from dbutils import DB
  4. # 连接mysql
  5. db = DB(
  6. host="127.0.0.1",
  7. user="root",
  8. passwd="",
  9. db="logtest"
  10. )
  11. # 日志处理成一个大的指定格式的字典(已统计好出现的次数) ((ip, status), count)
  12. res = {}
  13. with open('log.txt') as f:
  14. for line in f:
  15. if line == "\n":
  16. continue
  17. arr = line.split(" ")
  18. ip = arr[0]
  19. status = arr[8]
  20. res[(ip, status)] = res.get((ip, status), 0) + 1
  21. # 组合sql,执行sql入库日志
  22. for l in sorted(res.items(), key=lambda x: x[1], reverse=True):
  23. # {('192.168.1.1',404): 1000,('192.168.1.1',403): 3000,('192.168.1.1',200): 2000,}
  24. sql = "insert into log values ('%s','%s','%s')" % (l[0][0], l[0][1], l[1])
  25. db.execute(sql)

dbutils.py

  1. #!/usr/bin/env python
  2. # coding=utf-8
  3. import pymysql as ms
  4. class DB:
  5. def __init__(self, host, user, passwd, db):
  6. self.host = host
  7. self.user = user
  8. self.passwd = passwd
  9. self.db = db
  10. self.connect()
  11. def connect(self):
  12. self.conn = ms.connect(
  13. host=self.host,
  14. user=self.user,
  15. passwd=self.passwd,
  16. db=self.db
  17. )
  18. self.conn.autocommit(True)
  19. self.cursor = self.conn.cursor()
  20. def execute(self, sql):
  21. try:
  22. self.cursor.execute(sql)
  23. except Exception as e:
  24. self.cursor.close()
  25. self.conn.close()
  26. self.connect()
  27. return self.execute(sql)
  28. else:
  29. return self.cursor
  30. # def query(self,tables):
  31. # sql = 'select * from users'
  32. # self.cursor.execute(sql)
  33. # return self.cursor.fetchall()

下载实例日志: https://github.com/lannyMa/flask_info/blob/master/demo5/log.txt

执行脚本入库

  1. python log2db.py

结果查看

入库完成后, flask前端展示+echarts

将入库的日志通过flask前端展示

难点是找图形的数据模型,即json数据格式. 后端返回. 所以当一幅图出来后,要对其上面有啥数据,啥数据是后端返回的,要胸有成竹, 通过代码+浏览器f12conson.log打印出来.

echarts官网上去看最简单实例的教程,用flask展示出来

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>ECharts</title>
  6. <!-- 引入 echarts.js -->
  7. <script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/4.0.2/echarts.min.js"></script>
  8. </head>
  9. <body>
  10. <!-- 为ECharts准备一个具备大小(宽高)的Dom -->
  11. <div id="main" style="width: 600px;height:400px;"></div>
  12. <script type="text/javascript">
  13. // 基于准备好的dom,初始化echarts实例
  14. var myChart = echarts.init(document.getElementById('main'));
  15. // 指定图表的配置项和数据
  16. var option = {
  17. title: {
  18. text: 'ECharts 入门示例'
  19. },
  20. tooltip: {},
  21. legend: {
  22. data: ['销量']
  23. },
  24. xAxis: {
  25. data: ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"]
  26. },
  27. yAxis: {},
  28. series: [{
  29. name: '销量',
  30. type: 'bar',
  31. data: [5, 20, 36, 10, 10, 20]
  32. }]
  33. };
  34. // 使用刚指定的配置项和数据显示图表。
  35. myChart.setOption(option);
  36. </script>
  37. </body>
  38. </html>

echarts.min.js路径替换下

flask启动展示

  1. from flask import Flask, render_template
  2. app = Flask(__name__)
  3. @app.route('/')
  4. def index():
  5. return render_template('demo.html')
  6. if __name__ == '__main__':
  7. app.run(debug=True)

先找一个合适的echarts图,观察它所需的接口数据格式,后设计接口

计划使用echarts这个饼图展示

它的源码如下

  1. option = {
  2. title : {
  3. text: '某站点用户访问来源',
  4. subtext: '纯属虚构',
  5. x:'center'
  6. },
  7. tooltip : {
  8. trigger: 'item',
  9. formatter: "{a} <br/>{b} : {c} ({d}%)"
  10. },
  11. legend: {
  12. orient: 'vertical',
  13. left: 'left',
  14. data: ['直接访问','邮件营销','联盟广告','视频广告','搜索引擎']
  15. },
  16. series : [
  17. {
  18. name: '访问来源',
  19. type: 'pie',
  20. radius : '55%',
  21. center: ['50%', '60%'],
  22. data:[
  23. {value:335, name:'直接访问'},
  24. {value:310, name:'邮件营销'},
  25. {value:234, name:'联盟广告'},
  26. {value:135, name:'视频广告'},
  27. {value:1548, name:'搜索引擎'}
  28. ],
  29. itemStyle: {
  30. emphasis: {
  31. shadowBlur: 10,
  32. shadowOffsetX: 0,
  33. shadowColor: 'rgba(0, 0, 0, 0.5)'
  34. }
  35. }
  36. }
  37. ]
  38. };

下载后,修改echarts-pie.html源码

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>ECharts</title>
  6. <!-- 引入 echarts.js -->
  7. <script src="/static/jquery.min.js"></script>
  8. <script src="/static/echarts.min.js"></script>
  9. </head>
  10. <body>
  11. <!-- 为ECharts准备一个具备大小(宽高)的Dom画布 -->
  12. <div id="main" style="width: 600px;height:400px;"></div>
  13. <script type="text/javascript">
  14. // 基于准备好的dom,初始化echarts实例
  15. var myChart = echarts.init(document.getElementById('main'));
  16. // 指定图表的配置项和数据
  17. var option = {
  18. title: {
  19. text: '某站点用户访问来源',
  20. {# subtext: '纯属虚构',#}
  21. x: 'center'
  22. },
  23. tooltip: {
  24. trigger: 'item',
  25. formatter: "{a} <br/>{b} : {c} ({d}%)"
  26. },
  27. toolbox: {
  28. feature: {
  29. saveAsImage: {
  30. show: true
  31. }
  32. }
  33. },
  34. legend: {
  35. orient: 'vertical',
  36. left: 'left',
  37. {# data: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索引擎']#}
  38. },
  39. series: [
  40. {
  41. name: '访问来源',
  42. type: 'pie',
  43. radius: '55%',
  44. center: ['50%', '60%'],
  45. {# data: [#}
  46. {# {value: 335, name: '直接访问'},#}
  47. {# {value: 310, name: '邮件营销'},#}
  48. {# {value: 234, name: '联盟广告'},#}
  49. {# {value: 135, name: '视频广告'},#}
  50. {# {value: 1548, name: '搜索引擎'}#}
  51. {# ],#}
  52. itemStyle: {
  53. emphasis: {
  54. shadowBlur: 10,
  55. shadowOffsetX: 0,
  56. shadowColor: 'rgba(0, 0, 0, 0.5)'
  57. }
  58. }
  59. }
  60. ]
  61. };
  62. //使用jq去访问api获取得到数据.
  63. $.getJSON('/piedata', function (res) {
  64. option.legend.data = res.legend
  65. option.series[0].data = res.data
  66. // 使用刚指定的配置项和数据显示图表-绑定数据
  67. myChart.setOption(option);
  68. })
  69. </script>
  70. </body>
  71. </html>

我们知道了前端js需要的数据所需要的数据格式后,就从后端构造这样的api,供前端调用

  1. - api需返回数据的格式
  2. {"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]}
  3. - js访问接口方法
  4. $.getJSON('/piedata', function (res) {
  5. option.legend.data = res.legend
  6. option.series[0].data = res.data
  7. myChart.setOption(option); //获取后直接绑定
  8. })

设计top10状态码的api

  • 目标是

  1. 即访问
  2. http://127.0.0.1:5000/piedata
  3. 返回json数据:
  4. {"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]}
  • 查库后得到的结果
  1. - sql语句做数据汇聚,查出status 对应的总数, 按照状态码总数来排序
  2. select status,sum(count) from log group by status;

查询结果如下

  • flask写api

  1. - cur.fetchall返回的结果,需对其遍历,重组一定格式的数据
  2. ((200, Decimal('49691')), (206, Decimal('32')), (301, Decimal('2')), (304, Decimal('7584')), (403, Decimal('1')), (404, Decimal('3858')))
  3. @app.route("/piedata")
  4. def piedata():
  5. sql = "select status,sum(count) from log group by status";
  6. cur = db.execute(sql)
  7. # 构造前端所需的数据结构
  8. res = {
  9. 'legend': [],
  10. 'data': []
  11. }
  12. for c in cur.fetchall():
  13. code = c[0]
  14. count = int(c[1])
  15. res['legend'].append(code)
  16. res['data'].append({
  17. 'name': code,
  18. 'value': count
  19. })
  20. print(res)
  21. return json.dumps(res)
  22. - 重组后数据格式如下
  23. {'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]}
  24. - 通过json模块处理后返回给将这批数据返回给前端

最终访问

实现前端html展示

  1. @app.route("/")
  2. def index():
  3. return render_template("echarts-pie.html")

最终效果:

小结

[py]access日志入mysql-通过flask前端展示的更多相关文章

  1. 日志分析平台ELK之前端展示kibana

    之前的博客一直在聊ELK集群中的存储.日志收集相关的组件的配置,但通常我们给用户使用不应该是一个黑黑的shell界面,通过接口去查询搜索:今天我们来了ELK中的前端可视化组件kibana:kibana ...

  2. ELK之收集日志到mysql数据库

    写入数据库的目的是持久化保存重要数据,比如状态码.客户端浏览器版本等,用于后期按月做数据统计等. 环境准备 linux-elk1:10.0.0.22,Kibana ES Logstash Nginx ...

  3. 实时统计每天pv,uv的sparkStreaming结合redis结果存入mysql供前端展示

    最近有个需求,实时统计pv,uv,结果按照date,hour,pv,uv来展示,按天统计,第二天重新统计,当然了实际还需要按照类型字段分类统计pv,uv,比如按照date,hour,pv,uv,typ ...

  4. elk收集分析nginx access日志

    elk收集分析nginx access日志 首先elk的搭建按照这篇文章使用elk+redis搭建nginx日志分析平台说的,使用redis的push和pop做队列,然后有个logstash_inde ...

  5. legend2---开发日志6(后端和前端如何相互配合(比如php,js,元素状态和数据改变))

    legend2---开发日志6(后端和前端如何相互配合(比如php,js,元素状态和数据改变)) 一.总结 一句话总结:php给元素初始状态,js根据这个状态做初始化和后续变化,使用vue真的很方便( ...

  6. spring boot(13)-logback和access日志

    logback logback出自log4j的作者,性能和功能相比log4j作出了一些改进,而配置方法和log4j类似,是spring boot的默认日志组件.在application.propert ...

  7. nginx access 日志位置

    nginx access 日志位置 /var/log/nginx tail -f access.log

  8. Spring Boot (16) logback和access日志

    Spring Boot 内部采用的是Commons Logging进行日志记录,但是在底层为Java Util Logging.Log4J2.Logback等日志框架提供了默认配置. logback ...

  9. [PHP] PHP-FPM的access日志error日志和slow日志

    PHP-FPM的错误日志建议打开,这样可以看到PHP的错误信息:一般是这个配置路径 /etc/php/7.3/fpm/pool.d/www.conf,日志目录如果需要自己建立PHP目录,一定要把权限赋 ...

随机推荐

  1. 树莓派上 安装并 运行opencv

    1.先安装依赖项 OpenCV 2.2以后版本需要使用Cmake生成makefile文件,因此需要先安装cmake. sudo apt-get install build-essential sudo ...

  2. GitHub上整理的一些工具【转载】

    技术站点 Hacker News:非常棒的针对编程的链接聚合网站 Programming reddit:同上 MSDN:微软相关的官方技术集中地,主要是文档类 infoq:企业级应用,关注软件开发领域 ...

  3. 剑指offer——49

    丑数 因子只含2,3,5的数称为丑数. 怎么求第K大的丑数呢.K可以为10^7 最简单的做法是,对每个数判断是否为丑数. 复杂度为O( n * log(n) ),理论上是不行的. uglys[i] 来 ...

  4. 【Python系列】Python3获取控制台输入

    """ 接收控制台的输入 How old are you? 18 How tall are you ? 180 How much do you weigh? 50 So ...

  5. 浏览器缓存机制介绍 + 常用 http 状态码

    浏览器缓存分为两种, 强制缓存  与  协商缓存, https://www.pass4lead.com/300-209.htmlhttps://www.pass4lead.com/300-320.ht ...

  6. 关于windows下基于php7.0.2下编写的第一个扩展

    网上的教程是比较多的,但是基于php7+windows的教程非常之少,通过几天的摸索及参考很多资料,终于发现如下可以运行. php7要求使用vc2015,同时安装sdk,我使用的是8.1的window ...

  7. 关于spring中的事件体系

    在客户这边上班,平时做开发的时候用到了一个客户自己写的一个开发框架,和spring类似,就是功能少一点,提供了依赖注入,事件体系,任务执行等常用的功能,还提供了一个桥接器,可以把spring中的bea ...

  8. FPAG结构 组成 工作原理 开发流程(转)

    FPGA组成.工作原理和开发流程 备注:下面的描述基于ALTERA系列的FPGA芯片,而且是第一次学习FPGA,其中的一部分内容是参考一些资料总结的,个人独特的分析和见解还偏少. 1. FPGA概述 ...

  9. 【POJ2154】Color Pólya定理+欧拉函数

    [POJ2154]Color 题意:求用$n$种颜色染$n$个珠子的项链的方案数.在旋转后相同的方案算作一种.答案对$P$取模. 询问次数$\le 3500$,$n\le 10^9,P\le 3000 ...

  10. 【POJ2409】Let it Bead Pólya定理

    [POJ2409]Let it Bead 题意:用$m$种颜色去染$n$个点的环,如果两个环在旋转或翻转后是相同的,则称这两个环是同构的.求不同构的环的个数. $n,m$很小就是了. 题解:在旋转$i ...