SystemTap 是監控和跟蹤運行中的Linux 內核的操作的動態方法,SystemTap 應用:對管理員,SystemTap可用于監控系統性能,找出系統瓶頸,而對于開發者,可以查看他們的程序運行時在linux系統內核內部的運行情況,下面我們來看看systemtap監控應用與碰到的問題分析。
應用場景:一天,在我們服務器上PHP代碼路徑下多了一個log文件,從沒注意到有這個log文件,但是log文件的格式明顯不是我們生成的,格式比較簡單,甚至沒有function name,log level,明顯是我們使用的某個第三方庫的輸出,到底是那個進程調用第三方庫干的壞事?我們當然是有懷疑對象的,從log的語義也可以初步判斷是那個進程干的這件事,可是沒有證據.
有的童鞋就說了,對這個可疑進程直接執行lsof -p pid或者對文件執行 lsof file不就OK 了,如果這個進程打開了這個莫名其妙的文件,就證明的確是可疑進程寫了這個log文件,可惜的是這個進程不是daemon,而且執行時間特別短,來不及對他進行lsof.
這有到了我們systemtap橫空出世的時候了,systemtap由于他的可定制,幾乎是一把無所不能的瑞士軍刀,第一思路就是監控sys_open,看下到底是那個進程在作死,打開了這個莫名其妙的文件.
方法一:監控sys_open
我們都知道systemtap可以監控系統調用,open作為一個系統調用,我們自然可以監控,如果open的文件恰好是我們要追蹤的文件,我們就將pid,execname 打印出來,真相大白,代碼如下:
- function is_open_creating:long (flag:long)
- {
- CREAT_FLAG = 4 // 0x4 = 00000100b
- if (flag & CREAT_FLAG)
- {
- return 1
- }
- return 0
- }
- probe begin
- {
- printf("monitor file beginn")
- }
- probe kernel.function("sys_open")
- {
- if(user_string($filename)== "/home/manu/shell/temp/abc.log")
- {
- creating = is_open_creating($mode);
- if(creating)
- {
- printf("pid %ld (%s) create the file %sn",pid(),execname(),user_string($filename));
- }
- else
- {
- printf("pid %ld (%s) open the file %s n",pid(),execname(),user_string($filename));
- }
- }
- }
OK,我們開始監控,看看能否捕捉到搗亂者,代碼如下:
- root@manu:~/code/systemtap#
- root@manu:~/code/systemtap# stap file_monitor.stp
- monitor file begin
我們在另一個終端l中echo創建這個/home/manu/shell/temp/abc.log,代碼如下:
root@manu:~/code/shell/temp# echo abefdf >/home/manu/code/shell/temp/abc.log
root@manu:~/code/shell/temp#
我們看到stap捕捉到了這個事件,代碼如下:
- root@manu:~/code/systemtap# stap file_monitor.stp
- monitor file begin
- pid 3024 (bash) create the file /home/manu/code/shell/temp/abc.log
Stap捕捉到進程名為bash,PID為3024的進程create了這個文件,目前為止,一切都好,可惜這種方法有個致命的缺陷。filename是進程調用系統調用 open時 輸入的文件名,可能輸入全路徑/home/manu/shell/temp/abc.log,也可能輸入的是相對路徑,如果輸入的是相對路徑,我們的stap不能捕捉到這個事件.
比如我們再次想abc.log追加寫:
- root@manu:~/code/shell/temp# echo "second line " >> abc.log
- root@manu:~/code/shell/temp# cat abc.log
- abefdf
- second line
- root@manu:~/code/shell/temp#
另一端沒有stap沒有檢測到任何事件.
這種方法有缺陷,因為我們不能夠假設進程輸入的絕對路徑還是相對路徑.
方法二:監控文件的inode
文件的名字表示方法可能不同,比如當前路徑是 /home/manu/shell/temp/,下面表示的都是同一個文件,這就給上面一種方法帶來的困難.
- abc.log
- ./abc.log
- ../temp/abc.log
- /home/manu/shell/temp/abc.log
- .....
如果我們的文件在磁盤上,那么只要有,主設備號,次設備好,inode,這三個元素,就唯一確定了一個文件,我們還是監控剛才的abc.log,對于我的文件在/dev/sda6,對應的主設備號和次設備號是,0x8,0x6,abc.log對應的inode為:
361way:/opt # ll -ali abc.log
2099351 -rwxr-xr-x 1 root root 17623 Sep 2 22:55 abc.log
我們的三元組是(0x08,0x06,2099351),下面是我們的監控腳本inode_monitor.stp,代碼如下:
- probe begin
- {
- printf("watch inode %d %d %ld beginn",$1,$2,$3)
- }
- probe vfs.write
- {
- if (dev == MKDEV($1,$2) # major/minor device
- && ino == $3)
- printf ("%s(%d) %s 0x%x/%un",execname(), pid(), probefunc(), dev, ino)
- } //Vevb.com
然后我們讓stap來監控這個inode對應的文件,代碼如下:
root@manu:~/code/systemtap# stap inode_monitor.stp 0x8 0x6 2099351
watch inode 8 6 2099351 begin
開始我們的實驗,我們在shell終端上echo兩句寫入abc.log,在寫一個test.sh腳本去寫這個abc.log,實驗如下:
- root@manu:~/code/shell/temp# echo abefdf >abc.log
- root@manu:~/code/shell/temp# echo "second line" > ./abc.log
- root@manu:~/code/shell/temp# cat test.sh
- #!/bin/sh
- echo "third line " >> ./abc.log
- root@manu:~/code/shell/temp# ./test.sh
stap監控腳本的輸出如下:
- root@manu:~/code/systemtap# stap inode_monitor.stp 0x8 0x6 2099351
- watch inode 8 6 2099351 begin
- bash(3024) vfs_write 0x800006/2099351
- bash(3024) vfs_write 0x800006/2099351
- test.sh(9484) vfs_write 0x800006/2099351
我們看到這三個事件都被捕捉到了,也就完成了我們監控這個文件,判斷到底是那個進程寫入這個log的目標.
systemtap作為一個動態監控和跟蹤linux內核的工具,其功能還可以發掘更多,更多內容可以查看IBM社區或systemtap官方網站,同時也可以了解DTrace、ProbeVue,這兩者在unix平臺上,及fanotify,下一代的inotify文件監控,同類工具.
其他性能工具OProfile、Valgrind、Perf、 redhat MGR 等回頭再總結學習.
新聞熱點
疑難解答