Logstash概念與原理

Logstash概念

Logstash是一款開源的數據收集引擎,具備實時管道處理能力。簡單來說,logstash作爲數據源與數據存儲分析工具之間的橋樑,結合ElasticSearch以及Kibana,能夠極大方便數據的處理與分析。通過200多個插件,logstash可以接受幾乎各種各樣的數據。包括日誌、網絡請求、關係型數據庫、傳感器或物聯網等等。

Logstash工作過程

如上圖,Logstash的數據處理過程主要包括:Inputs,Filters,Outputs 三部分,另外在Inputs和Outputs中可以使用Codecs對數據格式進行處理。這四個部分均以插件形式存在,用戶通過定義pipeline配置文件,設置需要使用的input,filter,output,codec插件,以實現特定的數據採集,數據處理,數據輸出等功能 。

  1. Inputs:用於從數據源獲取數據,常見的插件如file, syslog, redis, beats 等
  2. Filters:用於處理數據如格式轉換,數據派生等,常見的插件如grok, mutate, drop, clone, geoip等
  3. Outputs:用於數據輸出,常見的插件如elastcisearch,file, graphite, statsd等
  4. Codecs:Codecs(編碼插件)不是一個單獨的流程,而是在輸入和輸出等插件中用於數據轉換的模塊,用於對數據進行編碼處理,常見的插件如json,multiline。Logstash不只是一個input | filter | output 的數據流,而是一個 input | decode | filter | encode | output 的數據流!codec 就是用來 decode、encode 事件的。
     

Logstash簡單實踐

我們使用Logstash輸出一個 “hello world” 。在終端中,像下面這樣運行命令來啓動 Logstash 進程:

 # bin/logstash -e 'input{stdin{}}output{stdout{codec=>rubydebug}}'

以上命令表示從控制檯輸入,然後通過Codec插件從控制檯輸出。然後終端在等待你的輸入。敲入 Hello World,回車,查看結果:

{
	"@version" => "1",
	"host" => "sdn-253",
	"message" => "Hello World",
	"@timestamp" => 2019-07-01T12:28:07.207Z
}

Logstash 就像管道符一樣!你輸入(就像命令行的 cat )數據,然後處理過濾(就像 awk 或者 uniq之類)數據,最後輸出(就像 tee )到其他地方。數據在線程之間以 事件 的形式流傳。Logstash會給事件添加一些額外信息。最重要的就是 @timestamp,用來標記事件的發生時間。 大多數時候,還可以見到另外幾個:

  • host 標記事件發生在哪裏。
  • type 標記事件的唯一類型。
  • tags 標記事件的某方面屬性。這是一個數組,一個事件可以有多個標籤。
    你可以隨意給事件添加字段或者從事件裏刪除字段。

注意:每個 logstash 過濾插件,都會有四個方法叫 add_tag, remove_tag, add_field 和remove_field。它們在插件過濾匹配成功時生效。

Logstash配置語法

數據類型

Logstash 支持少量的數據值類型:
bool

debug => true

string

host => "hostname"

number

port => 514

array

match => ["datetime", "UNIX", "ISO8601"]

hash

options => {
    key1 => "value1",
    key2 => "value2"
}

條件判斷

表達式支持下面這些操作符:

相等: ==, !=, <, >, <=, >=

正則: =~(匹配正則), !~(不匹配正則)

包含: in(包含), not in(不包含)

布爾操作: and(與), or(或), nand(非與), xor(非或)

一元運算符:!(取反) ,()(複合表達式), !()(對複合表達式結果取反)

通常來說,你都會在表達式裏用到字段引用。比如:

if "_grokparsefailure" not in [tags] {
	...
} else if [status] !~ /^2\d\d/ and [url] == "/noc.gif" {
	...
} else {
	...
}

Logstash插件

logstash插件功能很強大,下面會根據每個模塊的情況,對常用插件進行分析。

Input模塊——標準輸入

我們已經使用 stdin 輸入Hello World了。這也應該是 logstash 裏最簡單和基礎的插件了。 input { stdin { } }表示從控制檯輸入

File插件

從文件讀取數據,如常見的日誌文件。文件讀取通常要解決幾個問題:

logstash-input-file配置:

注意:

  • 其中path匹配規則如下,路徑必須使用絕對路徑,不支持相對路徑:
  • /var/log/.log:匹配/var/log目錄下以.log結尾的所有文件
  • /var/log/**/.log:匹配/var/log所有子目錄下以.log結尾的文件
  • /var/log/{app1,app2,app3}/*.log:匹配/var/log目錄下app1,app2,app3子目錄中以.log結尾的文件
     

file插件作爲input例子如下:

input {
    # file爲常用文件插件,插件內選項很多,可根據需求自行判斷
    file {
	   # 要導入的文件的位置,可以使用*,例如/var/log/nginx/*.log
        path => "/var/lib/mysql/slow.log"
        # 要排除的文件
        exclude =>”*.gz”
        # 從文件開始的位置開始讀,end表示從結尾開始讀
        start_position => "beginning"
        # 多久之內沒修改過的文件不讀取,0爲無限制,單位爲秒
        ignore_older => 0  
        # 記錄文件上次讀取位置,輸出到null表示每次都從文件首行開始解析
        sincedb_path => "/dev/null"
        # type字段,可表明導入的日誌類型
        type => "mysql-slow"
    }
}

Http插件

input {
	http { port => 端口號 }
}

Redis插件

input {
    # redis插件爲常用插件,插件內選項很多,可根據需求自行判斷
    redis {
        # EVAL命令返回的事件數目,設置爲5表示一次請求返回5條日誌信息
	   batch_count => 1 
        # logstash redis插件工作方式
        data_type => "list" 
        # 監聽的鍵值
        key => "logstash-test-list" 
        # redis地址
        host => "127.0.0.1" 
        # redis端口號
        port => 6379 
        # 如果有安全認證,此項爲認證密碼
        password => "123qwe" 
        # 如果應用使用了不同的數據庫,此爲redis數據庫的編號,默認爲0。
        db => 0 
        # 啓用線程數量
        threads => 1
      }
}

Filter模塊

Filter是Logstash功能強大的主要原因,它可以對Logstash Event進行豐富的處理,比如解析數據、刪除字段、類型轉換等等,常見的有如下幾個:

Date插件

date插件可以將日期字符串解析爲日期類型,然後替換@timestamp字段或者指定其他字段:

filter{
	date {
	    match => ["timestamp","dd/MMM/yyyy:HH:mm:ss Z"] 
         # 記錄@timestamp時間,可以設置日誌中自定的時間字段,如果日誌中沒有時間字段,也可以自己生成
         target=>“@timestamp”
         # 將匹配的timestamp字段放在指定的字段 默認是@timestamp
    }
}

Grok插件

grok是filter最重要的插件,grok使用正則表達式來生成grok語法,grok支持許多默認的正則表達式規則,grok中常用patterns的配置路徑:

[logstash安裝路徑]\vendor\bundle\jruby\x.x\gems\logstash-patterns-core-x.x.x\patterns\grok-patterns

grok語法

%{SYNTAX:SEMANTIC}

SYNTAX爲grok pattern的名稱,SEMANTIC爲賦值字段名稱。%{NUMBER:duration}可以匹配數值類型,但是grok匹配出的內容都是字符串類型,可以通過在最後指定爲int或者float來強轉類型:%{NUMBER:duration:int}

自定義正則表達式
例如,如下定義一個關鍵字爲version的參數,內容爲兩位的數字。

(?<version>[0-9]{2})

自定義grok pattern
我們通過pattern_definitions參數,以鍵值對的方式定義pattern名稱和內容。也可以通過pattern_dir參數,以文件的形式讀取pattern。

filter {
	grok {
		match => {
			"message" => "%{SERVICE:service}"
		}
		pattern_definitions => {
			"SERVICE" => "[a-z0-9]{10,11}"
		}
	}
}

Dissect插件

基於分隔符原理解析數據,解決grok解析時消耗過多cpu資源的問題。dissect語法簡單,能處理的場景比較有限。它只能處理格式相似,且有分隔符的字符串。它的語法如下:

  1. %{}裏面是字段
  2. 兩個%{}之間是分隔符。

例如,有以下日誌:

Apr 26 12:20:02 localhost systemd[1]: Starting system activity accounting tool

我想要把前面的日期和時間解析到同一個字段中,那麼就可以這樣來做:

filter {
    dissect {
        mapping => {
        	"message" => "%{ts} %{+ts} %{+ts} %{src} %{prog}[%{pid}]: %{msg}"
        }
    }
}

Mutate插件

mutate是使用最頻繁的插件,可以對字段進行各種操作,比如重命名、刪除、替換、更新等,主要操作如下:

1、convert類型轉換

2、gsub字符串替換

3、split、join、merge字符串切割、數組合併爲字符串、數組合併爲數組

4、rename字段重命名

5、update、replace字段內容更新或替換。它們都可以更新字段的內容,區別在於update只在字段存在時生效,而replace在字段不存在時會執行新增字段的操作

6、remove_field刪除字段
 

Json插件

將字段內容爲json格式的數據解析出來,如果不指定target的話,那麼filter會把解析出來的json數據直接放到根級別。配置實例如下:

filter {
	json {
		source => "message"
		target => "msg_json"
	}
}

運行結果:

{
    "@version": "1",
    "@timestamp": "2014-11-18T08:11:33.000Z",
    "host": "web121.mweibo.tc.sinanode.com",
    "message": "{\"uid\":3081609001,\"type\":\"signal\"}",
    "jsoncontent": {
        "uid": 3081609001,
        "type": "signal"
    }
}

Geoip插件

GeoIP 庫可以根據 IP 地址提供對應的地域信息,包括國別,省市,經緯度等,對於可視化地圖和區域統計非常有用。語法如下:

filter {
	geoip {
		source => "message"
	}
}

運行結果:

{
       "message" => "183.60.92.253",
      "@version" => "1",
    "@timestamp" => "2014-08-07T10:32:55.610Z",
          "host" => "raochenlindeMacBook-Air.local",
         "geoip" => {
                      "ip" => "183.60.92.253",
           "country_code2" => "CN",
           "country_code3" => "CHN",
            "country_name" => "China",
          "continent_code" => "AS",
             "region_name" => "30",
               "city_name" => "Guangzhou",
                "latitude" => 23.11670000000001,
               "longitude" => 113.25,
                "timezone" => "Asia/Chongqing",
        "real_region_name" => "Guangdong",
                "location" => [
            [0] 113.25,
            [1] 23.11670000000001
        ]
    }
}

Output模塊

標準輸出

標準輸出多用於調試,配置示例:

output {
    stdout {
        codec => rubydebug
    }
}

redis插件

output {
     redis{  # 輸出到redis的插件,下面選項根據需求使用
         batch => true
         # 設爲false,一次rpush,發一條數據,true爲發送一批
         batch_events => 50
         # 一次rpush發送多少數據
         batch_timeout => 5
         # 一次rpush消耗多少時間
         codec => plain
         # 對輸出數據進行codec,避免使用logstash的separate filter
         congestion_interval => 1
         # 多長時間進項一次擁塞檢查
         congestion_threshold => 5
         # 限制一個list中可以存在多少個item,當數量足夠時,就會阻塞直到有其他消費者消費list中的數據
         data_type => list
         # 使用list還是publish
         db => 0
         # 使用redis的那個數據庫,默認爲0號
         host => ["127.0.0.1:6379"]
         # redis 的地址和端口,會覆蓋全局端口
         key => xxx
         # list或channel的名字
         password => xxx
         # redis的密碼,默認不使用
         port => 6379
         # 全局端口,默認6379,如果host已指定,本條失效
         reconnect_interval => 1
         # 失敗重連的間隔,默認爲1s
         timeout => 5
         # 連接超時的時間
         workers => 1
         # 工作進程
     }
}

elasticsearch插件

output {
    # stdout { codec => "rubydebug" }
    # 篩選過濾後的內容輸出到終端顯示
    elasticsearch {  # 導出到es,最常用的插件
        codec => "json"
        # 導出格式爲json
        hosts => ["127.0.0.1:9200"]
        # ES地址+端口
        index => "logstash-slow-%{+YYYY.MM.dd}"
        # 導出到index內,可以使用時間變量
        user => "admin"
        password => "xxxxxx"
        # ES如果有安全認證就使用賬號密碼驗證,無安全認證就不需要
        flush_size => 500
        # 默認500,logstash一次性攢夠500條的數據在向es發送
        idle_flush_time => 1
        # 默認1s,如果1s內沒攢夠500,還是會一次性把數據發給ES
    }   
}

Logstash配置實例

logstash配置的時候,input和output都可以配置多個不同的入參。filter可以針對input裏面的每個數據源做不一樣的過濾,通過各自定義的type來匹配。配置示例如下:

input{
      kafka{
        bootstrap_servers => ["192.168.110.31:9092,192.168.110.31:9093,192.168.110.31:9094"]
        client_id => "test"
        group_id => "test"
        auto_offset_reset => "latest" //從最新的偏移量開始消費
        consumer_threads => 5
        decorate_events => true //此屬性會將當前topic、offset、group、partition等信息也帶到message中
        topics => ["logq","loge"] //數組類型,可配置多個topic
        type => "bhy" //所有插件通用屬性,尤其在input裏面配置多個數據源時很有用
      }
	file {
	   # 要導入的文件的位置,可以使用*,例如/var/log/nginx/*.log
        path => "/var/lib/mysql/slow.log"
        # 記錄文件上次讀取位置,輸出到null表示每次都從文件首行開始解析
        sincedb_path => "/dev/null"
        # type字段,可表明導入的日誌類型
        type => "mysql-slow"
    }
}
filter{
        if[type] == "bhy"{
            grok{
               ........
            }
        }
        if[type] == "mysql-slow"{
            mutate{
               ........
            }
        }
}
output {
        if[type] == "bhy"{
          elasticsearch{
               hosts => ["192.168.110.31:9200"]
               index => "school"
               timeout => 300
               user => "elastic"
               password => "changeme"
          }

        }
        if[type] == "mysql-slow"{
            ........
        }
 }

1、針對如下類型的log:

Apr 26 12:20:02 localhost systemd[1]: Starting system activity accounting tool

logstash的配置如下:

input {
    file {
        path => "/home/songfeihu/logstash-6.2.3/config/test.log"
        # 要導入的文件的位置,可以使用*,例如/var/log/nginx/*.log
        start_position => "beginning"
        # 從文件開始的位置開始讀,end表示從結尾開始讀
        ignore_older => 0
        # 多久之內沒修改過的文件不讀取,0爲無限制,單位爲秒
        sincedb_path => "/dev/null"
        # 記錄文件上次讀取位置,輸出到null表示每次都從文件首行開始解析
    }
}
filter {
        dissect {
                mapping => {
                        "message" => "%{ts} %{+ts} %{+ts} %{src} %{prog}[%{pid}]: %{msg}"
                }
        }
        if "Starting" in [msg]{
                grok{
                        match => {"msg" => "(?<test1>[a-zA-Z0-9]+).*"}
                }
        }
       mutate {
               remove_field => ["message"]
       }
}
output {
	stdout{codec=>rubydebug}
}

output返回值:

{
          "host" => "sdn-253",
      "@version" => "1",
    "@timestamp" => 2019-06-28T08:08:58.062Z,
           "msg" => "Starting system activity accounting tool",
         "test1" => "Starting",
            "ts" => "Apr 26 12:20:02",
          "path" => "/home/songfeihu/logstash-6.2.3/config/test.log",
           "src" => "localhost",
          "prog" => "systemd",
           "pid" => "1",
       "message" => "Apr 26 12:20:02 localhost systemd[1]: Starting system activity accounting tool"
}

2、針對如下log:

<188>Mar 29 2019 16:57:30 BJQ-219-A1-ITCloud-FW-E8000E-1 %%01SEC/4/POLICYPERMIT(l)[1976979]:VSYS=public;

logstash配置如下:

input {
    stdin {    }
}
filter {
    grok {
        match => {
	"message" => "\<(?<id>[0-9]+)\>(?<timestamp>([a-zA-Z]+)\s[0-9]{1,2}\s[0-9]{1,4}\s[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2})\s%{HOSTNAME:hostname} \%\%(?<version>[0-9]{2})(?<model>[a-zA-Z0-9]+)\/(?<severity>[0-9])\/(?<brief>[a-zA-Z0-9]+)\S+:(?<description>.*)"
	}
    }
}
output {
stdout{codec=>rubydebug}
}

output輸出如下:

{
           "host" => "sdn-253",
             "id" => "188",
      "timestamp" => "Mar 29 2019 16:57:30",
       "hostname" => "BJQ-219-A1-ITCloud-FW-E8000E-1",
          "brief" => "POLICYPERMIT",
     "@timestamp" => 2019-06-28T09:54:01.987Z,
       "severity" => "4",
       "@version" => "1",
        "version" => "01",
          "model" => "SEC",
        "message" => "<188>Mar 29 2019 16:57:30 BJQ-219-A1-ITCloud-FW-E8000E-1 %%01SEC/4/POLICYPERMIT(l)[1976979]:VSYS=public;",
    "description" => "VSYS=public;"
}

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章