fbpx

ElasticSearch 自幹訪客流量分析地圖

kibana map

透過 ElasticSearch + Fluentd + GeoIP Plugin 實現訪客流量分析地圖

前陣子需要一種地圖報表,像是 Google Analytics 的那種世界地圖,可以看出來訪客與流量來自哪裡,以便進行訪客流量分析。雖然用 GA 或 OpenSource Piwik 也可以做的到,但是一些不是 Web Page 的 API 的呼叫還要另外整合 Record API,同時也不方便同時統計一大推 Virtual Host。想想其實透過 Web Server Access Log 也可以做到一樣的效果,剛好前陣子,我把所有的 Log 都餵進 ElasticSearch 資料庫進行儲存,透過 Kibana 建立一些常用的檢測報表,可以同時蒐集與整合分析好幾台主機的 Log,不管是 Apache, Nginx, NodeJS 都可以一起進來,集中管理還蠻方便的,完整的 Log Server 建置可以參考這一篇文章的介紹。今天的介紹會用到 Fluentd 來讀取 Log File,蒐集後透過 GeoIP Plugin 解析 Remote Address,換算成地理座標位置,最後傳送到 ElasticSearch 集中儲存。在此記錄一下實現步驟,以後好回顧使用。其實改用 log-stash 更簡單更方便,只是我那時候剛好比較熟 Fluentd,log-stash 剛碰不久,未來有心得再分享了。

安裝 Fluentd, GeoIP Plugin 與 ElasticSearch Plugin

由於我有不同 Linux Distribution,因此介紹一下 CentOS 與 Ubuntu 的安裝方式。

CentOS 安裝 Fluentd (td-agent)

sudo curl -L https://toolbelt.treasuredata.com/sh/install-redhat-td-agent2.sh | sh
sudo td-agent-gem install fluent-plugin-elasticsearch
sudo sed -i.`date +%F` 's/TD_AGENT_USER\=td\-agent/TD_AGENT_USER\=root/g;s/TD_AGENT_GROUP\=td\-agent/TD_AGENT_GROUP\=root/g' /etc/init.d/td-agent
sudo mv /etc/td-agent/td-agent.conf /etc/td-agent/td-agent.conf.orig && mkdir /etc/td-agent/td-agent.conf.d
sudo cp /dev/null /etc/td-agent/td-agent.conf
sudo echo '@include td-agent.conf.d/*.conf' > /etc/td-agent/td-agent.conf

CentOS 安裝 GeoIP Library 與 Fluentd GeoIP Plugin

sudo yum install GeoIP-devel
sudo yum install GeoIP-GeoLite-data-extra.noarch
sudo td-agent-gem install fluent-plugin-geoip

Ubuntu 安裝 Fluentd (td-agent)

sudo curl -L https://toolbelt.treasuredata.com/sh/install-ubuntu-trusty-td-agent2.sh | sh
sudo apt-get -y install libgeoip-dev
sudo td-agent-gem install fluent-plugin-elasticsearch
sudo sed -i.`date +%F` 's/TD_AGENT_USER\=td\-agent/TD_AGENT_USER\=root/g;s/TD_AGENT_GROUP\=td\-agent/TD_AGENT_GROUP\=root/g' /etc/init.d/td-agent
sudo mv /etc/td-agent/td-agent.conf /etc/td-agent/td-agent.conf.orig && mkdir /etc/td-agent/td-agent.conf.d
sudo cp /dev/null /etc/td-agent/td-agent.conf
sudo echo '@include td-agent.conf.d/*.conf' > /etc/td-agent/td-agent.conf

Ubuntu 16.04 安裝 GeoIP Library 與 Fluentd GeoIP Plugin

sudo apt-get install build-essential libgeoip-dev libmaxminddb-dev
sudo apt-get install geoip-database-extra
sudo td-agent-gem install fluent-plugin-geoip

Ubuntu 14.04 安裝 GeoIP Library 與 Fluentd GeoIP Plugin

sudo apt-get install make ruby-dev libcurl4-gnutls-dev libgeoip-dev autoconf
sudo apt-get install geoip-database libtool shtool
sudo td-agent-gem install fluent-plugin-geoip

建立 Access Log 專用的 Index Template

ElasticSearch 有一個專門用來存放地理位置的資料型態,叫做「geo_point」,在倒資料之前要先準備好 Mapping 資訊,Mapping 有點像是 RDBMS 中的 Schema,設定 Mapping 是為了讓 ElasticSearch 知道用什麼方式建立索引。由於 Fluentd 預設使用的 index 名稱是以日期來命名,因此需要借助 Index Template 來自動建立新索引的 Mapping。ElasticSearch API 如下:

PUT _template/logstash
{  
   "template":"logstash-*",
   "settings":{  

   },
   "mappings":{  
      "log":{  
         "properties":{  
            "location":{  
               "type":"geo_point"
            },
            "size":{  
               "type":"number"
            },
            "remote":{  
               "type":"ip"
            }
         }
      }
   }
}

透過 Kibana Dev Tools 執行畫面如下:

elasticsearch template

如此,未來如果有建立 logstash- 開頭的索引,就會自動套用以上 Mapping,這裡比較重要的是 location 設定成為 geo_point 用來存放「經緯度」地理資訊。

利用 ElasticSearch 搜集 Appche Log 資料並使用 Kibana 產生圖表

先編輯一個新的 td-agent 設定檔,可以由 Apache Access Log File Parse 資料存進 ElasticSearch。下述的設定檔先在 <source> Block 透過 format 找出 Line Log 記錄的 Client IP Address 並且設定為 remote 參數,接著透過 <match> Block 將設定好的 tag 傳遞給 GeoIP Library,便可由資料庫中找出 Remote IP Address 對應的地理位置資訊,並且附加到 Document geoip 與 location 中,最後傳到 ElasticSearch 進行儲存,如下:

sudo vim /etc/td-agent/td-agent.conf.d/apache.conf

設定檔內容如下:

<source>
  @type tail
  path /var/log/apache2/other_vhosts_access.log
  pos_file /var/log/td-agent/apache2-access.log.pos
  tag ori.apache.access
  read_from_head true
  format /^(?<host>[^ ]*) (?<remote>[^ ]*) - (?<user>[^ ]*)- \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*) +\S*)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?.*$/
  time_format %d/%b/%Y:%H:%M:%S %z
</source>

<match ori.apache.access>
  @type geoip
  geoip_database /usr/share/GeoIP/GeoIPCity.dat
  geoip_lookup_key remote
  <record>
    location              ${latitude["remote"]},${longitude["remote"]}
    geoip.location.lat    ${latitude["remote"]}
    geoip.location.lon    ${longitude["remote"]}
    geoip.country_code3   ${country_code3["remote"]}
    geoip.country         ${country_code["remote"]}
    geoip.country_name    ${country_name["remote"]}
    geoip.dma             ${dma_code["remote"]}
    geoip.area            ${area_code["remote"]}
    geoip.region          ${region["remote"]}
    geoip.city            ${city["remote"]}
  </record>
  remove_tag_prefix ori.
  add_tag_prefix es.
</match>

<match es.**>
  @type elasticsearch
  host 192.168.32.243
  port 9200
  index_name logstash-apache
  logstash_format true
  type_name ubuntu
  include_tag_key true
  flush_interval 5s
</match>

設定檔完成後記得重新啟動 td-agent

service td-agent restart

我們設定每 5S 同步資料到 ElasticSearch,之後有 Log 可以先去 Kibana 看看 index 有沒有自動建出來,透過 Dev Tools 進行 Query,如下:

GET logstash-2018.01.31/_search
{
  "query": {
    "match_all": {}
  }
}

kibana access log

如果有問題可以查看 /var/log/td-agent/* Log File,接著在 Kibana Management 功能中先導入 logstash-* Index,如果成功就可以繼續建立圖表了。

透過 Kibana 建立 Maps Visualize 圖表

進入 Kibana 後,選擇左邊的「Visualize」接著選擇「Maps」,如下:

kibana geo point setup

進入後設定「Geo Coordinates」為我們產生的 location 欄位,如果沒有出現表示 Mapping 有誤,請檢查 Mapping 是否正確。如下:

kibane map chart

建立以後就可以看到地圖上面出現資料囉,一旦 ElasticSearch 有了 Access Log 就可以在 Kibana 建立各種類型的報表,對於雲服務的營運很有幫助。如果一些 API 的規格設計就遵循 REST 風格,那麼在 Access Log 就會有更多資訊可以分析,以後報表不需要再手刻了,靠這些工具進行流量分析就可以省下不少時間囉。