ELK日誌採集實踐

一 日誌收集設計

1.1 背景

​ 目前公司業務量增大、項目增多、並且項目中錯誤的信息越來越難以排查,以前排查問題的方式是去服務器把日誌文件拉下來,然後再檢查日誌文件關於報錯的地方。利用這種方式大大延緩了開發效率,並對團隊協作效率產生了較大的影響。解決此問題,應該是公司趨於強大的必經之路。那麼如何在不借助其他人力量的時候,通過日誌快速定位問題和解決問題呢?

​ 在經過公司多次組織和相關人士的深入調研之下,通過各方資料以及對開源日誌處理方案的對比與學習,終於總結出了一套適用於公司內部日誌收集的方案。

​ 由上可知,當前我們的日誌方案主要解決的難題是利用日誌的價值,快速發現問題,節約溝通成本並提高團隊協作效率,同時也是公司發展技術棧的一種完善和延伸。

1.2 整體架構

在這裏插入圖片描述
filebeat是一個輕量級的日誌數據採集器,作爲服務器上的代理進行安裝,filebeat監控特定目錄或者特定日誌文件,並將內容輸出到kafka集羣。filebeat以tail的方式,在prospector、harvester組件的共同作用下,既能保證日誌快速獲取,又能保證文件的狀態、保證日誌能夠至少被輸出過一次。

kafka消息隊列集羣,用來持久化存儲數據,保證數據並行處理,並且kafka有較高的性能和不錯的橫向擴展性,能在每天100w以上數據量的情況下提高整體的性能。

logstash是一款功能強大的數據處理工具,能夠實現數據輸入,格式化處理,數據輸出等功能。logstash默認使用內存隊列接受數據並處理,會佔用大量cpu和內存資源,重啓情況下可能會發生數據丟失情況。logstash也提供了持久化隊列的方式保存 可配置量的數據大小,但是性能會有所下降。

​ **Elasticsearch(ES)**是一個基於Lucene構建的開源、分佈式、RESTful接口的全文搜索引擎。Elasticsearch還是一個分佈式文檔數據庫,其中每個字段均可被索引,而且每個字段的數據均可被搜索,ES能夠橫向擴展至數以百計的服務器存儲以及處理PB級的數據。可以在極短的時間內存儲、搜索和分析大量的數據。通常作爲具有複雜搜索場景情況下的核心發動機。

二 日誌收集注意事項

2.1 數據源格式

​ 項目都是springboot的項目,集成了log4j2統一定義日誌的格式,配置如下

......
<Properties>
    <Property name="baseDir">baseDir</Property>
    <Property name="pattern">%d %p %c.%M:%L [%t] [owinfo-ewtp-core-business] %m%n</Property>
    <Property name="operationDir">operationDir</Property>
</Properties>
......

​ 日誌打印出來的格式

2019-12-12 15:07:24,621 INFO com.owinfo.ewtp.outbound.controller.WayBillController.listPage:63 [http-nio-5005-exec-1]  ===> 類型:清單總分單管理|模塊:清單總分單列表查詢|描述:執行清單總分單查詢成功|參數:WayBillHeadQuery(super=PageParam(page=1, pageSize=10), preNo=null, loctNo=null, voyageNo=null, copNo=null, billNo=null, agentName=null, logisticsName=null, returnStatus=A, startDate=null, endDate=null, type=0)|結果:成功

2.2 logstash配置

​ 首先在kibana頁面上寫好日誌分割的grok表達式,分割的目的見下圖

在這裏插入圖片描述
​ 只要再在logstash中配置對logInfo的分割,就能得到我們想到的字段,logstash配置如下

input{  
   kafka{
        codec => json {
                        charset=>"UTF-8"
                }
        auto_offset_reset => "earliest"
        topics => ["ewtp-operation-log"]
        consumer_threads => 3
        group_id => "ewtp-operation-log-consmer-group"
        bootstrap_servers => "node1:9092,node2:9092,node3:9092"
   }
}

filter{
 grok{
    match => {
                "message" => "(?<timestamp>(\d*-\d*-\d* \d*:\d*:\d*,\d*))\s*(?<level>([Aa]lert|ALERT|[Tt]race|TRACE|[Dd]ebug|DEBUG|[Nn]otice|NOTICE|[Ii]nfo|INFO|[Ww]arn?(?:ing)?|WARN?(?:ING)?|[Ee]rr?(?:or)?|ERR?(?:OR)?|[Cc]rit?(?:ical)?|CRIT?(?:ICAL)?|[Ff]atal|FATAL|[Ss]evere|SEVERE|EMERG(?:ENCY)?|[Ee]merg(?:ency)?))\s*(?<location>[a-zA-Z0-9.]*:[0-9]*)\s*(?<thread>\[[A-Za-z0-9_.-]+\])\s*(?<service>\[?\S*\]?)\s*===>\s*(?<logInfo>(.)*)"
                }
    }
         
        mutate {
        split => ["logInfo","|"]
    }
    if [logInfo][0] {
        mutate {
            add_field =>   {
                "logType" => "%{[logInfo][0]}"
            }
        }
    }
    if [logInfo][1] {
        mutate {
            add_field =>   {
                "module" => "%{[logInfo][1]}"
            }
        }
    }  

    if [logInfo][2] {
        mutate {
            add_field =>   {
                "desc" => "%{[logInfo][2]}"
            }
        }
    } 

    if [logInfo][3] {
        mutate {
            add_field =>   {
                "params" => "%{[logInfo][3]}"
            }
        }
    } 

    if [logInfo][4] {
        mutate {
            add_field =>   {
                "result" => "%{[logInfo][4]}"
            }
        }
    } 


        date {
         match => ["timestamp", "yyyy-MM-dd HH:mm:ss,SSS"]
                  target => [ "@timestamp" ]
                  timezone => "Asia/Shanghai"

                }



    if "_grokparsefailure" in [tags] {
        mutate {
                remove_field => ["logInfo","beat","prospector","offset","input",    "host"]
        }  
 
        } else {
          mutate {
                remove_field => ["logInfo","message","beat","prospector","offset","input",      "host"]
          }
        }

}

output {
  if "_grokparsefailure" in [tags] {
      elasticsearch {
                  index => "ewtp-parse-error-log"
                  hosts => ["http://192.168.0.16:9200"]
      }
  } else {
        elasticsearch {
                index => "ewtp-operation-log"
                hosts => ["http://192.168.0.16:9200"]

    } 
  }
}

​ 通過logstash最終存儲到es的日誌內容如下,這個時候可以使用字段就行檢索
在這裏插入圖片描述

2.3 filebeat使用

​ filebeat需要將異常信息歸併到上一行,因此配置不是時間開頭的合併到上一行日誌中。很多配置已省略

#=========================== Filebeat inputs =============================

filebeat.inputs:
- type: log
  paths:
    - /home/admin/baseDir/*.log
    - /home/admin/baseDir/statement/*.log
  fields:
    host: 192.168.0.174
    env: test
    hostname: localhost
  multiline.pattern: '^[0-9]{4}-[0-9]{2}-[0-9]{2}'
  multiline.negate: true
  multiline.match: after
  multiline.timeout: 10s
  # 省略中間一大截
......
#------------------------------- Kafka output ----------------------------------
output.kafka:
  enabled: true
  hosts: ["192.168.0.16:9092", "192.168.0.251:9092", "192.168.0.252:9092"]
  # 該topic可以利用kafka-monitor進行創建
  topic: ewtp-system-log

2.3 elasicsearch注意事項

可以設置默認的分詞器,如果要對日誌的mapping優化,可以手動創建mapping優化行存和列存.

2.4 日誌收集流程

  • 搭建kafka集羣,定義日誌存儲的topic
  • 使用filebeat配置要收集的目錄,配置日誌存儲地址爲kafka集羣地址
  • 搭建elasticsearch集羣和kibana可視化界面
  • 使用logstash獲取kafka topic的數據,數據格式化之後再傳輸到elasticsearch中
  • 在kibana界面上指定index pattern,最好在discover欄目進行日誌查看和檢索。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章