基於SQL的日誌分析工具myselect

基本介紹

程序開發者經常要分析程序日誌,包括本身打印的日誌及使用的其餘軟件打印的日誌,如php,nginx日誌等,linux環境下分析日誌有一些內置命令可以使用,如grep,sort,uniq,awk等,當中最強大的是awk,是做爲一門小巧的文本處理語言存在的,但因爲它是一門語言,功能強大,但在命令行下使用並不那麼方便,因爲awk是面向計算而不是面向統計的。awk可以定義變量,可以進行計算,命令行下就是一個包括隱式for循環的語言。php

awk假設很是長時間不用,它的一些語法就忘了,要分析線上日誌時就想假設能用sql分析該多好,確實,sql(結構化查詢語言)是一門真正面向統計的語言,包含HIVE也是用它,因而最近開發了一個基於sql的日誌分析器,可以用類sql語法分析日誌,如下稱它爲myselect。linux

myselect是一個簡化日誌分析的工具,相信它已經覆蓋了大部分awk能完畢的日誌分析功能,固然特殊狀況下仍是需要用到awk等。myselect把要分析日誌文件當成一個數據庫,裏面的日誌行看成數據庫記錄,從而對裏面的日誌數據進行統計分析。如下看看myselect與awk等其餘命令在使用上的對照。nginx

以分析ngnix日誌爲例,如下這條日誌是咱們線上web機器的一條日誌git

198.52.103.14 - - [29/Jun/2014:00:17:11 +0800] "GET /q/1403060495509100 HTTP/1.1" 200 26788 "http://wenda.so.com/q/1403060495509100" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727)" 221 0.532github

第一個字段是IP,假設要知道來源ip最多的是哪些,用 awk等其餘命令實現例如如下web

$ awk '{ print $1}' accesstest.log | sort | uniq -c | sort -k1nr | less 
14 111.13.65.251 
13 10.141.88.248 
12 10.141.88.239 
10 10.141.88.250 
9 121.226.135.115 
8 10.141.88.241 
8 10.141.88.249 
8 222.74.246.190 
7 211.149.165.150 
6 119.138.167.213算法

甚至全然單純使用awk都可以實現以上功能,但有其餘更好用的命令這樣顯得不是必需了sql

myselect怎樣實現以上功能? myselect將日誌行當作多個字段,字段間以空格分隔,在雙引號中的所有字符是算做一個字段的,即便當中包含空格,這點與awk純粹以空格分隔是不一樣的,這使咱們處理日誌也更方便。可以經過例如如下命令查看某一日誌行各字段值:數據庫

$ myselect -s '198.52.103.14 - - [29/Jun/2014:00:17:11 +0800] "GET /q/1403060495509100 HTTP/1.1" 200 26788 "http://wenda.so.com/q/1403060495509100" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727)" 221 0.532'網絡


**log fields** 
$1   198.52.103.14 
$2   - 
$3   - 
$4   [29/Jun/2014:00:17:11 
$5   +0800] 
$6   GET /q/1403060495509100 HTTP/1.1 
$7   200 
$8   26788 
$9   http://wenda.so.com/q/1403060495509100 
$10   Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727) 
$11   221 
$12   0.532

-s選項將日誌行各字段值打印出來,接下來可以依據相應字段進行計算,例如如下

$ myselect 'select count($1),$1 from accesstest.log group by $1 order by count($1) desc limit 10' 
14 111.13.65.251 
13 10.141.88.248 
12 10.141.88.239 
10 10.141.88.250 
9 121.226.135.115 
8 10.141.88.241 
8 10.141.88.249 
8 222.74.246.190 
7 211.149.165.150 
6 61.174.51.174

結果全然同樣

還有一個常用的需求是查看每分鐘的流量,並觀察流量異常的狀況,用awk等命令例如如下:

$ awk '{ print gensub(/.*2014:(.+):.*+0800].*/,"\\1","g")}' access_wenda.qihoo.com_log | uniq -c | grep -v Windows | less 
1567 00:17 
1597 00:17 
933 00:18 
3045 00:18 
1605 00:19 
294 00:19 
2021 00:19 
1315 00:20 
666 00:20 
1875 00:20 
3679 00:21 
1172 00:22 
479 00:22 
2094 00:22 
1352 00:23 
51 00:23 
37 00:23

grep -v Windows是爲了過濾掉一些亂碼行,在awk咱們需要經過gensub得到子的字段,如這裏的分鐘值,而在myselect也有相同的功能的函數regsub($1,pattern,replace),用myselect 完畢相同的需求例如如下:

$ myselect 'select regsub($4, /.*2014:(.+):\d{2}.*/,\1),count($1) from access_wenda.qihoo.com_log group by regsub($4, /.*2014:(.+):\d{2}.*/,\1) order by count($1)desc limit 10'

regsub($4, /.*2014:(.+):\d{2}.*/,\1),咱們對第4個字段使用正則得到分鐘值。

再比方咱們要計算網絡請求平均耗時,用awk可以實現,但過程比較複雜,需要定義變量並進行計算,而用myselect 僅僅需要 利用 avg函數較爲簡單計算出來,例如如下

$ myselect 'select avg($12) from access_wenda.qihoo.com_log'

從以上的對照中,可以發現myselect是以寫sql方法進行統計,不但好記,而且分析思路比較直觀,不像awk需要一堆命令進行配合。

或許你會說把日誌放到數據庫再分析也同樣,只是這個過程太麻煩了,不如直接對文件用SQL分析。

myselect 使用

安裝myselect 程序後,可以查看用法

$ myselect -h 
usage: 
myselect 'sql sentence'; 用 sql進行統計分析 
myselect -s 'log line';對日誌行按空格進行切割編號 
myselect -n 'log line' 'sql sentence'; 對日誌行用sql進行解析 
myselect -p 'sql sentence'; 查看sql語法解析結果 
myselect -c 'sql sentence'; 查看sql計算過程

統計分析基本使用例如如下

$ myselect 'sql語句'

sql語句語法基本與普通數據庫查詢select語句一致,不區分大寫和小寫(固然,文件名稱是區分大寫和小寫的),支持自由格式,僅僅有小部分不一樣,咱們有理由相信sql語言在統計分析上必定是眼下最優的語言,基本照着它來實現便可了。

sql語句 = SELECT 
select_expr [, select_expr ...] 
[FROM file_name 
[WHERE where_condition] 
[GROUP BY {col_name | expr } 
[HAVING where_condition] 
[ORDER BY {col_name | expr } 
[ASC | DESC]] 
[LIMIT {[offset,] row_count }]

簡單說明例如如下:

select_expr

可以包含字段編號如$1,$2,字段以空格分隔,也可以包含函數,函數分兩類 
字符串處理函數:

  • strsub($1,2,3) 截取子字符串
  • regsub($1,/(.):(.+):(.)/i,\2) 按正則替換子字符串

字符串函數可以用在不論什麼字段可以出現的地方,它的參數也包含了字段編號

聚合函數:

  • count
  • sum
  • agv
  • max
  • min

意義與普通sql同樣。

where_condition

用and 鏈接起來的關係表達式,眼下還不支持or, 支持例如如下的操做符 
=,!=,>,<,>=,<=,like,rlike 
like表示是否包含對應字符串,rlike表示正則匹配對應模式

原計劃myselect用go語言實現,並看了一遍go手冊,但在咱們組內技術期刊投稿截止以前的很是短期裏沒法用一門剛看的語言來實現它,轉而先用php實現一個了版本號,並且基本可用,眼下實現的php版本號實現了基本的sql select 語句語法,像askeyword及or邏輯操做符尚未實現,但這不重要。在日誌文件很是大時,php實現的版本號在性能以及內存佔用上都沒法很是好知足要求,但相信不久就會有go語言實現的高可用版本號。

對於不熟悉awk或一下沒法記起awk語法細節的人來講,在需要分析日誌時myselect可以很是好實現咱們的需求,sql語言你們都應該是很是熟悉的。

本工具源代碼已放到到了 github   https://github.com/micweaver/myselect 基本實現算法在裏面,接下來要翻譯成go語言實現,go語言能很是好的知足咱們對性能及內存佔用的需求,固然極大的日誌你要藉助於hadoop,hive等分佈式計算工具

相關文章
相關標籤/搜索