Logstash 時區問題

1. Date Filter 插件


  • 日期過濾器用於分析字段中的日期,然後使用該日期或時間戳作爲事件的 logstash 時間戳。

1.1. 配置項

Setting Input type Required Default
locale string No No
match array No []
tag_on_failure array No ["_dateparsefailure"]
target string No "@timestamp"
timezone string No No
1.1.1 locate
  • Value type is string

  • There is no default value for this setting.

  • 使用 IETF-BCP47 或 POSIX 語言標記指定用於日期分析的語言環境。en,en-US 用於 BCP47 或者 en_US 用於 POSIX。

  • 當解析月份名稱(MMM模式)和星期幾名稱(EEE模式)時,如果默認語言環境不是 english,需要設置:

    date {
        locale => "en"
        ...
    }
    
1.1.2. match
  • Value type is array

  • Default value is []

  • 對於非格式化語法,您需要在值的周圍放置單引號字符。例如,如果你解析ISO8601時間,“2018-06-01T01:12:23”,你需要這樣寫:

    date {
        match => ["log_timestamp", "yyyy-MM-dd'T'HH:mm:ss"]
    }
    
  • 如果你需要匹配多種時間格式,如 "2018-06-01T01:23:05Z"、"1529122935988"、"1529122935",你需要這樣寫:

    date {
        match => ["log_timestamp", "ISO8601", "UNIX", "UNIX_MS"]
    }
    
  • date 插件支持五種時間格式:

    • ISO8601:類似 "2018-06-17T03:44:01.103Z" 這樣的格式。具體 Z 後面可以有 "08:00" 也可以沒有,".103" 這個也可以沒有。常用場景裏來說,Nginx 的 log_format 配置裏就可以使用 $time_iso8601 變量來記錄請求時間成這種格式。
    • UNIX:UNIX 時間戳格式,記錄的是從 1970 年起始至今的總秒數。Squid 的默認日誌格式中就使用了這種格式。
    • UNIX_MS:這個時間戳則是從 1970 年起始至今的總毫秒數。據我所知,JavaScript 裏經常使用這個時間格式。
    • TAI64N:TAI64N 格式比較少見,是這個樣子的:@4000000052f88ea32489532c。我目前只知道常見應用中,qmail 會用這個格式。
    • Joda-Time 庫:Logstash 內部使用了 Java 的 Joda時間庫來作時間處理。所以我們可以使用Joda庫所支持的時間格式來作具體定義。
  • Joda時間格式定義見下表:

    Symbol Meaning Presentation Examples
    G era text AD
    C century of era (>=0) number 20
    Y year of era (>=0) year 1996
    x weekyear year 1996
    w week of weekyear number 27
    e day of week number 2
    E day of week text Tuesday; Tue
    y year year 1996
    D day of year number 189
    M month of year month July; Jul; 07
    d day of month number 10
    a halfday of day text PM
    K hour of halfday (0~11) number 0
    h clockhour of halfday (1~12) number 12
    H hour of day (0~23) number 0
    k clockhour of day (1~24) number 24
    m minute of hour number 30
    s second of minute number 55
    S fraction of second number 978
    z time zone text Pacific Standard Time; PST
    Z time zone offset/id zone -0800; -08:00; America/Los_Angeles
    ' escape for text delimiter
    '' single quote literal '
  • 舉例:

    example match
    2018-06-01T01:23:05+08:00 yyyy-MM-dd'T'HH:mm:ss+08:00 或 ISO8601
    2018-06-01T01:23:05Z yyyy-MM-dd'T'HH:mm:ssZ 或 ISO8601
    Jun 07 2018 01:23:05 MMM dd yyyy HH:mm:ss (注: locale => "en")
    Jun 7 2018 01:23:05 MMM d yyyy HH:mm:ss (注: locale => "en")
    1529122935988 UNIX_MS
    1529122935 UNIX
1.1.3. tag_on_failure
  • Value type is array
  • Default value is ["_dateparsefailure"]

如果匹配失敗,將值附加到 tag 字段。

1.1.4. target
  • Value type is string
  • Default value is "@timestamp"
  • 將匹配的時間戳存儲到給定的目標字段中。如果未提供,則默認更新事件的@timestamp字段。
1.1.5. timezone
  • Value type is string

  • There is no default value for this setting.

  • 當需要配置的date裏面沒有時區信息,而且不是 UTC 時間,需要設置 timezone 參數。

  • 比如匹配北京時間 "2018-06-18 11:10:00",則需要設置:

    date {
        match => ["logdate", "yyyy-MM-dd HH:mm:ss"]
        timezone => "Asia/Chongqing"
    }
    
  • 東八區:

    Standard Offset Canonical ID Aliases
    +08:00 Asia/Chongqing Asia/Chungking
    +08:00 Asia/Hong_Kong Hongkong
    +08:00 Asia/Shanghai PRC
  • 附: timezone列表

2. logstash @timestamp自定義


  • 在ELK組合中我們在 outputs/elasticsearch 中常用的 %{+YYYY.MM.dd} 來創建索引,而這種寫法是必須要讀 @timestamp 這個字段的。默認情況下 @timestamp 字段顯示的是當前時間,但我們可能需要記錄的是日誌中的字符串類型的時間,所以我們需要把日誌中字符串類型的時間覆蓋掉 @timestamp 中的當前時間。
input  {
     stdin{}
}
filter {
    grok {
        match => ["message", "%{TIMESTAMP_ISO8601:logdate}"] 
    }
    date {
        match => ["logdate", "yyyy-MM-dd HH:mm:ss.SSS"]
        target => "@timestamp"
    }
    mutate {
        remove => ["logdate"]
    }
}
output{
     stdout{
        codec=>rubydebug{}
     }
}

3. @timestamp 時間少 8 小時


3.1. 5.0 以下版本

input { stdin {} }  
output { stdout { codec => rubydebug } }  
filter {  
  date {  
    match => ["message","UNIX_MS"] # message在實際應用中修改爲自己的字段  
    target => "@timestamp"     
  }  
 ruby {   
   code => "event['timestamp'] = LogStash::Timestamp.new(event['@timestamp']+ 8*60*60)"   
 }  
 ruby {  
   code => "event['@timestamp']= event['timestamp']"  
 }  
 mutate {  
   remove_field => ["timestamp"]  
 }  
} 

3.2. 5.x 以上版本

input { stdin {} }  
output { stdout { codec => rubydebug } }  
filter {  
  date {  
    match => ["message","UNIX_MS"]  
    target => "@timestamp"     
  }  
 ruby {   
   code => "event.set('timestamp', event.get('@timestamp').time.localtime + 8*60*60)"   
 }  
 ruby {  
   code => "event.set('@timestamp',event.get('timestamp'))"  
 }  
 mutate {  
   remove_field => ["timestamp"]  
 }  
}

4. index 索引名稱少 8 小時


# 1. 增加一個字段,計算timestamp+8小時
ruby { 
    code => "event.set('index_date', event.get('@timestamp').time.localtime + 8*60*60)" 
} 
# 2. 用mutate插件先轉換爲string類型,gsub只處理string類型的數據,在用正則匹配,最終得到想要的日期
mutate { 
    convert => ["index_date", "string"] 
    gsub => ["index_date", "T([\S\s]*?)Z", ""] 
    gsub => ["index_date", "-", "."] 
}      
# 3.output配置
elasticsearch { 
  hosts => ["localhost:9200"] 
  index => "myindex_%{index_date}" 
}

5. 時區問題的解釋


  • 很多中國用戶經常提一個問題:爲什麼 @timestamp 比我們早了 8 個小時?怎麼修改成北京時間?

  • 其實,Elasticsearch 內部,對時間類型字段,是統一採用 UTC 時間,存成 long 長整形數據的!對日誌統一採用 UTC 時間存儲,是國際安全/運維界的一個通識——歐美公司的服務器普遍廣泛分佈在多個時區裏——不像中國,地域橫跨五個時區卻只用北京時間。

  • 對於頁面查看,ELK 的解決方案是在 Kibana 上,讀取瀏覽器的當前時區,然後在頁面上轉換時間內容的顯示。

  • 所以,建議大家接受這種設定。否則,即便你用 .getLocalTime 修改,也還要面臨在 Kibana 上反過去修改,以及 Elasticsearch 原有的 ["now-1h" TO "now"] 這種方便的搜索語句無法正常使用的尷尬。

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