syslog之二:syslog協議及rsyslog服務全解析

背景:需求來自於一個客戶想將服務器的日誌轉發到自己的日誌服務器上,所以希望我們能提供這個轉發的功能,同時還要滿足syslog協議。

一、什麼是syslog協議

1、介紹(略)

2、syslog標準協議如下圖

  這裏的facility爲模塊,serverity爲等級,由這兩個信息共同計算出一個PRI頭部。HEADER部分包含了時間和主機名。在HEADER和MSG之間有一個空格,MSG是需要記錄的日誌部分(日誌消息體)。

  這裏也就是說,理論上使用這種格式構造的字符串發送,接收方就能解析出來。實際上根據實驗,我使用了UDP發送,接收方syslog日誌服務器能正確解析。

  這裏需要注意的是,如果使用了程序的庫,比如:python的syslog庫(同樣c++也有相似的庫),那麼就不再需要關注PRI和HEADER部分,只要將相關的參數(facility,severity,time,ip)傳入函數,調用發送就可以,不必自己構造字符串。對服務端來說,接收到的是整個消息,但通常來講,比如使用linux默認的rsyslog作爲接收服務端的話,是不能看到除MSG之外的部分。所看到的消息跟接收端配置有關,這個在下面有具體的講。

3、以下是各級別及對應的數字代碼

Facility:有0-23種設備可選,在python的syslog庫中有一部分缺失

複製代碼
0 kernel messages 
1 user-level messages 
2 mail system 
3 system daemons 
4 security/authorization messages 
5 messages generated internally by syslogd 
6 line printer subsystem 
7 network news subsystem 
8 UUCP subsystem 
9 clock daemon 
10 security/authorization messages 
11 FTP daemon 
12 NTP subsystem 
13 log audit 
14 log alert 
15 clock daemon 
16-23     local0 - local7
複製代碼

Severity:日誌等級

複製代碼
0 Emergency
1 Alert
2 Critical
3 Error
4 Warning
5 Notice
6 Informational
7 Debug
複製代碼

這裏結合等級再詳細講一下syslog協議:

Priority(優先級) = facility * 8 + severity值。比如說,一個核心信息(facility=0)和一個Emergency的severity將會產生優先級爲0。同樣, 一個“local use 4”信息(facility=20)和一個Notice的severity(severity=5)將會產生165的優先級。

標題(HEADER)部分由稱爲TIMESTAMP和HOSTNAME的兩個域組成,PRI結尾的“>”會馬上跟着一個 TIMESTAMP,任何一個TIMESTAMP或者HOSTNAME域後面都必須跟着一個空格字符。HOSTNAME包含主機的名稱,若無主機名或無法 識別則顯示IP地址。如果一個主機有多個IP地址,它通常會使用它傳送信息的那個IP地址。TIMESTAMP是本機時間,採用的格式是“Mmm dd hh:mm:ss”表示月日時分秒。HOSTNAME域僅僅能夠包括主機名稱,Ipv4地址或者是信息產生者的Ipv6地址。

MSG部分是Syslog數據包剩下的部分。這通常包含了產生信息進程的額外信息,以及信息的文本部分。MSG部分有兩個域,分別爲TAG域和 CONTENT域,TAG域的值是產生信息的程序或者進程的名稱,CONTENT包含了這個信息的詳細內容。傳統上來說,這個域的格式較爲自由,並且給出 一些時間的具體信息。TAG是一個不許超過32個字符的字母數字字符串,任何一個非字母數字字符都將會終止TAG域,並且被假設是CONTENT域的開 始。在大多數情況下,表示TAG結束的CONTENT域的第一個字符用左大括號( [ ],分號( : )或者是空格來表示。

下面是一個使用socket實現syslog日誌的py腳本,大家可以參考,加深理解syslog協議

https://github.com/ucookie/anytools/blob/master/usyslog/usyslog.py

4、Syslog庫

  以python的庫爲例:

  openlog(ident[, logopt[, facility]])

  首先需要使用openlog指定模塊及相應的信息。ident爲頭部需要顯示的字符串,這個信息不包含在MSG中,可以通過配置日誌服務器模板決定是否顯示。logopt是一些參數,可選擇有(LOG_PIDLOG_CONSLOG_NDELAYLOG_NOWAIT and LOG_PERROR),對應的分別是(包括每個消息PID,直接寫入系統控制檯,立即打開連接,不等待子進程(因爲其有可能在記錄消息的時候就被創建了,GNU C庫不創建子進程,所以該選項在Linux上沒有影響),同時輸出到stderr)。facility則是模塊參數,需要填入對應的值,這裏syslog庫中有以下參數使用:

1
2
LOG_KERN, LOG_USER, LOG_MAIL, LOG_DAEMON, LOG_AUTH, LOG_LPR
LOG_NEWS, LOG_UUCP, LOG_CRON and LOG_LOCAL0 to LOG_LOCAL7

  通常來說,openlog需要在模塊最開始指定,即限定了這個模塊內都是一個facility的日誌。

  

  syslog([sevirity], msg):

  這個是具體打印日誌的函數,第一個參數指定消息的級別,第二個參數爲日誌內容。

  sevirity對應的參數爲:

1
LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR, LOG_WARNING, <br data-filtered="filtered">LOG_NOTICE, LOG_INFO, LOG_DEBUG.

  

  closelog():

  這個是關閉的功能,不過多解釋了。

5、說明部分

  python的syslog庫打印日誌是依賴了rsyslog服務,具體的轉發規則,記錄文件等在rsyslog.conf中配置

二、瞭解rsyslog服務

1、rsyslog介紹(略)

2、rsyslog配置文件

  配置文件/etc/rsyslog.conf大概分爲三個部分

  #MODULES

  這個部分是針對接收配置的,主要是指定接收日誌的協議和端口。若要配置日誌服務器,則需要將相應的配置項去掉註釋。

  #GLOBAL DIRECTIVES

  這個部分主要用來配置模板,模板的作用是指定你希望在日誌文件中保存的日誌格式。

  默認配置爲:

1
2
# Use default timestamp format
$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat

  這裏列舉一個模板,將所有信息保存:

1
2
3
4
5
6
7
8
9
10
11
12
# 這裏第一行(爲了方便顯示,參數寫成了一列)是模板,即日誌服務器記錄到日誌文件的格式
# 第二行是指定需要使用的模板myFormat,這個名字可以自己定義
$template myFormat,"%TIMESTAMP% host=%HOSTNAME%,
                   relayHost=%FROMHOST%,
                   tag=%syslogtag%,
                   programName=%programname%,
                                procid=%PROCID%,
                                facility=%syslogfacility-text%,
                                sev=%syslogseverity-text%,
                                appName=%APP-NAME%,
                                msg=%msg%\n"
$ActionFileDefaultTemplate myFormat

  模板額外說明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#在rsyslog7 和更高版本使用以下格式:
template(name="scalaLogFormat" type="list") {
        property(name="timestamp" dateFormat="rfc3339")
        constant(value=" host=")
        property(name="hostname")
        constant(value=", relayHost=")
        property(name="fromhost")
        constant(value=", tag=")
        property(name="syslogtag")
        constant(value=", programName=")
        property(name="programname")
        constant(value=", procid=")
        property(name="procid")
        constant(value=", facility=")
        property(name="syslogfacility-text")
        constant(value=", sev=")
        property(name="syslogseverity-text")
        constant(value=", appName=")
        property(name="app-name")
        constant(value=", msg=")
        property(name="msg" )
        constant(value="\n")
        }

  ### begin forwarding rule

  這個模塊主要講一下轉發

  #*.* @@remote-host:514

  根據這個實例可以看出,分爲4個部分[模塊.等級] [轉發協議][日誌服務器地址]:[日誌服務器端口],其中轉發協議的參數@@爲TCP協議,對應的接收端也需要配置接受TCP協議。@爲UDP協議。

  注:使用TCP協議,若地址錯誤或不能連同的情況,轉發的協議會寫入緩存,但是不用擔心會卡死服務器,當到達一定限度後會自動轉存到硬盤,這個不是我們應該關心的部分,使用就好了。

說明:

  針對rsyslog.conf配置文件的所有操作都需要重啓服務生效(service rsyslog restart)

  在新版本的rsyslog中,對日誌發送有默認限速,如果有集中大量推送日誌的情況,需要在配置文件中加上參數$SystemLogRateLimitInterval 0(具體位置沒有影響,但通常寫在GLOBAL DIRECTIVES模塊)

  通常來說,日誌推送到服務器的協議使用UDP

三、實例演示轉發日誌模塊

1、python庫實現

   這個具體查看官方文檔吧

2、使用TCP/UDP通信,自己構造syslog消息發送

  首先了解syslog協議,及接受的方式,自己使用網絡編程實現轉發日誌變成了可能,下面介紹syslog接受原理

  接受端服務器收到發送給它的syslog數據包,它將檢查它的有效PRI。如果第一次字符不是一個“<”,或者第三、第四或者第五不是一個 “>”,接收端將認爲數據包沒有包含有效的PRI。接着檢查在標題部分的有效TIMESTAMP,從這些規則中,信息的接收一般有三個情況,下面給 出了這三個情況的通常屬性,並列舉了隨後在這篇中什麼地方會描寫這些情況。
  有效的PRI and TIMESTAMP:在數據包中發現一個有效的PRI和TIMESTAMP,那麼會接着檢查數據包的內部配置,接收端必須根據數據包的優先級來還原,或者 在不對數據包做任何變化的情況下將它轉發出去。這裏要注意到的是接受端沒有必要確認TIMSTIMP裏面的時間,同時接收端也沒有必要確認 HOSTANME的值和發送信息設備的主機名或者IP地址一致。
有效的 PRI,但沒有TIMESTAMP 或者TIMESTAMP無效:要是在數據包中發現一個有效的TIMESTAMP,那麼必須馬上添加一個TIMESTAMP和一個空格字符在PRI部分的結 尾的方括號內,它還必須添加一個HOSTNAME和空格字符在TIMESTAMP後面,接收到的信息包剩下的部分必須被當曾MSG的CONTENT域並附 加上,由於無法識別產生信息的設備所發出的進程,TAG的值無法被識別出來, 所以不會包含再裏面。TIMESTAMP將會是接收端的本地時間,HOSTNAME是設備的名稱,它被中繼器所識別。如果名字如能被決定, 設備的IP地址將被使用到。要是中繼器添加一個TIMESTAMP(或者同時添加TIMESTAMP和HOSTNAME)在PRI後面, 然後檢 查是否數據包的總體長度仍然小於或等於1024個字節。如果數據包被擴展超過1024個比特, 中繼器必須截去一部分數據包數據使它到達到1024比特。這將會導致原始數據包結尾部分重要信息的丟失. 所以,這就是產生的syslog數據包的PRI和HEADER部分包含在4.3節所記錄的值和域之中的緣故。
  沒有 PRI or 或者 PRI無法識別:如果收不到PRI或者PRI不可識別,除了必須插入一個優先級爲13的PRI和我們在上面描述的TIMESTAMP,還必須插入一個 HOSTNAME。被接收到的數據包的全部內容將被認爲是被傳遞的MSG的CONTENT並被添加在後面。一個不可識別的PRI的例子就是“< 00>”,這也許是一個信息的前4個字符。如果接收到這樣的syslog信息,那麼它的優先級將被中繼器或收集者改爲13,並且加入 TIMESTAMP。具體如下:
原來接收到的信息
  <00>...
  被傳遞或識別的信息
  <13>TIMESTAMP HOSTNAME <00>...
  如果中繼器添加一個TIMESTAMP(或者同時添加一個TIMESTAMP和HOSTNAME)在PRI後面, 那麼它將檢查這個數據包的總體長度是否等於或者小於1024個比特。
  在UNIX文件系統裏頭,syslog設備依據兩個重要的文件:syslogd(守護進程)和syslog.conf配置文件。習慣上,多數syslog 信息被寫到/var/adm或/var/log目錄下的信息文件中(syslog或messages.*)。一個典型的syslog紀錄包括生成程序的名 字和一個文本信息。它還包括一個設備和一個優先級範圍(但不在日誌中出現)。Syslog.conf的格式比較複雜,大家可以參考一下有關書籍(或者在主 機上man syslog.conf),主要是如下語句形式: facility、level、action。Facility代表各種服務,level代表syslog的認證級別,action代表的是針對前面信息 的處理動作。Action字段如果是@loghos(主機名或具體IP),則把信息發送到loghost,而不是本地的 /var/adm/messages。

  所以根據以上規則就可以實現,這裏給一個偷懶的可使用python代碼

  https://github.com/ucookie/anytools/blob/master/usyslog.py

  簡單介紹下這個模塊代碼,主要分爲三個部分:獲取日誌,處理日誌,發送日誌。其中獲取日誌,是從/var/log/app目錄下定期獲取日誌,由於實際情況中,會出現日誌轉存到情況,如果只是單純的從一個文件讀取,在這個過程中日誌被轉存了等情況,程序是不能知道的,會造成混亂。第二部分處理日誌可以選用(這裏是由於用戶需求不明確導致了這個模塊產生,實際上是不必要的),第三部分是這一節想講的,使用的是UDP發送,只要構造了正確規範的字符串發送,syslog日誌服務器就能解析。

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