Logstash概念
Logstash是一款開源的數據收集引擎,具備實時管道處理能力。簡單來說,logstash作爲數據源與數據存儲分析工具之間的橋樑,結合ElasticSearch以及Kibana,能夠極大方便數據的處理與分析。通過200多個插件,logstash可以接受幾乎各種各樣的數據。包括日誌、網絡請求、關係型數據庫、傳感器或物聯網等等。
Logstash工作過程
如上圖,Logstash的數據處理過程主要包括:Inputs,Filters,Outputs 三部分,另外在Inputs和Outputs中可以使用Codecs對數據格式進行處理。這四個部分均以插件形式存在,用戶通過定義pipeline配置文件,設置需要使用的input,filter,output,codec插件,以實現特定的數據採集,數據處理,數據輸出等功能 。
- Inputs:用於從數據源獲取數據,常見的插件如file, syslog, redis, beats 等
- Filters:用於處理數據如格式轉換,數據派生等,常見的插件如grok, mutate, drop, clone, geoip等
- Outputs:用於數據輸出,常見的插件如elastcisearch,file, graphite, statsd等
- 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語法簡單,能處理的場景比較有限。它只能處理格式相似,且有分隔符的字符串。它的語法如下:
- %{}裏面是字段
- 兩個%{}之間是分隔符。
例如,有以下日誌:
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;"
}