日誌服務(SLS)是阿里集團自研的一站式日誌平臺,它包含數據實時採集、數據加工、智能查詢分析以及數據分發四大基礎功能,用戶無需開發就能能夠開箱即用地使用它來提升運維、運營效率,建立 DT 時代海量日誌處理能力。
為了讓大家對日誌服務有更直觀的感受,本文將帶著大家體驗一下這些基礎功能,以最常見的 Linux Syslog 作為對象,看看如何簡單快速地實現對它的採集、加工、查詢分析以及可視化。
Linux Syslog
Syslog 是 Unix 類操作系統上非常常見的一種日誌,廣泛應用於系統日誌,但同樣可作為應用輸出日誌的一種形式。在許多 Linux 發行版上,部分 Syslog 默認會被存放在本地目錄 /var/log/
中,其中包含 messages
、kern
、secure
等多個分別用於存放不同類似日誌的文件。
本文將以最常見的 /var/log/messages
作為實驗目標,以下是一些示例日誌:
# OOM 日誌
[ 1074.669060] Out of memory: Kill process 20680 (perl) score 487 or sacrifice child
[ 1074.669089] Killed process 20680 (perl), UID 0, total-vm:1072528kB, anon-rss:943192kB, file-rss:0kB, shmem-rss:0kB
# 應用日誌
Mar 16 12:04:08 clusterx-master systemd: Removed slice libcontainer_8947_systemd_test_default.slice.
Mar 16 12:04:08 clusterx-master systemd: Scope libcontainer-8952-systemd-test-default-dependencies.scope has no PIDs. Refusing.
# 登錄日誌(特殊應用)
Mar 13 12:29:25 clusterx-master sshd[13501]: Accepted publickey for root from 192.168.56.1 port 64934 ssh2: RSA SHA256:W8j/QK8kV0Ab8/yTENQko8
Mar 13 12:29:25 clusterx-master sshd[13501]: pam_unix(sshd:session): session opened for user root by (uid=0)
Mar 13 13:19:08 clusterx-master sshd[13501]: Received disconnect from 192.168.56.1 port 64934:11: disconnected by user
Apr 16 20:00:50 clusterx-master sshd[718]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=192.168.56.1 user=root
Apr 16 20:00:52 clusterx-master sshd[718]: Failed password for root from 192.168.56.1 port 54469 ssh2: RSA SHA256:W8j/QK8kV0Ab8/yTENQko8
數據實時採集
首先,我們需要實現對這些日誌的採集。由於系統日誌需要外部事件觸發,產生時機不太確定,因此,我們針對上述的示例日誌編寫了一個生成器以保證實驗過程持續有日誌產生。
在機器上運行生成器,即會不斷地有日誌輸出到文件 /var/log/mock_messages
。
$ mkdir mock-syslog; cd mock-syslog
$ wget http://baoze-oss-bj.oss-cn-beijing.aliyuncs.com/mock-syslog/raw_data
$ wget http://baoze-oss-bj.oss-cn-beijing.aliyuncs.com/mock-syslog/mock_messages.py
$ chmod +x mock_messages.py
$ nohup ./mock_messages.py /var/log/mock_messages &
$ tail /var/log/mock_messages
為了存放日誌,我們需要先開通日誌服務,並在控制檯上創建相應的 project/logstore,過程可參考快速入門中的步驟 1。對於文本日誌,我們可通過 SLS 自研的採集 agent Logtail 來實現採集。
操作步驟如下:
- 創建 Logtail 採集配置,選擇【單行-文本日誌】
- 在機器上安裝 logtail,對於 ECS 機器,可直接在控制檯上進行勾選,點擊【立即執行】後即可完成安裝
- 安裝完成後,勾選機器 IP 會被自動加入到機器組列表中,在填寫名稱後即可完成創建機器組創建
- 填寫配置
- 跟隨嚮導完成配置,點擊【立即嘗試】進入查詢界面
數據查詢
進入查詢界面後,只需稍等一會兒,待採集配置下發到 logtail 後,即可通過點擊【查詢/分析】按鈕瀏覽日誌內容。藉助 SLS 針對日誌的極致優化,我們可以通過關鍵詞快速地從海量日誌中查詢我們感興趣的日誌。比如:
通過關鍵詞 sshd
查詢登錄日誌
通過關鍵詞 Out of memory
查詢 OOM 日誌
除了基礎的關鍵字查詢外,SLS 還提供了 and/or/not 等謂詞進行組合查詢(文檔),能夠滿足更為豐富的查詢場景。
數據加工
在完成數據的採集和查詢後,我們會發現,因為日誌是單行採集上來的,日誌的所有內容都被放在了單一的 content
字段中,相對來說會比較混亂。在這種情況下,我們很難對日誌的內容進行進一步地分析,比如有哪些應用輸出了系統日誌、最近一天是否有應用發生 OOM、發生次數等等。
假設我們期望通過分析日誌來得到以下信息:
- 哪些進程產生了系統日誌,分別產生了多少?如果產生了較多日誌的話,可能說明應用存在一些異常?
- 其中的哪些應用發生過 OOM ?頻繁 OOM 的應用需要得到關注。
- 僅查看進程 sshd 產生的登錄日誌,檢查短時間內是否有較多的密碼登錄失敗(可能是入侵攻擊)?如果有,IP 和端口是什麼?
如果要完成上述需求,從數據分析的角度來說,我們需要識別出:
- 每條日誌所屬的進程名
- 哪些日誌是 OOM 日誌
- 哪些日誌是 sshd 密碼登錄失敗?
通過數據加工,我們可以非常簡單地完成上述需求,通過增加額外的字段來標記對需要識別的內容。
1. 標記 OOM 日誌
[ 1074.669060] Out of memory: Kill process 20680 (perl) score 487 or sacrifice child
[ 1074.669089] Killed process 20680 (perl), UID 0, total-vm:1072528kB, anon-rss:943192kB, file-rss:0kB, shmem-rss:0kB
從示例來看,OOM 日誌有兩個關鍵字 Out of memory
和 Killed process
,並且都包含了發生 OOM 的進程 ID 和進程名。因此,我們可以通過數據加工 DSL 中的正則提取來完成字段抽取,如下:
# 解析 oom_kill 日誌
e_if(op_or(
regex_match(v("content"), "Out of memory"),
regex_match(v("content"), "Killed process")),
e_compose(
e_set("log_type", "oom_kill"),
e_regex("content", "process (?<pid>[0-9]*) \((?<process>[a-zA-Z0-9_]*)\)")))
藉助數據加工的預覽功能,我們可以快速地判斷上面的處理是否滿足需求。
測試數據及處理邏輯
結果
可以看到,兩條日誌都增加了 log_type:oom_kill
的字段,並通過 process
和 pid
兩個字段記錄了發生 OOM 的進程名和 PID。
2. 解析 Syslog 基本字段
雖然 Syslog 的輸出格式並未嚴格統一,但大部分 Linux 發行版下,都由時間、主機名、進程名、可選的進程 PID 以及日誌內容幾部分組成,其中,最後的日誌內容完全由應用定義。
為了能夠分析各個應用輸出日誌的情況,我們可以按照上面的格式來對所有日誌進行字段提取。類似地,我們藉助 DSL 正則提取來實現:
# 解析 syslog 基本字段
e_regex("content", "(?<system_time>[a-zA-Z 0-9:]{15}) (?<hostname>[a-zA-Z0-9\-]*) (?<process>([a-zA-Z0-9\-]*))(\[(?<pid>[0-9]*)\])?: (?<message>.*)")
同樣地,藉助預覽功能進行快速驗證,確認日誌被提取成我們所期望的 system_time
、hostname
、process
、pid
、message
字段。
3. 豐富登錄日誌
從前面的示例日誌我們可以知道,登錄日誌的 message
字段內容並不固定,不同內容向我們展示了不同信息,比如:
- Accepted publickey 告訴我們有人成功使用密鑰完成對某個用戶的登錄;
- Failed password 告訴我們有人使用密碼登錄某個用戶失敗;
- Received disconnect 告訴我們有人斷開了連接。
而這些日誌同時也有共性,它們記錄了期望登錄的用戶、登錄的 IP、端口等信息。基於這些特點,我們可以對 sshd 的日誌進行進一步地處理,提取出這些公共字段,並根據展示內容進行特殊標記。
e_if(e_search('process=="sshd"'),
e_compose(
e_regex("content", grok('%{IP:ip}')),
e_regex("content", "port (?<port>[0-9]*)"),
e_if(regex_match(v("content"), "Received disconnect from"),
e_set("sshd_action" , "client_disconnect")),
e_if(regex_match(v("content"), "Failed password"),
e_set("sshd_action" , "client_password_fail")),
e_if(regex_match(v("content"), "Accepted publickey"),
e_set("sshd_action" , "client_login"))
))
結果如下:
4. 輸出到新目標
在完成了上述所有規則的調試後,我們可以把它們合併在一起,併為處理後的日誌指定一個新的 logstore(命名為 processed_syslog,需要手動創建)作為輸出目標。
在【加工結果頁】中,點擊【保存數據加工】即可將規則進行保存。
當加工任務啟動後,我們就可以在新 logstore 中看到處理後的日誌。
數據分析以及可視化
在藉助數據加工完成數據處理後,我們就可以開始前面提到的分析工作了。SLS 提供了支持 SQL92 標準的分析語法,可以方便地支撐我們完成各類場景下的分析需求。
0. 快速創建索引
為了使用分析功能,我們首先需要對待分析的字段創建相應的索引,這一過程可以使用控制檯提供的自動創建索引功能快速完成。
在創建完索引後,我們就可以使用 SQL 對先前提到的需求進行分析。
1. 分析應用日誌分佈
not log_type:oom_kill | select process, count(*) as c group by process order by c desc
通過上面的分析語句,我們即可得到每個進程分別輸出了多少條日誌,如下:
除了最基本的預覽圖表外,SLS 控制檯提供了非常豐富的可視化能力,並且我們能夠將對應的可視化圖表以儀表盤的形式保存下來。比如使用餅圖來呈現上面的結果:
儀表盤效果
2. 分析 OOM 應用
統計最近 10 分鐘發生 OOM 的次數,並同比 10 分鐘前的情況,以單值圖的形式展示。
# 同環比
log_type:oom_kill | select diff[1] as today, round((diff [3] -1.0) * 100, 2) as growth from (select compare(count, 600) as diff from (select count(1) as count from log))
查看 OOM 應用分佈
log_type:oom_kill and process:* | select process, count(*) as c group by process order by c desc
3. 分析登錄失敗 IP 分佈
process:sshd and sshd_action:client_password_fail | select ip, count(*) as c group by ip order by c desc
根據 IP 獲取來源地(國家)
process:sshd and sshd_action:client_password_fail | select ip_to_country(ip) as country, sum(c) as c from( select ip, count(*) as c from log group by ip order by c desc) group by country