«

»

十一 22 2018

开源项目:Web 日志分析工具 Web-Log-Analyzer-IceFairy

Web-Log-Analyzer-IceFairy 是一款 Client-Only 的 Web Log 的工具。

snap2019

此款工具致力于在本地直接加载 Web 日志文件 并进行分析。工具并不会向服务端发送任何数据,日志分析全部在本地浏览器中进行。

文档都已经在 GitHub ,这里就只写抱怨。

需求

其实一直想要一个 Web 日志 分析工具,然而一直找不到好用的。

Webalizer 和 AWStats 必须安装在服务器端,依赖一大堆,安装起来不方便,用起来更不方便。分析日志就是为了捉贼,这两款工具也都没提供相应的功能。感觉看这一大堆图标就是图个乐子。

Web Log Storming 倒是能勉强满足需求,然而是收费的,而且用起来也不方便。

不少大神牛逼吹得不错,结果一问细节就假装看不见你,开启自娱自乐的表演。

求人不如求己,不如干脆自己做!

开发过程

需求分析

做一款完全跑在客户端的工具,做到无网络依赖,无额外软件安装,无环境依赖。

选型

核心

不能有服务端,所以 PHP 虽然强大但是不符合需求。没有额外软件,所以数据库也不能用。不依赖操作系统环境,这方面对我倒是没啥,本来我也不会桌面客户端开发。

这范围就小很多了,连 Python 都被刨除在外了,只剩 Javascript,只要有浏览器就行了。虽说载入还是需要网络和浏览器,不过后期可以直接上 Electron ,还可以直接覆盖三个桌面操作系统平台。

框架

题外话

先说一段题外话,大部分都是想骂人结果找不到挨骂的,当然我是更愿意能动手就动手的。不想读就直接跳过。

半年以前曾强挤出个人时间,给公司做了一个 License 管理器。当时公司管理 License 的方式非常的大众。你得首先找经理说要申请 License,之后经理要找有权限做 License 的开发人员,开发人员要找到对应的平台服务器,登录到底层,手动拼字符串,之后再导出,再拷贝到 U 盘。至于是什么客户申请 License,谁批准的 License ,谁生成的 License,没人记录。经常为了一个 License,几个人要耽误一上午的工作,只为了找人协调,甚至发生过一个客户申请 License 结果好几个人做了好几个 Lincese 出去的情况,客户估计都笑话了。而最后一点记录都没有,活白干了。我做完这个 License 管理器之后,直接把管理权限甩给经理,以后生成 License 只要经理鼠标点点就行了,数据永久记录,谁申请的发给谁的都有记录存档。~后来工作就丢了~

当时前端就是用 vue 写的,我就想着前端框架就直接拿这套直接上。

结果 TMD 编译不过了!

是的,一个字节都没动过,原来好好的项目,因为各个包都升级了,接口和配置文件全变了,整个工程自杀了。

虽说有 yarn.lock 帮忙挡着,但是这也意味着有一堆上个项目有用但新项目完全用不着的包也赖在里面,想添加新的组件也会引入更多更大的冲突。

为了搞定这些破玩意所需要的学习成本贼鸡巴高,配置文件都不一样,和重新学习各个组件没个啥区别。这也是我当时写 《软件开发算知识吗?》 的原因,写前端跟 办税票 真他妈的没什么区别了。我在选框架前绞尽脑汁考虑日志分析的思路和性能优化,结果却在 猴子如何使用工具 这个阶段翻了车。

当然文章收到的一条反馈,则更是让我恼火:

常识而言,编程不是技能吗?就像我用三维软件建模一样。这算啥知识。

我他妈的就想反问了:编程是技能不是知识,三维软件建模算技能不是知识,那解一元二次方程算不算技能?小学数学加减法算不算技能?技能如果不算知识,那 1+1 算啥屁!用手抓筷子吃饭算啥!你他妈活着又算啥!

框架选型

SPA (single-page application) 应该是定了,而这世上知名的 SPA 框架,我只认识仨:React、Angular、VUE。

占有率最低的 vue ,没事就大幅度更新。用旧版删不掉旧组件加不进去新组件。文档和 npm/yarn 能扒下来的版本大部分时间对不上号。

考虑用 Angular。不过我上次写 Angular 可是 3 年前,Angular 1.3.7 。当时公司就没写下去。当时公司只看得懂 1.3.7 的文档,而官方已经更新到 1.5.9 不再维护 1.3.7 。不仅如此, Angular 2 马上就要发布。Angular 每次中版本号更新都是天壤地别的变化,就算学了 1.3.7 ,马上就白学了。即使全公司都啃下来 1.5.9 ,估计也挺不过一个季度所有努力全白费(何况还有人偷偷在学习 DEM O 里掺 jQuery 以图蒙混过关)。

现在再一看 Angular, v7.0.3 ,我估计当年会的那点 1.3.7 现在连运行依赖都扒不下来了。

React 我则是完全的不喜欢。把 HTML 和 JS 混在一起写的做法,和番茄汁兑牛奶一个感觉。感受过 现代 PHP 那种把不同语言分开写的清爽感觉之后,再看 React 这种写法就跟看到被卡车碾过的死耗子一样。当然,不少公司不论是 PHP 还是 JAVA 还是什么其他的语言,HTML、JS、CSS 都混在一起仍然是家常便饭,很多学校和培训机构的教材也是这样,网上不少价格不菲的收费教学视频也都是这么教的。

反思最佳实践?JSX 更容易代码复用?听这帮专家 BB,和听统计局骗人有啥不一样的地方?~(有啊,资本主义专家都是外国佬,赚得更多!烫个带卷金毛穿个衬衫就特有学问是吧,转个身就能代言电磁炉!)~

纯原生实现,工作量不知道得大到哪个星系去了。毕竟这玩意要是个人原生很容易实现,那几个框架的学习成本也不会搞得云里雾里。jQuery 就很好学,去 jQuery 化也特容易。

唉……

结果转了一圈发现还是转回 vue 了,只剩下这玩意学习成本相对来说低一点,相对来说。

图表选型

本来是想用 Hightcharts 的,但是注意到这货并不商免。于是换成 Chart.js 了。

组件库

以前公司是用 iVuiw ,丑不说,文档超 element 都抄错字了,一堆该实现没实现的坑。license 那个我就是自作主张换用了 element 。

唉,还是该早点投奔 Bootstrap 。

开发过程

核心

核心开发思路

这一块是最开心的地方了,因为这一段要动脑子。

首先搞到日志样本。

日志就长这样,只不过每个月的日志是从几百行到几百万行不定,日志文件大小也是从几十 K 到几百 M 不一定,如果没有老老实实的做日志维护的话,一个日志几百 G 都是很常见的事情,不少产品犯这种缺心眼问题导致服务器瘫痪,我已经司空见惯了。

想要从这些日志里挑出有价值信息,靠正则没啥问题。把数据都塞到不同的数组里,生成不同表格所需的数据组合,现代电脑用个几百 M 甚至几个 G 都不是事,Chrome 这种吃内存大户经常干这种事,一个 setTimeout 的内存泄露都能爆掉几个 G 呢。

问题就在于量,数据量越大,必然需要时间越长。很不幸我没学过算法那些玩意,时间复杂度啥的只听过概念,半分钟内没法理解的东西我就打怵。

简单来讲,要解决的问题就是:我有一组数据,我现在需要把他们全部来一遍,来生成 N 种不同的数据组合,而各种组合的方式不同。最简单的思路就是对每种组合方式都用各自的方法把所有数据循环一次。那么假如我有 30W 条数据,有 12 种组合方式的话,每条数据就得被重复读 12 次。太傻。

不过最终我还是研究出来了,12 组输出,只用 2 次循环。其实只用一次也能做到,只不过我进行了一次预处理。一方面是为了降低 Debug 难度,另一方面也是希望后期能在这里做其他方面的优化。

核心开发遇到的情况
基于 Referrer 的注入攻击

头一次发现基于 Referrer 的注入攻击:

唉,我之前还在 《服务器遭分布式主动探测攻击》里说:“啥样的网络攻击我没见识过”。虽然这个并不能震惊到我,不过这个攻击思路是真不错。到网上搜了一下,应该是 ECShop 的漏洞,不过如果有其他服务也是用 MySQL 存 Web 日志 的话,也可以用相同的手段进行攻击,估计没多少 做运维的人 会想到从 Web 日志 下手攻击,都是一股脑直接写进去。

进度展示

这个现在没实现。

循环过程中是没法渲染 DOM 的,我还写成同步请求了,所以没法实现。

一种思路思路是把循环改写成 setTimeout 回调。代码实现倒是实现了,然而出现了极为严重的效率问题。

这个和算法没啥关系,主要是操作系统和浏览器的限制。

600 条的日志,相同的算法,for 循环执行完需要 103ms,而 setTimeout 回调使用了 6358ms ,60 多倍!搞毛啊!

幸好 Chrome 有个 Performance 调试工具,头一次用。这年头我就没见过有人考虑过前端性能,东西得做多肿多卡才能让人考虑前端性能?

  • For 循环:

snap2032

  • setTimeout 回调:

snap2033

For 循环瞬间完成的事情, setTimeout 超过 88% 的时间都在哩哩啦啦的 IDLE ,浏览器完全没干活啊!

好吧这个我解决不了,只好在 segmentfault.com 请教了,得到的答案是 setTimeout 有个基于操作系统存在的最短运行间隔,并给出了几种思路,我列举一下我能理解的:

  • setTimeout 中一次循环 1000 条

否决。一次要处理的可能是 10W 条,也可能是 1000W 条,用固定数值做单位就解决不了 setTimeout 引入的问题,使用动态数值就增加后期维护难度

  • 循环中途来一次 setTimeout

否决。这个实现更丑,维护起来能难

  • window.requestAnimationFrame

这个的确是个思路,然而其实在这个 IDLE 问题出现之前,我就已经开始担心 Rending 时间可能会导致的问题。想要在 JS 单线程模型下解决这个问题,还真得靠多次循环单次渲染的方式解决,也就是说,这个的确有可能解决 IDLE 问题,但是并不会做到最好。

  • Web Worker

Web Worker 这个词经常在 MDN 上见,当时没明白这是啥玩意,现在知道这是为 JavaScript 创造多线程环境的方法。这是最完美的思路,可以直接将这个同步工作转变成为异步,剩下的事情就好办多了,可以选择定时渲染,或定量渲染,选择变得突然变得很多,也能带来很好的用户体验。

不过现在处理 30W 条记录只需 2s,进度条的事情就先缓缓吧。

前端

前端开发思路

从这里开始就没意思了。没有需要动脑子的地方,内容就是一遍试,试一遍,一遍一遍试,试一遍又一遍。

首先还是先把之前项目的基本文件扒过来,多组件就多组件吧,只能期望 webpack 不会把用不着的代码也打进去了。

在纸上画点草图,之后照着这个思路做就好了。

本来想拍几张草图的照片上来的,不过吃完的时候草图都被我当桌布了。我的痴呆是越来越严重了,吃东西总从最里面漏出来,草图沾了不少油和汤,都被我扔了。

遇到的情况
数据树模型

首先说,我对 vuex 极为不爽。思路挺好,但是代码真他妈的冗余臃肿。要把可能会无比巨大的数据挂在这棵歪脖树上,还不如在客户端装个数据库呢。

第一反应是直接把数据放在根节点上,用 props 传参给子组件。结果是不行,因为用了 vue-router,导致复杂的参数传不下去。vue-router 传个 id 啥的还行,传个大数组,想想太恐怖。

不用 vuex,又不能用 props 传参,这是穷途末路了?

不,仔细想想,我管这玩意叫 ,就是期望这玩意处于根节点,我埋一个种子种一棵大树,上面的每个叶子组件都能访问这个节点就行了,我也不需要组件间隔离,不需要权限控制。这种需求,根本用不着巴结 vuex ,根本用不着传参,我直接存在浏览器上不就结了!

直接把数据转换成 JSON 保存到 localstorage 中!这样即使用户刷新整个页面数据都不会丢,比 vuex 和 vue-router 靠谱多了!组件们只要从 localstorage 中读取字符串就好了。

本地存储限制

当我尝试导入 30W 条日志之后,Chrome 直接就崩了,这情况在写无 vue 的 Demo 时完全没遇到过。我当时就懵逼了:妈蛋难道 vue 还有这种限制?还能导致浏览器崩溃?我总不能把做到一半的 vue 全推翻了再换框架把。

一筹莫展之际,顺手打开了 Firefox 再来一遍,结果竟然得到报错信息!Persistent storage maximum size reached 喜出望外!

到网上一搜,localstorage 等本地存储有大小限制,默认是 5M ,而我的输出结果也是 5M 左右。解决办法:修改 Firefox 的 about:config 中的 dom.storage.default_quota

Firefox 你要是 Developer Tools 做得再好看点我就卸了 Chrome!

(顺便不知道为啥直接写就能写进去,上了 vue 就进不去了)

千分位

流量统计展示的页面,应该用千分位,那么怎么表示呢?

snap2034

脑洞大开什么思路都有,比如正则,比如字符串切割。

正则的效率那叫一个烂啊,没必要时我都不想用正则。

我用了 toLocaleString('en-US'); ,本以为这种原生手段效率最高,结果发现这方法比用正则还要慢 100 多倍。下个提交我就把你换了!

关于千分位的研究可以参考这篇文章:《从千分位格式化谈 JS 性能优化》

vue 开始抽风

到了最烦人的地方了。

开发过程中,webpack-dev-server 的工作都极为稳定。到了开发尾声了,执行 build ,结果报了一大堆莫名其妙的错,找不到各种包,找不到各种依赖,找不到各种配置。我就纳了闷了,webpack-dev-server 一个错都没有,到了 build 就开始犯毛病,闹什么鬼。

想要救活估计是没戏,半年前的框架估计是没法继续用了,好在组件文件都写完了,没准努努力换上新版的 vue 能活。

重新建了个目录,想法把 vue-cli 捣鼓到 3.x,新建 hello-world 项目,发现 devDependencies 里只剩 "@vue/cli-plugin-babel" "@vue/cli-service""vue-template-compiler",这工具总算开始有点人样了。

把组件文件都复制过来,yarn run serve 一跑,这什么鬼!

snap2008

看了半天文档也没发现任何端倪,回头看 hello-world ,发现有这么一段

什么鬼,根组件还得额外指定?

没辙重新写一个 Root 组件,只负责挂路由。

和文档对不上的时候,最难受

element UI 开始抽风

一个接一个的抽啊,更新完 vue,结果 element 也抽了, NavMenuunique-opened 强制为 true 关不掉了。

完全失去耐性。直接把 element UI 卸了重装一遍,重新启动 yarn run serve,好了。

真应了程序员那几句老话:

  • “程序没调通,我不知道怎么回事;程序调通了,我不知道怎么回事。”
  • “重启,重装,换电脑。”

已知问题和未来计划

  • 数据存储

5M 的限制在 Firefox 上可以放开,未来如果打包成独立应用的话则可以做到无限制。但是储存在 localstorage 中不是什么长久之计,毕竟拿着字符串 parse 来 parse 去的太山寨了。现在还缺失很多功能,尤其是关联查询。这种时候如果有 MySQL 就很好了,一个 Select 加 Join 都能搞定。

IndexedDB 应是个不错的方案,虽然不支持 SQL 查询,但是毕竟是个名正言顺的数据库,Join 自己实现就好了。

  • 异步和进度

Web Worker 是计划内的必选项,同样进度条也是

  • 更多功能

文章开头也说了,想要一个抓贼工具,然而这个工具现在还实现不了这样的功能,只能单独的展示单对象属性。一个人的精力有限,这种不赚钱的项目做起来虽然压力小,但是肚子饿啊。

  • 框架

谁知道需要过多久 vue 系 又会开始抽风。有能力的话真想把这玩意换了。

其他

License

Mozilla Public License Version 2.0

链接

2 comments

  1. 灰狼
    WebView 4.0 WebView 4.0 Android 6.0.1 Android 6.0.1
    Mozilla/5.0 (Linux; U; Android 6.0.1; zh-CN; Redmi 4 Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 Quark/2.4.2.986 Mobile Safari/537.36

    上次分析自己博客的访问日志,弄到 excel 直接卡死。量不算很大,可能就是电脑资源不够,最后分析失败…

    1. 石樱灯笼
      Google Chrome 70.0.3538.110 Google Chrome 70.0.3538.110 Windows 7 x64 Edition Windows 7 x64 Edition
      Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36

      excel 不行,excel 自己就够肿的了。

发表评论

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

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据