Linux 日誌分析
雖然提取的時候,不總是和你想的一樣簡單,但是日誌中有大量資訊在等著你。在這部分,我們會講一些基本分析示例,你可以馬上拿來處理你的日誌(只是搜尋裡面有什麼)。我們還會講一些高階分析方法,開始的時候可能要花時間來做配置,但會為以後省很多時間。你可以把高階分析的示例用在待解析的資料上,比如生成摘要計數,過濾欄位值等。
首先我們會演示,你應該如何使用不同的工具在命令列進行日誌分析;然後,演示一個日誌管理工具,它能夠讓大多數乏味的工作變得自動化和高效。
使用 Grep 搜尋
搜尋文字是找到你想要的資訊的最基本方法。搜尋文字最常用的工具是 grep 。這個命令列工具,大多數 Linux 發行版上都有,它支援你用正規表示式來搜尋日誌。正規表示式是一種用專門語言寫成的語句,可用來識別匹配文字。最簡單的正規表示式是把你搜尋的字串加上引號。
正規表示式
這裡有個例子,它在 Ubuntu 的認證日誌裡搜尋 “user hoover”:
1 2 3 4 |
$ GREP "USER HOOVER" /VAR/LOG/AUTH.LOG ACCEPTED PASSWORD FOR HOOVER FROM 10.0.2.2 PORT 4792 SSH2 PAM_UNIX(SSHD:SESSION): SESSION OPENED FOR USER HOOVER BY (UID=0) PAM_UNIX(SSHD:SESSION): SESSION CLOSED FOR USER HOOVER |
構造精確的正規表示式很難。例如,假設我們搜尋一個數字,比如埠號“4792” ,它也可以匹配時間戳,URLs和其他不需要的資料。在下面針對 Ubuntu 的例子裡,它匹配了 Apache 日誌,但這並不是我們想要的。
1 2 3 |
$ grep "4792" /var/log/auth.log Accepted password for hoover from 10.0.2.2 port 4792 ssh2 74.91.21.46 - - [31/Mar/2015:19:44:32 +0000] "GET /scripts/samples/search?q=4972HTTP/1.0" 404 545 "-" "-” |
延伸搜尋
另一個有用的技巧是你可以用grep 做延伸搜尋。它會輸出匹配項的前幾行和後幾行內容。它可以幫你除錯是什麼導致了錯誤或問題。B 選項指定顯示匹配項前面的行數,A 選項指定顯示匹配項後面的行數。如下所示,我們看到,當有人以 admin 身份登陸失敗後, 反向對映也會失敗,這說明他們可能沒有有效的域名。這很可疑!
1 2 3 4 5 6 |
$ grep -B 3 -A 2 'Invalid user' /var/log/auth.log Apr 28 17:06:20 ip-172-31-11-241 sshd[12545]: reverse mapping checking getaddrinfo for 216-19-2-8.commspeed.net [216.19.2.8] failed - POSSIBLE BREAK-IN ATTEMPT! Apr 28 17:06:20 ip-172-31-11-241 sshd[12545]: Received disconnect from 216.19.2.8: 11: Bye Bye [preauth] Apr 28 17:06:20 ip-172-31-11-241 sshd[12547]: <b>Invalid user</b>; admin from 216.19.2.8 Apr 28 17:06:20 ip-172-31-11-241 sshd[12547]: input_userauth_request: invalid user admin [preauth] Apr 28 17:06:20 ip-172-31-11-241 sshd[12547]: Received disconnect from 216.19.2.8: 11: Bye Bye [preauth] |
Tail命令
你也可以將 tail 和 grep 搭配起來使用,以獲取檔案最後幾行,或者跟蹤日誌並實時列印。當你在進行互動式更改比如架設伺服器或測試程式碼更改的時候,非常有用。
1 2 3 |
$ tail -f /var/log/auth.log | grep 'Invalid user' Apr 30 19:49:48 ip-172-31-11-241 sshd[6512]: Invalid user ubnt from 219.140.64.136 Apr 30 19:49:49 ip-172-31-11-241 sshd[6514]: Invalid user; admin from 219.140.64.136 |
全面介紹 grep 和正規表示式超出了本文的範圍,Ryan 的教程裡有更深入的介紹。
日誌管理系統中有更高效更強大的搜尋工具。它們通常對資料建立索引和並行查詢,因此你可以在數秒之內快速查詢高達 G 位元組或 T 位元組的日誌。相比之下,用 grep ,可能要花幾分鐘,極端情況下會花費數小時。日誌管理系統也像 Lucene (譯註:一個開源的全文檢索引擎工具包)一樣使用查詢語言 ,它為數字,欄位等的搜尋提供了簡單的語法。
用Cut,AWK 和 Grok 解析日誌
命令列工具
Linux 提供了幾種文字解析和分析的命令列工具。如果你想快速解析少量的資料,它們很強大,但是處理大量資料要花很長時間。
Cut 命令
cut 命令可以從帶分隔符的日誌中解析欄位。分隔符是類似等號或逗號的字元,用來劃分欄位或鍵值對。
比如說,我們想從這個日誌中提取使用者名稱:
1 |
pam_unix(su:auth): authentication failure; logname=hoover uid=1000 euid=0 tty=/dev/pts/0 ruser=hoover rhost= user=root |
我們可以和下面一樣使用 cut 命令,獲取第八個等號後邊的文字。這是 Ubuntu 上的例子:
1 2 3 4 5 6 |
$ grep "authentication failure" /var/log/auth.log | cut -d '=' -f 8 root hoover root nagios nagios |
AWK 命令
此外,你還可以用 awk,它擁有更強的解析欄位的功能。它提供了一個指令碼語言,讓你幾乎可以過濾出任何毫不相關的資訊。
舉個例子,假設我們在 Ubuntu 上有如下的日誌,我們想提取登陸失敗的使用者名稱:
1 |
Mar 24 08:28:18 ip-172-31-11-241 sshd[32701]: input_userauth_request: invalid user guest [preauth] |
下面是使用 awk 的例子。首先,用一個正規表示式 /sshd.*invalid user/ 匹配 sshd 無效使用者的那一行。然後使用 { print $9 } 列印第九個欄位(預設的分隔符是空格)。這樣就輸出了使用者名稱。
1 2 3 4 5 6 |
$ awk '/sshd.*invalid user/ { print $9 }' /var/log/auth.log guest admin info test ubnt |
你可以從 Awk 使用者指南中獲取更多關於如何使用正規表示式和列印欄位的資訊。
日誌管理系統
日誌管理系統讓解析更容易並且讓使用者可以快速分析大量日誌檔案。它們可以自動解析標準日誌格式,比如公共 Linux 日誌或 web 服務日誌。這會節省很多時間,因為你在定位系統問題的時候不用去想如何寫你的解析邏輯。
這裡你可以看一個來自 sshd 的日誌資訊,解析出了遠端主機和使用者欄位。這個截圖來自 Loggly,一個基於雲端計算的日誌管理服務。
對非標準格式的日誌,你也可以自定義解析規則。最常用的工具是 Grok,它用通用正規表示式庫把純文字解析成 JSON 格式。這是 Grok 的配置示例,用來解析 Logstash 的核心日誌 :
1 2 3 4 5 |
filter{ grok { match => {"message" => "%{CISCOTIMESTAMP:timestamp} %{HOST:host} %{WORD:program}%{NOTSPACE} %{NOTSPACE}%{NUMBER:duration}%{NOTSPACE} %{GREEDYDATA:kernel_logs}" } } |
這是用 Grok 解析後輸出的結果:
使用 Rsyslog 和 AWK 過濾
過濾是搜尋特定的欄位,而不是全部文字。這讓你的日誌分析更精確,因為它會忽略其他不需要的日誌資訊。為了搜尋一個欄位值,你需要先解析你的日誌或者至少有一種基於事件結構的搜尋方法。
如何篩選出同一個應用的日誌
通常,你只想看來自同一個應用的日誌。如果你的應用總是把日誌記錄在單個檔案中,這樣很容易分析。如果你要從聚合或集中起來的日誌裡篩選出和某個程式相關的日誌,會很複雜。這裡有幾種解決的辦法。
- 用 Rsyslog 服務解析和過濾日誌。這個例子是將 sshd 應用程式的日誌寫入名為 sshd-messages 的檔案中,然後丟棄事件,所以它不會在其他日誌裡重複出現。你可以把它加到你的 Rsyslog.conf 檔案裡試一下。
1 2 |
:programname, isequal, “sshd” /var/log/sshd-messages &~ |
- 使用命令列工具比如 awk ,提取特定欄位的值,比如取 sshd 使用者名稱。這是 Ubuntu 上的例子。
1 2 3 4 5 |
$ awk '/sshd.*invalid user/ { print $9 }' /var/log/auth.log guestadmin info test ubnt |
- 使用日誌管理系統自動解析你的日誌,然後點選目標應用的名字進行過濾。這個截圖顯示了 syslog 的各個欄位,在一個叫做 Loggly 的日誌管理服務中。如圖中文氏圖所示,當前正在過濾 sshd 這個應用。
如何篩選出錯誤資訊
最常見的事情是,人們想看到日誌中的錯誤。不巧的是,預設的 syslog 配置不會直接輸出錯誤的級別,這使得錯誤資訊很難被篩選。
這裡有兩種方案來解決這個問題。首先,你可以修改 rsyslog 配置,讓它輸出級別到日誌檔案中,使得錯誤資訊容易被讀取和搜尋。在你的 Rsyslog 配置中你可以加一個pri-text 模版,如下所示:
1 |
"<%pri-text%> : %timegenerated%,%HOSTNAME%,%syslogtag%,%msg%n" |
這個例子的輸出如下,可以看到級別是 err。
1 |
<authpriv.err> : Mar 11 18:18:00,hoover-VirtualBox,su[5026]:, pam_authenticate: Authentication failure |
你可以用 awk 或grep 篩選出錯誤資訊。這是 Ubuntu 下的例子,我們加了開始結束標誌 . 和 > ,這樣它就只匹配這個欄位。
1 2 |
$ grep '.err>' /var/log/auth.log <authpriv.err> : Mar 11 18:18:00,hoover-VirtualBox,su[5026]:, pam_authenticate: Authentication failure |
第二種選擇是使用日誌管理系統。好的日誌管理系統會自動解析 syslog 訊息並提取出級別欄位。只需點一下,就會按指定的級別篩選日誌。
這是 Loggly 的截圖。顯示了 syslog 各個欄位, Error 級別高亮顯示了,說明正在按級別 Error 過濾
打賞支援我翻譯更多好文章,謝謝!
打賞譯者
打賞支援我翻譯更多好文章,謝謝!