2010年12月13日 星期一

process監控的問題與替代方法

在監控某一process時,常用
watch -n1 ps -p $(pidof 'process name' ) -o comm,pid,vss,rsz,pcpu,pri,cstime,cutime,utime
或者
while :; do date; ps -p $(pidof 'process name') -o comm,pid,vss.rsz,pcpu,pri,cstime,cutime,utime ;sleep 1; done
while :; do date; ps -oe comm,pid,vss,rsz,pcpu,pri,cstime,cutime,utime | grep 'process name' ;sleep 1; done
或者
for pidd in $(pidof 'process name')
do
top -n 1 -S -b -p $pidd >> $LOG
ps -p $pidd -o comm,cmd,user,group >> $LOG
done

但會發現pcpu(欄位%CPU)不會變,跟top指令比較,TOP確會變
於是修改指令如下,即可:
while :; do date; top -n 1 -S -b | grep vmware-vmx;sleep 1; done

[AIX]
ps -p 442584 -o args,pid,vsz,pcpu
ps -ef -o args,pid,vsz,pcpu

#!/usr/bin/ksh
if [ "$1" = "" ] ; then
echo "you need to entery the [pid] what you want to lookup."
echo "shell>./mon.sh [pid]"
exit 0;
else
# while :; do date >> ~/mon.log;ps -ef -o comm,pid,pcpu,vsz | grep $1 >> ~/mon.log ; sleep 5; done
while :; do date >> ~/mon.log;ps -efl | grep $1 >> ~/mon.log ; sleep 5; done
fi

[結果]
F S UID PID PPID C PRI NI ADDR SZ WCHAN STIME TTY TIME CMD
200003 A root 1 0 0 60 20 d8039000 756 Nov 24 - 0:21 /etc/init
240001 A root 98420 1 0 60 20 d0138400 496 * Nov 24 - 11:37 /usr/sbin/syncd 60
40401 A root 102602 1 0 60 20 e803f400 828 10a09d8 Nov 24 - 0:00 /usr/lib/errdemon

TIME
(all flags) The total execution time for the process.
TTY
(all flags) The controlling workstation for the process:
-
The process is not associated with a workstation.
?
Unknown.
Number
The TTY number. For example, the entry 2 indicates TTY2.
UID
(-f, -l, and l flags) The user ID of the process owner. The login name is printed under the -f flag.
WCHAN
(-l flag) The event for which the process or kernel thread is waiting or sleeping. For a kernel thread, this field is
blank if the kernel thread is running. For a process, the wait channel is defined as the wait channel of the sleeping
kernel thread if only one kernel thread is sleeping; otherwise STIME
(-f and u flags) The starting time of the process. The LANG environment variables control the appearance of this
field.
SZ
(-l and l flags) The size in 1KB units of the core image of the
NI
(-l and l flags) The nice value; used in calculating priority for the sched other policy.
PID
(all flags) The process ID of the process.
PGIN
(v flag) The number of disk I/Os resulting from references by the process to pages not loaded in core.
PPID
(-f, l, and -l flags) The process ID of the parent process.
PRI
(-l and l flags) The priority of the process or kernel thread; higher numbers mean lower priority.
S
(-l and l flags) The state of the process or kernel thread :(見man ps)
F
(-l and l flags) Some of the more important F field flags (hexadecimal and additive) associated with processes and
threads are shown in the following table:(見man ps)
CMD
(-f, -l, and l flags) Contains the command name. Under the -f flag, ps tries to determine the current command name and
arguments both of which may be changed asynchronously by the process. These are then displayed. Failing this, the
command name as it would appear without the option -f, is written in square brackets.

ADDR
(-l and l flags) Contains the segment number of the process stack, if normal; if a kernel process, the address of the
preprocess data area.
C
(-f, l, and -l flags) CPU utilization of process or thread, incremented each time the system clock ticks and the
process or thread is found to be running. The value is decayed by the scheduler by dividing it by 2 once per second.
For the sched_other policy, CPU utilization is used in determining process scheduling priority. Large values indicate
a CPU intensive process and result in lower process priority whereas small values indicate an I/O intensive process
and result in a more favorable priority.

2010年11月16日 星期二

vector與map...怎麼選擇

平常我們在寫程式時,經常可以用很多方法來解決
不過寫到後來,可能會因為客戶要求, 程式品質, 或者挑戰自己
而想要用比較有效率的方法
這時候,什麼是有效率的,沒比較過是不會知道的
我們在寫C++程式時,一定都知道STL,常用的排序與尋找的方法
就是vector 搭配binary_search 以及map這二個較多了

以下的程式碼(BCB5),就把這2個做了一個比較(200萬筆)
//---------------------------------------------------------------------------

#include < vcl.h >
#pragma hdrstop
#include < iostream >
#include < vector >
#include < list >
#include < map >
#include < ctime >
#include < stdio.h >
#include < time.h >
//---------------------------------------------------------------------------
#pragma argsused

using namespace std;

int main(int argc, char* argv[])
{

//vector
vector v;
vector ::iterator it;

v.push_back( 10 );

cout << "vector container " << endl << "================" << endl << endl;
time_t t1; time(&t1);
for(int i=0;i<2000000;i++)
v.push_back(i);
// v.insert( v.begin( ) , i );
time_t t2; time(&t2);
cout<<" vcetor insert data , the time it takes is " << t2-t1 << " sec." << endl;

sort(v.begin(),v.end());

int a;
time_t t5; time(&t5);
for(int i=0;i<2000000;i++)
{
srand(time(NULL));
a=(rand() % 2000000) +1;
bool b1 = binary_search(v.begin(),v.end(),a);
}
time_t t6; time(&t6);
cout<<" vcetor search data , the time it takes is " << t6-t5 << " sec." << endl;


time_t t3; time(&t3);
v.erase (v.begin(),v.begin()+2000000);
time_t t4; time(&t4);
cout <<" vcetor erase data , the time it takes is " << t4-t3 << " sec." << endl ;
//map
map< int,int > mymap;
map< int,int >::iterator map_it;
pair< map< int,int >::iterator,bool > ret;


mymap.insert ( pair< int,int >(0,100) );

cout << endl << "map container " << endl << "================" << endl;
time_t map_t1; time(&map_t1);
for(int i=1;i<2000000;i++)
mymap.insert ( pair(i,2000000+i) );
time_t map_t2; time(&map_t2);
cout << endl <<" map insert data , the time it takes is " << map_t2-map_t1 << " sec." << endl;


int c;
time_t map_t5; time(&map_t5);
for(int i=0;i<2000000;i++)
{
srand(time(NULL));
c=(rand() % 2000000) +1;
map_it=mymap.find(c);
}
time_t map_t6; time(&map_t6);
cout<<" map search data , the time it takes is " << map_t6-map_t5 << " sec." << endl;



time_t map_t3; time(&map_t3);
mymap.erase(mymap.begin(),mymap.end());
time_t map_t4; time(&map_t4);
cout <<" map erase data , the time it takes is " << map_t4-map_t3 << " sec." << endl << endl;

system("pause");
return 0;
}
//---------------------------------------------------------------------------

以下是執行結果,可以明顯看出,vector與binary_search的組合是比較有效率的
你不禁會懷疑,是不是巧合(因為random),執行幾次後,還是一樣

vector container
================

vcetor insert data , the time it takes is 0 sec.
vcetor search data , the time it takes is 4 sec.
vcetor erase data , the time it takes is 0 sec.

list container
================

list insert data , the time it takes is 0 sec.

list erase data , the time it takes is 1 sec.

map container
================

map insert data , the time it takes is 8 sec.
map search data , the time it takes is 5 sec.
map erase data , the time it takes is 1 sec.

請按任意鍵繼續 . . .

從上面的比較可以得知,vector與binary_search的合作似乎都比較好
那為什麼還要用到map,答案隱藏在上面vector程式碼裡用雙斜線mark掉那行
如果我vector都一直insert在第1筆,那效率就很慘了(可以打開來試看看)
況且,如果你的情況,是要一邊insert , 排序, search
那猜測這樣的結果可能不見得會是vector跟binary_search會比較好了(因為不是push_back)
筆者試過,每push_back 1筆就排序一次,只要2萬筆,...就慢到不行

所以建議:
(1)如果資料一剛開始就確定範圍,可以用vector 與binary_search來處理
(2)如果資料使用中不斷變化,簡單方法可以用map
(3)承(2),如果一定要用vector,比較常遇到的解法是
1)不要用sort,改用lower_bound或upper_bound來決定插入資料的位置
2)因為sort資料會花時間,尤其是資料量大時,如果還是要用sort,那就原始資料一律用vector.push_back,
另外建一個vector來與原始資料對應序號(KEY),針對這個KEY的vector進行SORT
會有效率得多,不過在做erase時,請記得2方都要刪除
(當然KEY的vector也可運用1)的技巧)

以下補充:以下參考(http://hi.baidu.com/litinglong2010/blog/item/6b55d23962cbabca9f3d6215.html)

vector中存儲資料 標準關聯容器(map)
概要:在有序vector中存儲資料很有可能比在標準關聯容器中保存相同的資料消耗更少的記憶體;
當頁面錯誤值得重視的時候,在有序vector中通過二分法查找可能比在一個標準關聯容器中查找更快。

當然,有序vector的大缺點是它必須保持有序!當一個新元素插入時,大於這個新元素的所有東西都必須向上移一位。
它和聽起來一樣昂貴,如果vector必須重新分配它的內在記憶體(參見條款14),則會更昂貴,
因為vector中所有的元素都必須拷貝。同樣的,如果一個元素從vector中被刪除,所有大於它的元素都要向下移動。
vector的插入和刪除都很昂貴,但是關聯容器的插入和刪除則很輕量。這就是為什麼只有當你知道
你的資料結構使用的時候查找幾乎不和插入和刪除混合時,使用有序vector代替關聯容器才有意義。

本條款有很多文字,但不幸的是只有很少的例子,所以我們來看看一個使用有序vector代替set的代碼骨架:

vector < Widget > vw; // 代替set < Widget >
... // 建立階段:很多插入,
// 幾乎沒有查找
sort(vw.begin(), vw.end()); // 結束建立階段。(當
// 模擬一個multiset時,你
// 可能更喜歡用stable_sort
// 來代替;參見條款31。)
Widget w; // 用於查找的值的對象
... // 開始查找階段
if (binary_search(vw.begin(), vw.end(), w))... // 通過binary_search查找
vector < Widget > ::iterator i =
lower_bound(vw.begin(), vw.end(), w); // 通過lower_bound查找
if (i != vw.end() && !(w < *i))... // 條款19解釋了
// “!(w < *i)”測試
pair < vector < Widget > ::iterator,
vector < Widget > ::iterator > range =
equal_range(vw.begin(), vw.end(), w); // 通過equal_range查找
if (range.first != range.second)...
... // 結束查找階段,開始
// 重組階段
sort(vw.begin(), vw.end()); // 開始新的查找階段...

就像你可以看到的,這非常直截了當。裏面最難的東西就是怎麼在搜索演算法中做出選擇(比如,binary_search、lower_bound等),條款45可以幫你做出選擇。

當你決定用vector代替map或multimap時,事情會變得更有趣,因為vector必須容納pair物件。
畢竟,那是map和multimap所容納的。但是要注意,如果你聲明一個map < K, V > 的物件
(或者等價的multimap),保存在map中的元素類型是pair < const K, V > 。
如果要用vector模擬map或者multimap,你必須去掉const,因為當你對vector排序時,
它的元素的值將會通過賦值移動,那意味著pair的兩個元件都必須是可賦值的。
當使用vector來模擬map < K, V > 時,保存在vector中資料的類型將是pair < K, V > ,
而不是pair < const K, V > 。

map和multimap以順序的方式保存他們的元素,但用於排序目的時它們只作用於元素的key部分
(pair的第一個元件),所以當排序vector時你必須做一樣的事情。你需要為你的pair寫一個
自定義比較函數,因為pair的operator < 作用於pair的兩個組件。

有趣的是,你會需要第二個比較函數來進行查找。用來排序的比較函數將作用於兩個pair物件,
但是查找只用到key值。必須傳給用於查找的比較函數一個key類型的物件(要查找的值)和一個pair
(存儲在vector中的一個pair)——兩個不同的類型。還有一個附加的麻煩,你不會知道key還是pair
是作為第一個實參傳遞的,所以你真的需要兩個用於查找的比較函數:一個key值先傳遞,一個pair先傳遞。

這個例子演示了怎麼把這些東西合在一起:

typedef pair < string, int > Data; // 在這個例子裏
// "map "容納的類型
class DataCompare { // 用於比較的類
public:
bool operator()(const Data& lhs, // 用於排序的比較函數
const Data& rhs) const
{
return keyLess(lhs.first, rhs.first); // keyLess在下麵
}

bool operator()(const Data& Ihs, // 用於查找的比較函數
const Data::first_type& k) const // (形式1)
{
return keyLess(lhs.first, k);
}

bool operator()(const Data::first_type& k, // 用於查找的比較函數
const Data& rhs) const // (形式2)
{
return keyLessfk, rhs.first);
}

private:
bool keyLess(const Data::first_type& k1, // “真的”
const Data::first_type& k2) const // 比較函數
{
return k1 < k2;
}
};

在這個例子中,我們假設有序vector將模擬map < string, int > 。
這段代碼幾乎是上面討論的字面轉換,除了存在成員函數keyLess。
那個函數的存在是用來保證幾個不同的operator()函數之間的一致性。
每個這樣的函數只是簡單地比較兩個key的值,所以我們把這個測試放在keyLess中並讓operator()
函數返回keyLess所做的事情,這比複製那個邏輯要好。
這個軟體工程中絕妙的動作增強了DataCompare的可維護性,但有一個小缺點,
它提供了有不同參數類型的operator()函數,這將導致函數物件無法適配(看見條款40)。
噢,好了。

把有序vector用作map本質上和用作set一樣。唯一大的區別是必須把DataCompare物件用作比較函數:

vector < Data > vd; // 代替map < string, int >
... // 建立階段:很多插入,
// 幾乎沒有查找
sort(vd.begin(), vd.end(), DataCompare()); // 結束建立階段。(當
// 模擬multimap時,你
// 可能更喜歡用stable_sort
// 來代替;參見條款31。)
string s; // 用於查找的值的對象
... // 開始查找階段
if (binary_search(vd.begin(), vd.end(), s,
DataCompare()))... // 通過binary_search查找
vector ::iterator i =
lower_bound(vd.begin(), vd.end(), s,
DataCompare()); // 在次通過lower_bound查找,
if (i != vd.end() && !DataCompare()(s, *i))... // 條款45解釋了
// “!DataCompare()(s, *i)”測試
pair < vector < Data > ::iterator,
vector < Data > ::iterator > range =
equal_range(vd.begin(), vd.end(), s,
DataCompare()); // 通過equal_range查找
if (range.first != range.second)...
... // 結束查找階段,開始
// 重組階段
sort(vd.begin(), vd.end(), DataCompare()); // 開始新的查找階段...

正如你所見,一旦你寫了DataCompare,東西都很好的依序排列了。而一旦位置合適了,
只要你的程式按照101頁描述的階段方式使用資料結構,它們往往比相應的使用真的map的設計
運行得更快而且使用更少記憶體。如果你的程式不是按照階段的方式操作資料結構,
那麼使用有序vector代替標準關聯容器幾乎可以確定是在浪費時間。

2010年11月11日 星期四

free -- cached and buffers(2)

一般程式在執行,與進入CPU大致上會有幾個資料搬移的作業

Disk(code) <--> RAM <--> L2 Cache <--> L1 Cache(inside CPU)

當程式要執行時會愈往右邊走,執行完畢時,會慢慢走回左邊,如果都用不到,始終回到只剩DISK

以上的Cache跟主題要講的Cached有些類似,但不是指同一件事

一支程式要執行時,會有需要將使用的資料從File(Disk)讀起來使用的時候

讀起來就會進入RAM,但結束時理當要釋放這個RAM給其他程式使用

Linux考量到其他的程式可能也會用到,所以會先Cache住,如果有要用到,可以馬上反應使用

這是指在DRAM充裕的狀況下,如此運作對效能有幫助

但如果因為導致實體記憶體被吃光,而使用到Swap空間時,就輪到CPU倒楣

使用上應特別注意

其中的 Cached Memory 會依據系統的使用狀況做動態調整,借此以提高系統效能. /proc/sys/vm/drop_caches 的預設值為 0,也就是啟動 cache 的功能.如果你不喜歡這些功能或者覺得它不夠Smart的話,可以把他取消掉.在 Kernel 2.6.16 之後的本版可以透過 /proc/sys/vm/drop_caches 來釋放 Cached Memory

釋放 pagecache 所使用的 Cached Memory.



[root@localhost]# echo 1 > /proc/sys/vm/drop_caches

釋放 dentries,inodes 所使用的 Cached Memory.





[root@localhost]# echo 2 > /proc/sys/vm/drop_caches

釋放 pagecache,dentry,inode 所使用的 Cached Memory.





[root@localhost]# echo 3 > /proc/sys/vm/drop_caches




free


total used free shared buffers cached

Mem: 1023916 975816 48100 0 26376 465844

-/+ buffers/cache: 483596 540320

Swap: 2096440 105564 1990876


計算方式


total used free shared buffers cached

Mem: a b c d e f

-/+ buffers/cache: g h

Swap: i j ka = 總記憶體大小

b = 配給 buffers cache 的記憶體大小(包含未用的 buffers cache)

c = 剩下的記憶體大小

e = 配給 buffers 但未用的記憶體大小

f = 配給 cache 但未用的記憶體大小

g = buffers cache 被使用掉的記憶體大小,也就是實際被應用程式用走的

h = 那這個就是實際剩下的記憶體大小


a = b + c

a = g + h

g = b - e - f

h = c + e + f


buffer cache 的區別:

A buffer is something that has yet to be "written" to disk.

A cache is something that has been "read" from the disk and stored for later use.




一般情況下,Linux kernel 會盡可能多地利用 RAM 的空閑空間作為 cache/buffer 以最大幅度地提高系統性能。當系統中運行的應用程序占用的 RAM 增加時,則將 cache/buffer 所占用的空間釋放出來,讓渡給應用程序使用。


Mem: 那一行顯示了實際記憶體的使用率;

Swap: 顯示的是系統 swap 空間的使用率;

-/+ buffers/cache: 則是目前撥給系統緩衝區的實體記憶體數量。



記憶體管理的概觀

當系統開機一段時間後,像是「top」這種傳統的 Unix 工具常常回報少的可憐的可用記憶體數值,在我寫這篇文章的系統中,就算我總共有 512 MB 的記憶體在我的系統裡,但約開機m後三個小時,我只剩下 60 MB 的可用記憶體,那些記憶體到底跑到那裡去了?


用掉最多記憶體的地方是磁碟快取 (disk cache),目前它總共用了超過 290 MB 的記憶 ( top 裡的「cached」項目中),快取記憶體 (cached memory) 基本上是空閒的,當有新/執行中的程式需要記憶體的話,它會快速的被取回來。


為什麼 Linux 使用這麼多的記憶體來當作磁碟快取 (disk cache) 呢?主要的原因便是:假如 RAM 沒有被使用的話,它便是閒放在那邊浪費著不用。如果把資料放在用 RAM 組成的磁碟上,它的存取速度比直接從硬碟上存取還要快上 1000 倍。假如在快取裡找不到該資料,當然還是得直接從磁碟裡存取,但就如同上面說的,您將可以節省些微的存取時間。



Out of Memory

more /var/log/messages


kernel: Mem-info:

kernel: Zone:DMA freepages: 2916 min: 0 low: 0 high: 0

kernel: Zone:Normal freepages: 758 min: 766 low: 4031 high: 5791

kernel: Zone:HighMem freepages: 125 min: 253 low: 506 high: 759

kernel: Free pages: 3799 ( 125 HighMem)

kernel: ( Active: 237940/1195, inactive_laundry: 1, inactive_clean: 0, free: 3799 )

kernel: aa:0 ac:0 id:0 il:0 ic:0 fr:2916

kernel: aa:209592 ac:2087 id:1190 il:1 ic:0 fr:758

kernel: aa:26033 ac:232 id:0 il:0 ic:0 fr:125

kernel: 0*4kB 2*8kB 4*16kB 2*32kB 4*64kB 2*128kB 1*256kB 1*512kB 0*1024kB 1*2048kB 2*4096kB = 11664kB)

kernel: 8*4kB 1*8kB 175*16kB 6*32kB 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 3032kB)

kernel: 1*4kB 0*8kB 1*16kB 1*32kB 1*64kB 1*128kB 1*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 500kB)

kernel: Swap cache: add 5156731, delete 5156620, find 19439534/21006374, race 0+19

kernel: 4115 pages of slabcache

kernel: 1566 pages of kernel stacks

kernel: 13 lowmem pagetables, 5378 highmem pagetables

kernel: 32 bounce buffer pages, 32 are on the emergency list

kernel: Free swap: 0kB

kernel: 261760 pages of RAM

kernel: 32384 pages of HIGHMEM

kernel: 5781 reserved pages

kernel: 14591 pages shared

kernel: 116 pages swap cached

kernel: Out of Memory: Killed process 25580 (java).

free -- cached and buffers(1)

以下參考自:http://egloo.wordpress.com/2008/10/29/linux-cached-memory/
In Linux, reading from a disk is very slow compared to accessing real memory. In addition, it is common to read the same part of a disk several times during relatively short periods of time. For example, one might first read an e-mail message, then read the letter into an editor when replying to it, then make the mail program read it again when copying it to a folder. Or, consider how often the command ls might be run on a system with many users. By reading the information from disk only once and then keeping it in memory until no longer needed, one can speed up all but the first read. This is called disk buffering, and the memory used for the purpose is called the buffer cache.

Unlike (Windows) other operating systems, Linux administers memory the smartest way it can.

Since unused memory is next to worthless, the filesystem takes whatever memory is left and caches it in order to speed up disk access. When the cache fills up, the data that has been unused for the longest time is discarded and the memory thus freed is used for the new data.

Whenever an application needs memory, the kernel makes the cache smaller; You do not need to do anything to make use of the cache, it happens completely automatically.

Freeing memory buffer does not make your programs faster… Actually it makes disk access slower.

BUT if for some reason (kernel debugging for example) you want to force the buffer to be freed, you need to set the drop_caches value to 1:

$ echo 1 > /proc/sys/vm/drop_caches
Issuing this command will release all the cached memory and also will stop collecting I/O buffer blocks. Let’s see an example of the effect:




Under normal situations, most of the memory is already cached by the system. But if we force the system to free the memory, you can see in the graph how the memory is suddenly dropped.

The technical details of how this works are explained on the Linux API

2010年11月9日 星期二

Solaris process crashed debug 範例


Solaris process crashed debug 範例

DEV901 /export/spare/cts>coreadm -e process
coreadm�G�z������ root �~������ -[giedu] �ﶵ 必須用root
DEV901 /export/spare/cts>su -
Password:
#Sun Microsystems Inc. SunOS 5.8 Generic Patch December 2002
DEV901 />coreadm -e process
DEV901 />exit

DEV901 /export/spare/cts>vi crashed.c
"crashed.c" 10 ��, 139 �Ӧr��
#include
int main(int argc, char* argv[])
{
int *a=0;
printf("start...\n");
printf("%s",a); crashed 的地方

return 0;
}

~
~
"crashed.c" 10 ��, 148 �Ӧr��
-g參數確保pstack 可以查出問題所在
DEV901 /export/spare/cts>cc -o crashed crashed.c –g  
ELF的檔案類型
DEV901 /export/spare/cts>file crashed
crashed: ELF 32-�줸 MSB �i���� SPARC ���� 1, �ʺA�s��, �����h DEV901 /export/spare/cts>./crashed
start...
Segmentation Fault (core dumped)      產生core file了

DEV901 /export/spare/cts>coreadm
�����֤��ɮ׹ϼˡG/var/core/core.%f.%p
init �֤��ɮ׹ϼˡGcore.%f
�����֤߶ɦL�Gdisabled
�C�ӳB�z�֤߶ɦL�Genabled       確認會產生core file
���� setid �֤߶ɦL�Gdisabled
�C�ӳB�z setid �֤߶ɦL�Gdisabled
�����֤߶ɦL�O���Gdisabled
DEV901 /export/spare/cts>cat /etc/coreadm.conf
#
# coreadm.conf
#
# Parameters for system core file configuration.
# Do NOT edit this file by hand -- use coreadm(1) instead.
#
COREADM_GLOB_PATTERN=/var/core/core.%f.%p
COREADM_INIT_PATTERN=core.%f 產生core file檔名
COREADM_GLOB_ENABLED=no
COREADM_PROC_ENABLED=yes 確認會產生core file
COREADM_GLOB_SETID_ENABLED=no
COREADM_PROC_SETID_ENABLED=no
COREADM_GLOB_LOG_ENABLED=no


DEV901 /export/spare/cts>ls -l core.crashed
-rw------- 1 cts staff 80360 11�� 9 11:16 core.crashed
DEV901 /export/spare/cts>pstack core.crashed
core 'core.crashed' of 23061: ./crashed
這個位置發生core dump
ff2b3218 strlen (0, ffbefad0, 0, ff33f789, 0, 10702) + 80
ff308188 printf (10700, ff340284, ff343a54, 0, 22318, ff29bc20) + f4
000106a8 main (1, ffbefb54, ffbefb5c, 20800, 0, 0) + 30
00010650 _start (0, 0, 0, 0, 0, 0) + 108
DEV901 /export/spare/cts>pmap core.crashed
core 'core.crashed' of 23061: ./crashed
00010000 8K read/exec /export/spare/cts/crashed
00020000 8K read/write/exec /export/spare/cts/crashed
相對於symbol table的位置,應該在FF280000之後
FF280000 688K read/exec /usr/lib/libc.so.1
FF33C000 32K read/write/exec /usr/lib/libc.so.1
FF380000 8K read/write/exec /usr/lib/libdl.so.1
FF390000 8K read/exec /usr/platform/sun4u-us3/lib/libc_psr.so.1
FF3A0000 176K read/exec /usr/lib/ld.so.1
FF3DC000 8K read/write/exec /usr/lib/ld.so.1
FF3DE000 8K read/write/exec /usr/lib/ld.so.1
FFBEE000 8K read/write/exec [ stack ]
total 952K

DEV901 /export/spare/cts>elfdump -s /usr/lib/libc.so.1 | grep strlen
[1965] 0x00033198 0x000000f0 FUNC GLOB D 30 .text strlen
[723] 0x00000000 0x00000000 FILE LOCL D 0 ABS strlen.s
[2129] 0x0007c6b4 0x0000002c FUNC LOCL D 0 .text mini_strlen
[4677] 0x00033198 0x000000f0 FUNC GLOB D 0 .text strlen
0xFF280000 + 0x00033198 + 80 = 0xFF2b3218
從上面可以看到,strlen crashed的位置是如何被找出來的。從pstack可以得到0xFF2b3218,透過pmap找出symbol table中,crashed的base address應該落於0xFF280000(屬於libc.so.1),因為libc.so.1以及./crashed都是ELF檔案,所以用elfdump找出其中的symbol位置,最後發現在0x0033198。而因為pstack有再記載crashed address是位在其base address所在symbol再+0x80之偏移量,所以算出這樣結果。(也就是global strlen()是發生問題所在,但並不表示他有BUG)

Linux process crashed debug 範例

Linux process crashed debug 範例
[root@HTS099 ~]# cat crashed.c
#include
int main(int argc, char* argv[])
{
int *a=0;
printf("start...\n");
*a= 1;

return 0;
}

[root@HTS099 ~]# gcc -o crashed crashed.c -g
[root@HTS099 ~]# ./crashed
start...
Segmentation fault

[root@HTS099 ~]# ulimit -c
0
[root@HTS099 ~]# ulimit -c unlimited
[root@HTS099 ~]# ulimit -c
unlimited
[root@HTS099 ~]# ./crashed
start...
Segmentation fault (core dumped)

[root@HTS099 ~]# ls -l core.*
-rw------- 1 root root 143360 Nov 9 10:06 core.31393

[root@HTS099 ~]# gdb ./crashed core.31393
GNU gdb Fedora (6.8-37.el5)
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...

warning: Can't read pathname for load map: Input/output error.
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
Core was generated by `./crashed'.
Program terminated with signal 11, Segmentation fault.
[New process 31393]
#0 0x080483ab in main () at crashed.c:6
6 *a= 1;
(gdb) bt
#0 0x080483ab in main () at crashed.c:6
(gdb) list *0x080483ab
0x80483ab is in main (crashed.c:6).
1 #include
2 int main(int argc, char* argv[])
3 {
4 int *a=0;
5 printf("start...\n");
6 *a= 1;
7
8 return 0;
9 }

Core & Dump @ Solaris (2)


pstack, coreadm and symbol tables
Where symbol names come from?
In ELF files, symbols reside in two sections: .symtab and .dynsym.

On recent versions of Solaris, there is a new section, .SUNW_ldynsym, but for the purpose of this article it is identical to .dynsym, so I'll keep it simple and not talk about it.

Both sections are essentially tables that map name to a value; here we are interested in function names, so that value would be function address. When pstack unwinds the stack (starting from value of $pc and $fp/$sp registers that comes from special NOTE segment of core file), it goes through symbol tables of all files involved and find symbol with closest value.

For example, suppose we have this core file:

$ pstack core
core 'core' of 7719: ./a.out
fece586c strlen (8050ada, 8047a38, fed91c20, 0) + c
fed40814 printf (8050ad8, 0) + a8
08050969 ???????? (0, 8047b30, 8047a84, 80508bd, 1, 8047a90)
080509a2 main (1, 8047a90, 8047a98, fed93e40) + 12
080508bd _start (1, 8047b98, 0, 8047ba0, 8047bdc, 8047be7) + 7d
fece586c address belongs to libc.so.1 as can be seen from pmap(1) output:

$ pmap core
core 'core' of 7719: ./a.out
08046000 8K rwx-- [ stack ]
08050000 4K r-x--
08060000 4K rwx--
08061000 128K rwx-- [ heap ]
>>>FECC0000 760K r-x-- /lib/libc.so.1 <<<
FED8E000 32K rw--- /lib/libc.so.1
FED96000 8K rw--- /lib/libc.so.1
...
It is in code segment (r-x-- permissions gave that away) of /lib/libc.so.1.

Looking at libc.so.1 with elfdump we can see that global function strlen starts at offset 0x25860

$ elfdump -s /usr/lib/libc.so.1 | grep strlen
[2603] 0x00025860 0x00000045 FUNC GLOB D 37 .text strlen
So in our passed away process it would reside at 0xFECC0000 (base address of libc.so.1 in memory) + 0x25860 = 0xFECE5860. Hence 0xfece586c is 0xFECE5860+0xc, which is strlen+0xc

Symbol tables
As you can see in the above example, not all symbols were found. In this case, address 0x08050969 was not mapped to any symbol. That address belongs to a.out code segment starting at 0x08050000 and that's all we can tell. Yet the other symbol from the same segment is visible: main at 0x080509a2.

The difference is because those two symbols were present in different symbol tables while executable files are permitted to have only one: .dynsym (strictly speaking, that probably applies to dynamic executables only, but since Solaris 10 strongly discourages static linking, so we almost always have to deal with dynamic executables and shared libraries). This .dynsym section is used by run-time linker (ld.so.1(1)) and contains global names that program "exports" or "imports" from libraries; call to "main" is resolved at run time by looking up name "main" in .dynsym section and jumping to address associated with symbol found. Since this information is absolutely necessary at run time, .dynsym section always resides in a loadable segment and is always a part of process memory image (and thus a core file).

On the other hand, .symtab section that contains all symbols - including local ones - was useful mostly when linking relocatable object files (*.o). References inside one file can be resolved at compile time using offsets, so static functions does not have to have a name at run time, they are called directly using offset from current position. This is why .symtab section does not belong to a loadable segment and does not contribute to process' memory image in any way. And this is why it [used to be] customary to remove symbol table from final executables (using strip(1), for example) to save space and make life of support engineers harder.

In our case, ./a.out was indeed stripped:

$ elfdump -c a.out | grep symtab
$ elfdump -c a.out | grep dynsym
Section Header[4]: sh_name: .dynsym
It does have .dynsym, but no .symtab. By the way, main symbol indeed is present in .dynsym and has address 0x08050990:

$ elfdump -s -N .dynsym a.out | grep main
[28] 0x08050990 0x0000001a FUNC GLOB D 0 .text main
Loadable objects (executables and shared libraries)
Let's recompile a.out and see how it helps:

$ CC510 a.cc
$ ./a.out
Segmentation Fault (core dumped)
$ pstack core
core 'core' of 11761: ./a.out
fece586c strlen (8050ada, 8047a38, fed91c20, 0) + c
fed40814 printf (8050ad8, 0) + a8
08050969 __1cDfoo6F_i_ (0, 8047b30, 8047a84, 80508bd, 1, 8047a90) + 19
080509a2 main (1, 8047a90, 8047a98, fed93e40) + 12
080508bd _start (1, 8047b98, 0, 8047ba0, 8047bdc, 8047be7) + 7d
We now can see name __1cDfoo6F_i_ (mangled name of int foo()) instead of ???, but where would pstack get this information? __1cDfoo6F_i_ is not present in .dynsym, so it there was not information about this name in memory image of the process when it died:

$ strings core | grep __1cDfoo6F_i_
pstack(1) is smarter that that: it finds out which program generated this core file, locates it and uses its .symtab (if present, of course) to map symbols. Here's an excerpt from proc(1):

Some of the proc tools can need to derive the name of the
executable corresponding to the process which dumped core or
the names of shared libraries associated with the process.
These files are needed, for example, to provide symbol table
information for pstack(1). If the proc tool in question is
unable to locate the needed executable or shared library,
some symbol information is unavailable for display.
Let's delete a.out and see what happens:

$ rm a.out
$ pstack core
core 'core' of 11761: ./a.out
fece586c strlen (8050ada, 8047a38, fed91c20, 0) + c
fed40814 printf (8050ad8, 0) + a8
08050969 ???????? (0, 8047b30, 8047a84, 80508bd, 1, 8047a90)
080509a2 main (1, 8047a90, 8047a98, fed93e40) + 12
080508bd _start (1, 8047b98, 0, 8047ba0, 8047bdc, 8047be7) + 7d
We immediately got our ???'s back.

So pstack uses core file and executable/libraries as well in order to print readable names in stack trace.

Core file contents
If you have to send your core file to another person for inspection, you have him at a disadvantage: that person might not have your executable and even system libraries might be slightly different. If pstack would go look for address-to-symbol mapping there, it might end up printing wrong symbol names and question marks, making core file more harmful than helpful.

There is a way to embed symbol tables into the core file - using coreadm(1M) command. It allows to specify what kind of content you want the system to put into core file and it can even direct the system to pull .symtab from executable and shared libraries:

$ coreadm -I default+symtab(do this under root).
More information on coreadm can be found in its man page: coreadm(1M).

Side note: in fact, symbol tables of libc.so.1 and ld.so.1 were present in my core file even without "symtab" content requested as can be seen by elfdump -c core; seems to be an undocumented, but useful feature.

Let's turn .symtab inclusion on and see how if it helps:

$ su -
# coreadm -I default+symtab
# exit
$ ./a.out
Segmentation Fault (core dumped)
$ rm a.out
$ pstack core
core 'core' of 13604: ./a.out
fece586c strlen (8050ada, 8047a38, fed91c20, 0) + c
fed40814 printf (8050ad8, 0) + a8
08050969 __1cDfoo6F_i_ (0, 8047b30, 8047a84, 80508bd, 1, 8047a90) + 19
080509a2 main (1, 8047a90, 8047a98, fed93e40) + 12
080508bd _start (1, 8047b98, 0, 8047ba0, 8047bdc, 8047be7) + 7d
Core file now contains many symbol tables, one per loadobject:

$ elfdump -c core | grep symtab
Section Header[1]: sh_name: .symtab
Section Header[3]: sh_name: .symtab
Section Header[6]: sh_name: .symtab
Section Header[8]: sh_name: .symtab
Section Header[10]: sh_name: .symtab
Section Header[12]: sh_name: .symtab
and one of them has definition of our int foo() function that starts at 0x08050950:

$ elfdump -s core | grep foo
[56] 0x08050950 0x00000034 FUNC LOCL D 0 __1cDfoo6F_i_
How to prevent ??? to appear in stack trace?
Use pstack on the same machine
First and foremost, you can avoid many problems by first using pstack on the same machine where core file was generated. This will ensure that pstack uses the same binary and libraries as the process that generated core. Otherwise, you might end up looking at wrong symbols or (in the best case) a lot of question marks.

Don't strip binaries
In Solaris, it is no longer customary to strip binaries (see http://blogs.sun.com/ali/entry/which_solaris_files_are_stripped). Space savings are questionable and performance of unstripped binary does not suffer, so why having lives of those who will debug it difficult?

Don't delete binaries
By default, Solaris does not include .symtab into core files (except for libc.so and ld.so as I mentioned earlier, but that is not relevant here when we talk about user executables and libraries). So if you delete or move executable/library after core file was generated, pstack won't be able to find its .symtab and thus map addresses to local function names.

In other words, unless you've changed core file contents with coreadm(1M), don't delete your binaries before you have a chance to inspect core file. They are needed.

Use coreadm
Most of problems above can be eliminated with one blow:

# coreadm -I default+symtabThis tells the system to pull .symtab sections from every binary involved in the process and put them into core file. You no longer need binaries to see names instead of numbers in stack trace.



Core & Dump @ Solaris


managing crash dumps and core files
当操作系统崩溃的时候,savecore命令在启动的时候自动执行,并将内核信息存放在/var/crash/nodename/vmcore.X文件里面,将名字列表存放在/var/crash/nodename/unix.X文件里面.
在crash dump目录下,还创建了一个bounds的文件
# dumpadm
# cat /etc/dumpadm.conf
注意尽量使用dumpadm命令而避免直接编辑/etc/dumpadm.conf文件
dumpadm的一般语法格式是:
/usr/sbin/dumpadm [nuy] [-c content-type] [-d dump-device] [-m mink| minm| min%]
[-r root-dir] [-s savecore-dir]
其中-n是禁止重启之后自动运行savecore命令,-u是执行更新,-y是允许重启之后自动运行savecore命令.content-type包括三种类型:kernel,all,curproc.-r是指定根目录,如果没有这个参数那么默认是"/"目录.
当一个core文件发生的时候,要创建两个core文件的副本,分别是global core file,per-process core file,global core file只有root用户可以操作.后一个文件只有所有者可以操作.
# coreadm
# cat /etc/coreadm.conf
带-p参数的coreadm命令任何用户都可以使用,而带其他参数的coreadm命令则只有root用户可以使用.
coreadm -i pattern命令和coreadm -p pattern命令大同小异,区别在于前者在系统重启之后才生效.coreadm -i pattern命令的作用是设定per-process core文件名模式
coreadm -e包含四项:global,process,global-setid,proc-setid,log
coreadm -d:让设定的选项失效
coreadm -u:更新
coreadm -g pattern:设定global core文件名模式

使用coreadm命令p选项的一些参数:
%u:EUID;%g:EGID;%f:可执行文件名;%n:系统标示名;%m:机器硬件名;%t:自1970.1开始运行的秒数
$$ shell's pid
使用coreadm命令的一些实例:
# coreadm -p core.%f.%p $$
# coreadm -p $HOME/corefiles/%n.%f.%p $$
# coreadm -g /var/core/core.%f.%P -e global
# coreadm 278 5678


1 Core
core檔是系統軟體出現問題後產生的資訊記錄。它對軟體發展者和系統管理者的工作有很大的幫助作用。本節主要對Core檔產生和管理做一些初步介紹。

(1) 管理core文件概述
core檔在進程或者應用程式異常終止時產生。我們可以使用coreadm命令來管理core檔。比如,你可以使用coreadm命令來設定所有的core檔都放在一個目錄中。這樣,就會很容易通過測試找到問題的痕跡。

有兩種類型的core檔:

單個進程的core檔,在默認情況下是啟動的。當進程異常終止時,單個進程的core檔就在異常終止進程的目錄中產生。產生後,單個進程的core檔的擁有者就是進程的擁有者。只有擁有者才能查看這個檔。
全局core檔,它默認的情況下是不開啟的。如果啟動了全局core檔,它產生在引起全局core檔產生的目錄。全局core文件的擁有者就是超級用戶。非特權用戶不能查看全局core檔。
當進程異常終止時,默認在當前目錄產生core檔。如果這時全局core檔路徑也開啟著,每個異常終止的進程就會有兩個檔產生:一個在當前的工作目錄;另一個在全局core檔目錄。
默認時,setuid進程既不產生全局core檔也不產生單個core檔。
如果全局core檔是開啟的,core檔可以用表17-3中的變數所描述。

表17-3 描述Core檔的變數

變 量 名 變數描述
%d 執行的檔目錄名
%f 執行的檔案名
%g 組的ID
%m 機器名稱
%n 系統節點名
%p 進程ID
%t 十進位的時間
%u 有效的用戶ID
%z 進程運行的分區(xone)名
%% 百分比


舉例說明,全局core檔路徑設置為:

/var/core/core.%f.%p

這時,如果sendmail的PID為12345的進程發生異常終止,將產生下列core檔:

/var/core/core.sendmail.12345

我們可以使用coreadm命令設定進程產生的core檔的目錄和名稱。這將取代原來的默認設置。

# coreadm -i /var/core/core.%f.%p

全局core的屬性值存儲在/etc/coreadm.conf文件中。

(2) 管理core檔的實例

1.顯示當前core檔的設置
例17-2 使用不帶任何參數的coreadm命令顯示當前core的設置情況。

$ coreadm
global core file pattern:
global core file content: default
nit core file pattern: core
init core file content: default
global core dumps: disabled
per-process core dumps: enabled
global setid core dumps: disabled
per-process setid core dumps: disabled
global core dump logging: disabled

2.設置core檔案名的樣式
將當前Shell運行的所有進程所產生的core檔命名:

$ coreadm -p $HOME/corefiles/%f.%p $$
對全局檔設置core檔命名需要超級用戶許可權:
# coreadm -g /var/corefiles/%f.%p

3.啟用單個進程core檔的路徑
# coreadm -e process
$ coreadm $$
1180: /home/kryten/corefiles/%f.%p

4.啟用全局core檔的路徑
# coreadm -e global -g /var/core/core.%f.%p

(3) 查詢core檔資訊
一些proc工具可以像檢測活動的進程一樣檢測core檔。比如,/usr/proc/bin/pstack、pmap、pldd、pflags和pcred工具能管理core文件。更詳細的資訊請查看porc(1)的幫助。

例17-3 使用proc工具檢查core檔。
$ ./a.out
Segmentation Fault(coredump)
$ /usr/proc/bin/pstack ./core
core ’./core’ of 19305: ./a.out
000108c4 main (1, ffbef5cc, ffbef5d4, 20800, 0, 0) + 1c
00010880 _start (0, 0, 0, 0, 0, 0) + b8 

2 系統crash資訊的管理

crash主要回饋主機能否正常運行等比較嚴重的問題。系統管理員需要特別關注crash資訊。
(1) 系統崩潰概述
系統崩潰(crash)發生在硬體故障、I/O問題或軟體錯誤的情況下。如果系統崩潰發生了,它將在控制臺上顯示錯誤資訊,並將實體記憶體的拷貝寫入轉儲設備。這時,系統將自動重新啟動。當系統重啟後,savecore 命令運行將資料從轉儲設備中找回,並存儲到savecore目錄。這些資料為系統診斷提供了依據。

系統崩潰轉儲檔
當savecore命令自動運行將崩潰資訊從轉儲設備中找回,並寫成兩個檔:unix.X和vmcore.X。其中X為轉儲的次序號碼。這些檔一起用於表現系統的崩潰轉儲資訊。
崩潰轉儲檔存儲在預先設定好的目錄中,默認情況下是/var/crash/hostname。在以前的Solaris版本中,崩潰轉儲檔將在系統重新啟動的時候不寫在特定的目錄,除非你手動啟動,將記憶體的映射存儲到崩潰轉儲檔中。不過現在就自動存儲崩潰轉儲檔了。

dumpadm命令
我們可以用dumpadm命令來在Solaris系統中管理系統崩潰轉儲資訊。
dumpadm命令能使你在作業系統上設置崩潰轉儲。這個命令的設置參數包括轉儲的內容、轉儲的設備和崩潰轉儲資訊的存儲路徑。
轉儲資料是以壓縮的形式被存在轉儲設備中的。內核的崩潰轉儲映射可能達到4GB,壓縮資料就意味著更快的轉儲速度和更小的轉儲設備磁碟空間。
保存崩潰轉儲檔是在後臺運行的崩潰轉儲檔的任務。系統啟動的時候不需要等待savecore命令完成就可以進行下一步。當然,大的記憶體數量是有利於savecore完成任務的。
系統崩潰轉儲檔是由savecore命令產生的,保存一般也是按默認路徑進行的。
savecore –L命粗體令是新的屬性,它使你能在系統運行的時候崩潰轉儲。當系統記憶體存儲有問題的時候,這個命令試圖在系統運行的時候調試記憶體的快照。如果系統是啟動的,並且有些命令還能執行,你可以運行cavecore –L命令來存儲系統轉儲設備的快照到崩潰轉儲目錄。

通過dumpadm命令,轉儲設置參數存儲在/etc/dumpadm.conf文件中。注意不要手動編輯這個檔,這樣做可能會帶來不一致的轉儲設置。

dumpadm命令如何工作
當系統啟動的時候,dumpadm命令調用svc:/system/dumpadm:default服務來設置基於/etc/dumpadm.conf文件的的崩潰轉儲參數。

dumpadm命令通過/dev/dump介面來初始化轉儲設備和轉儲內容。

(2) 管理系統崩潰轉儲資訊

在管理系統崩潰資訊中,你必須要記住以下幾點:
你必須是超級用戶或具有管理系統崩潰功能的用戶。
不要關閉保存崩潰轉儲資訊的屬性。系統崩潰轉儲檔提供了導致系統崩潰的很珍貴的資訊。
不要輕易刪除系統崩潰資訊。

1.如何顯示當前的崩潰轉儲設置
# dumpadm
Dump content: kernel pages
Dump device: /dev/dsk/c0t3d0s1 (swap)
Savecore directory: /var/crash/venus
Savecore enabled: yes

上面輸出的意義如下:
轉儲內容是內核記憶體的換頁。
內核記憶體將轉儲到swap設備中,就是/dev/dsk/c0t3d0s1。
系統崩潰轉儲檔存在/var/crash/venus目錄。
系統的崩潰轉儲功能是啟動著的。

2.如何修改當前的崩潰轉儲設置
命令介紹

# dumpadm -c content -d dump-device -m nnnk | nnnm | nnn% -n -s savecore-dir

dumpadm命令的各個參數具體意義列在表17-4中。

表17-4 dumpadm命令的參數列表

轉儲參數
描 述

-c content
轉儲的資料類型。默認的轉儲內容是內核的記憶體。使用all關鍵字是指所有記憶體

-d dump-device
系統崩潰時,臨時存儲的專門設備

-m nnnk | nnnm | nnn%
在savecore目錄中為了存儲崩潰轉儲檔所留的專門空間。這個參數有可能是kb(nnnk),也有可能mb(nnnm),也有可能是百分比(nnn%)

-n 或-y
是否自動進行崩潰轉儲,y為是,n為否

-s savecore-dir
用來改變崩潰轉儲檔的路徑。默認路徑是/var/crash/hostname


 例17-4 轉儲內容改為所有記憶體,轉儲目錄改為/dev/dsk/c0t1d0s1,轉儲空間最大為這個檔系統的10%。

先查看原來的轉儲設置:

# dumpadm
Dump content: kernel pages
Dump device: /dev/dsk/c0t3d0s1 (swap)
Savecore directory: /var/crash/pluto
Savecore enabled: yes

更改轉儲設置:

# dumpadm -c all -d /dev/dsk/c0t1d0s1 -m 10%
Dump content: all pages
Dump device: /dev/dsk/c0t1d0s1 (dedicated)
Savecore directory: /var/crash/pluto (minfree = 77071KB)
Savecore enabled: yes

3.如何檢查崩潰轉儲檔內容
例17-5 使用mdb工具輸出崩潰轉儲檔內容,其中包括系統資訊和在/etc/system檔中可調用的一些參數。

# /usr/bin/mdb -k unix.0
Loading modules: [ unix krtld genunix ip nfs ipc ptm ]
> ::status
debugging crash dump /dev/mem (64-bit) from ozlo
operating system: 5.10 Generic (sun4u)
> ::system
set ufs_ninode=0x9c40 [0t40000]
set ncsize=0x4e20 [0t20000]
set pt_cnt=0x400 [0t1024] 

GDB


GDB
GNU debugger
常用參數
gdb [options] [executable-file [core-file or process-id]]
gdb [options] --args executable-file [inferior-arguments ...]

GNU manual
GDB online document
Lightweight Text UI
gdbtui -- gdb 自已提供的 curses mode 介面前端
cgdb -- 提供 vim like 的程式碼檢視功能
基本操作
執行環境

程式的參數 (Program's Arguments)
set args -- 設定程式的參數
show args -- 顯示 set args 所設定的程式參數


工作目錄 (Program's Working Directory)
cd -- 改變工作目錄,和在 shell 下使用 cd 相同
pwd -- 顯示工作目錄


環境變數 (Environment Variables)
show environment -- 顯示所有環境變數的內容
show environment varname -- 顯示所指定環境變數的內容
set environment varname [=value] -- 設定環境變數
unset environment varname -- 取消環境變數設定
path DIR -- 將 DIR 加到 PATH 中
path -- 顯示 PATH 的內容


SHELL
shell command --呼叫 shell 執行外部命令。e.g shell ls

程式執行
run (r) -- 開始執行程式
continue (c) -- 離開中斷點,繼續執行程式
next (n) -- 單步執行 (step over)
step (s) -- 進入函式 (step into)
until (u) -- 離開 while, for等迴圈。 執行到程式碼的行數比目前的大,如果目前是迴圈的最後一行,就會離開迴圈
finish -- 繼續執行程式直到函式返回
start --在 main 設置暫時中斷點,並開始執行程式
advance -- 執行程式直到指定的位置
run arglist -- 同 run,並指定程式參數
start arglist -- 同 start,並指定程式參數
kill (k) --終止程式執行
quit (q) --離開 GDB
觀看程式碼
list (l) --列出目前執行程式碼前後各五行的程式碼;或是接著前次 list 的程式碼,列出之後的程式碼
"list -" -- 上次列出程式碼的前十行,類似向上翻頁
list *ADDRESS -- 列出包含指定位址的程式碼,常與 bt 配合使用
(gdb) bt
#0 0x08048405 in memory_violation () at test.cpp:9
#1 0x08048427 in main () at test.cpp:15
(gdb) list *0x08048405

directory DIR -- 新增一個路徑到程式碼搜尋路徑
show directories --顯示目前的程式碼搜尋路徑
disassemble (disas) --反組譯目前執行的程式碼
disassemble start_addr end_addr --反組譯指定範圍的程式碼。e.g. disas 0x32c4 0x32e4
設定中斷點 (breakpoint)
break 簡寫指令 b
break (b) line_number -- 在指定的行數設定中斷點
break function -- 在指定的 function 設定中斷點。e.g. break main
break filename:line_num -- 在指定檔案的指定行數設定中斷點。e.g. break main.c:10
break [LOCATION] [if CONDITION] -- 條件式中斷點,當 CONDITION 滿足時才中斷。e.g. break main.c:10 if var > 10
info break -- 列出所有的中斷點及編號
delete number -- 刪除指定編號的中斷點
disable number -- 使指定編號的中斷點失效
enable number -- 取消 disable,使指定編號的中斷點生效
設定 watchpoint
watch varname -- 設定 watch point 監看變數,當變數被寫入時,中斷程式
rwatch varname -- 設定 watch point 監看變數,當變數被讀取時,中斷程式
awatch varname -- 設定 watch point 監看變數,當變數被讀取或寫入時,中斷程式
watch *(int *)0x12345678 -- 設定 watch point 監看記憶體位址,監看範圍由變數型別決定,當此記憶體位址被寫入時,中斷程式
info watch -- 列出所有的 watchpoint
觀察變數資料
print (p) varname -- 顯示變數內容
printf expression --使用 C 語言的格式化字串 (printf format string) 功能來顯示。e.g. printf "var=%d\n", var
display varname-- 遇到中斷點時,自動顯示變數的內容
undisplay display_num -- 取消指定編號的自動顯示
info display -- 列出所有 display 及編號
whatis varname -- 顯示變數型別
ptype varname --顯示 class, struct 的定義內容
info locals -- 顯示目前的區域變數
觀察記憶體
x/8xw ADDRESS -- 印出 8 個 word (4 bytes) 的記憶體內容
x/FMT ADDRESS -- 詳細的 FMT 說明,請參考 help x
dump memory FILE START END -- 將指定範圍內的記憶體內容 dump 到檔案
顯示函式呼叫堆疊 (Call Stack)
GDB 以函式為單位分成一個個的 frame,每一個 frame 各代表一個函式。
如 main() 是一個 frame,main() 裡面所呼叫的函式是另外一個 frame。
當呼叫函式時,會把目前的 frame 推到堆疊。這個堆疊就是 frame stack,也就是一般所認知的 call stack。

backtrace (bt) --顯示目前函式呼叫堆疊 (Call Stack) 內容
backtrace full -- 一併列出區域變數 (local variable)
where --顯示目前程式的執行位置,與 backtrace 的作用相同
frame frame_num -- 跳到指定編號的 frame
up -- 往上一個 frame
down -- 往下一個 frame
info args -- 顯示傳給函式的呼叫參數
Multi-thread
info threads -- 顯示目前所有的 thread
thread thread_num -- 切換 GDB 到指定的 thread_num
改變程式行為
return -- 直接從函式目前執行位置返回,放棄未執行的部份
return expression -- 執行 return, 並傳回 expression 的值
set varname=xxx -- 更改變數值
顯示程式相關資訊
info sharedlibrary -- 顯示被載入的共享函式庫 (shared object library),及載入的記憶體位置
info registers -- 顯示基本暫存器的內容
info all-registers -- 顯示所有暫存器的內容
print $eax -- 顯示 eax 暫存器的內容
利用 core file 來幫助除錯
當程式產生 segmentation fault 時,系統會將當時的所有狀態,包括變數值,記憶體資料以及程式中各個函式的呼叫狀態 dump 成一個 core file。我們可以用 GDB 來讀取 core file,分析當時引發 segmentation fault 的原因。

下面的程式嘗試寫入記憶體位址為 0 的區域,引發系統產生 segmentation fault

#include < stdio.h >

//This function will cause "Segmentation fault"
void memory_violation()
{
char* ptr = 0;
for(int i=0; i < 10; ++i)
{
ptr[i] = i;
}
}

int main(int argc, char* argv[])
{
memory_violation();
return 0;
}

編譯指令
$ g++ -g test.cpp -o mytest

設定 core file 最大 size
core file size 預設為 0,這裡改成沒有限制
$ ulimit -c unlimited

執行程式
$ ./mytest
Segmentation fault (core dumped)

利用 GDB 讀取 core file
利用 bt 找出發生錯誤的地方
利用 list *ADDRESS 列出產生錯誤的程式碼
利用 print 觀察變數值
$ gdb ./mytest core
...
(gdb) bt
#0 0x08048405 in memory_violation () at test.cpp:9
#1 0x08048427 in main () at test.cpp:15
(gdb) list *0x08048405
0x8048405 is in memory_violation() (test.cpp:9).
4 void memory_violation()
5 {
6 char* ptr = 0;
7 for(int i=0; i<10; ++i)
8 {
9 ptr[i] = i;
10 }
11 }
12
13 int main(int argc, char* argv[])
(gdb) print ptr
$1 = 0x0



2010年10月14日 星期四

mysql 安裝與ajax with php測試

[root@localhost ajax-poll]# yum install mysql mysql-server -y

[root@localhost ajax-poll]# service mysqld start
[root@localhost ajax-poll]# chkconfig mysqld on
[root@localhost ajax-poll]# mysqladmin -u root password 'rootpass'
[root@localhost ajax-poll]# mysql -u root -p

Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 5.0.77 Source distribution

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql> create database syspage;
mysql> show databases;
+--------------------+
Database
+--------------------+
information_schema
mysql
syspage
test
+--------------------+
4 rows in set (0.00 sec)

mysql> GRANT ALL PRIVILEGES ON syspage.* to sean@local IDENTIFIED BY 'syspass';
mysql> GRANT ALL PRIVILEGES ON syspage.* to sean@localhost IDENTIFIED BY 'syspass';
mysql> GRANT ALL PRIVILEGES ON syspage.* to sean@172.16.43.98 IDENTIFIED BY 'syspass';
mysql> GRANT ALL PRIVILEGES ON syspage.* to sean@172.16.43.99 IDENTIFIED BY 'syspass';
mysql> GRANT ALL PRIVILEGES ON syspage.* to sean@172.16.43.144 IDENTIFIED BY 'syspass';
mysql> SHOW GRANTS FOR 'sean'@'localhost';
+------------------------------------------------------------------------------------+
Grants for sean@localhost
+------------------------------------------------------------------------------------+
GRANT USAGE ON *.* TO 'sean'@'localhost' IDENTIFIED BY PASSWORD '02be59854f8541f8'
GRANT ALL PRIVILEGES ON `syspage`.* TO 'sean'@'localhost'
+------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)

[root@localhost ajax-poll]# cd ajax-poll
[root@localhost ajax-poll]# mysql -u root --password='rootpass' syspage < polls.sql
mysql> use syspage ;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+-------------------+
Tables_in_syspage
+-------------------+
options
questions
votes
+-------------------+
3 rows in set (0.00 sec)


[root@localhost ajax-poll]# yum install php php-devel php-mysql -y
[root@localhost html]# cp -r ~/Desktop/ajax-poll /var/www/html/.

[root@localhost ajax-poll]# cd /var/www/html/ajax-poll/

[root@localhost ajax-poll]# vi poll.php

$conn=mysql_connect('localhost', 'root', 'sikhadmin') or die("Can't connect to mysql host");
mysql_select_db('polls') or die("Can't connect to DB");


$conn=mysql_connect('localhost', 'root', 'rootpass') or die("Can't connect to mysql host");
mysql_select_db('syspage') or die("Can't connect to DB");





apache與php tarball版安裝

PHP版本:5.2.6

1.安裝相關的相依性套件

# yum -y install mysqlclient14 mysqlclient14-devel freeradius-mysql

mysql-server mysql-devel pcre-devel libc-client-devel cyrus-imapd-devel

gd-devel openldap-devel freetype-devel

##備註:安裝過程有缺檔案快速查詢方式,到別台已經裝好的電腦上利用 locate 找出

該檔案絕對路徑和使用 rpm -qf 做反查套件。


2.把 php 解壓縮到 root 家目錄

# tar -jxvf php-5.2.6.tar.bz2 -C /root/

3.編譯前先啟動 mysql,並在 runlevel 3 和 5 自動啟用

# service mysqld start && chkconfig --level 35 mysqld on

4. 開始配置 php

# cd php-5.2.6

# ./configure --prefix=/usr/local/php5 --with-mysql --with-apxs2

=/usr/local/apache2/bin/apxs ( 這裡由於apahce2也是自己編譯的,使用

系統預設 apache 的人要注意路徑 ) --with-regex=php --enable-shared

--with-gd=/usr --enable-gd-native-ttf -with-zlib --with-freetype-dir=/usr

--with-ldap=/usr

5. 編譯並安裝

# make && make install

6. 檢查自己的 apache modules 資料夾下有無 libphp5.so 並檢查 httpd.conf

是否已經載入模組。 沒有的自行加入下一行

LoadModule php5_module modules/libphp5.so

要注意 modules資料夾位置 , 寫法是相對於 ServerRoot 的位置 ,

我的 apache ServerRoot 是在 /usr/local/apache2, 實際上 libphp5.so

絕對位置在 /usr/local/apache2/modules/libphp5.so )

如有修改 httpd.conf 的話要做 apachectl restart

(使用rpm安裝的 apache 可用 service httpd restart )

##備註:我測試 2.2.9 和 2.2.11 版的 apachectl 工具上偶而會出現

restart 無效的情況,可嘗試 apachectl stop 後再 apachectl start

7. 設定 mysql 資料庫

# mysqladmin -u root password '123456' //設定root密碼123456

# mysqladamin -u -h localhost password '123456' -p

# mysql -p

8. 拷貝php.ini 到 /usr/local/php5下 ,並確認 register_globals 關閉

# cd /root/php-5.2.6/ ; cp php.ini-dist /usr/local/php5/lib/php.ini

# vi /usr/local/php5/lib/php.ini

register_globals=off

9. 到 apache 的 DocumentRoot 資料夾下建立一個 test.php的

測試頁面,內容如下



10. 瀏覽器測試

http://打入你的ip/test.php

成功的話就會看到 php 的頁面


===========================================================================================


Tarball Apache2 & PHP5
一月 1st, 2008 · shian · Linux No comments - Tags: centos, Linux
Share

安裝apach和php有很多方法,像是利用rpm檔來裝,或是使用yum安裝,本篇介紹使用tarball 方式來安裝apache和php, 使用tarball安裝的方式比較麻煩一點,建議初學者可以使用yum的方式安裝


Apache 安裝
安裝:
./configure –prefix=/usr/local/apache –enable-so –enable-ssl –enable-rewrite
make
make install
註:
–prefix=/usr/local/apache/ : 安裝apache的位置
–enable-so : 啟用模組
–enable-ssl : 啟用ssl
–enable-rewrite : 啟用rewrite

PHP 安裝
安裝:
./configure –prefix=/usr/local/php/ –with-apxs2=/usr/local/apache/bin/apxs –with-mysql=/usr/local/mysql/ –with-gd –with-jpeg-dir=/usr/lib –with-zlib-dir=/usr/lib –with-libxml-dir=/usr/lib –enable-ftp –enable-socket –enable-magic-quotes –enable-libgcc –enable-ftp –enable-mbstring –enable-debug –enable-fastcgi –enable-module=so
make
make install
註:
–prefix=/usr/local/php/ : 安裝php的位置
–with-apxs2=/usr/local/apache/bin/apxs : apache2的目錄位置
–with-mysql=/usr/local/mysql/ : mysql的目錄位置(如果是用rpm安裝的Mysql,那就不要指定路徑了,直接--with-mysql即可)
–with-gd : 安裝gd模組
–with-jpeg-dir=/usr/lib
–with-zlib-dir=/usr/lib
–with-libxml-dir=/usr/lib
–enable-ftp :啟用ftp
–enable-socket :啟用socket
–enable-magic-quotes
–enable-libgcc
–enable-mbstring
–enable-debug
–enable-fastcgi
–enable-module=so

設定 Apache
設定檔 : /usr/local/apache/conf/httpd.conf

檢查是否有下面這段
LoadModule php5_module modules/libphp5.so

更改 ServerName
ServerName 192.168.1.102:80

更改 DirectoryIndex
找到DirectoryIndex,設定首頁名稱加上 index.php index.phtml index.php3

增加AddType項目,找到並增加以下三行:(用tarball安裝後,如果沒有設定下列3行,.php的網頁還是會變文字檔顯示)
AddType application/x-httpd-php .php
AddType application/x-httpd-php .php3
AddType application/x-httpd-php .phtml

設定User home directories
找到 Include conf/extra/httpd-userdir.conf 並將前面的 # 去掉

設定PHP
設定檔 : /usr/local/php/lib
複製php.ini-dist 到 /usr/local/php/lib/php.ini
cp php.ini-dist /usr/local/php/lib/php.ini

設定extensions
extension_dir = "/usr/local/php/lib/php/extensions"
找到 extensions_dir , 並設定extensions的目錄

操作&啟動
啟動: /usr/local/apache/bin/apachectl start
重啟: /usr/local/apache/bin/apachectl restart
停止: /usr/local/apache/bin/apachectl stop

開機啟動APACHE
設定檔: /etc/rc.d/rc.local
加入這一段 /usr/local/apache/bin/apachectl start

2010年10月1日 星期五

C,C++ redirect and pipeline


[root@localhost ~]# cat t3.c | ./t3
start...
#include
int main(int argc , char * argv[])
{
char in[1024];
int rlen = 0;
printf("start...\n");
do
{
rlen = fread(in , 1,sizeof(in),stdin);
if(rlen> 0)
{
printf("%s\n",in);
}
}while(rlen > 0);
printf("end...\n");
return 0;
}

end...
[root@localhost ~]# ./t3 < `echo t3.c`
start...
#include
int main(int argc , char * argv[])
{
char in[1024];
int rlen = 0;
printf("start...\n");
do
{
rlen = fread(in , 1,sizeof(in),stdin);
if(rlen> 0)
{
printf("%s\n",in);
}
}while(rlen > 0);
printf("end...\n");
return 0;
}

end...
[root@localhost ~]# gcc -o t3 t3.c

2010年8月17日 星期二

RHCA之路-第5篇目錄服務及集中式的驗證服務

Directory Server過去對我來說是遙遠而不瞭解的東西,在RHCA裡卻也是實質的一個關卡。
這門課,是我第一次接觸RHCA也是最後一門考的子科目,第一次上課,就是直接講Directory Server,
有些覺得挫折,完全聽不懂,加上那時才剛接觸Linux的第2年,有像鴨仔聽雷。
經過2年工作上的洗禮(雖然工作上沒用過Directory Server),以及在其他課程的輔助下,回頭再去Study後,有撥雲見日的感覺。
Directory Server的主要目的當然是在建置一個RHDS(Red Hat Directory Server),除此之外當然還有額外附帶的內容
(1)Directory Server 的建置以及 Replication 的實作
(2)Directory Server的加密服務,包含憑證作業等
(3)NIS/AutoFS Migrate 至RHDS
(4)RHDS Authentication串接Windows AD
在過程中,當然也有其他進階的課題
(1)Kerberos取代Authentication的驗證
(2)IPA
利用IPA,整個Directory Server的建置管理就簡單容易多了,只是因為包裝好了,所以限制以外的就不能更改了

RHCA之路-第4篇部署安全的網路服務系統

這個主題,到現在開始寫作,其實已經過了9個月,要喚起我遙遠的回憶實在有點困難,
記得當時第一個挑戰的關卡,就是這個課題,在還沒接受挑戰前就已經耳聞他的困難度了。
現在回想起來,真可以感覺他就是RHCE的進階版,內容又多又細,什麼都有什麼都不奇怪。
(1)什麼都要iptables filter rule
(2)什麼都要注意要selinux policy
(3)重要的named設定,包含名稱解析設定檔的config
(4)mail server的設定,包含sendmail ,postfix
(5)NIS,sshd , telnet(and krb5-telnet), vsftpd with kerberos
(6)apache (http, https and access control)
(7)NFS, v3, v4
(8)gpg
說是RHCE進階版一點都不為過,多又雜,可以講是另類的打字比賽吧

2010年6月18日 星期五

solaris iscsi

本次實作,只是想要為公司在IDC的機器上省下一筆錢
實際環境是用Open Solaris建一個iscsi target server
然後試著用RHEL來抓這個server看看
由於RHEL應該鮮少作業系統有廣泛支援,得知Linux有support ZFS,所以就以Solaris的ZFS為主要Filesystem

ServerIP : 172.16.43.144 (OpenSolaris SunOS 5.10 @vmware)
ClientIP : 172.16.43.99 (RHEL 5.4 @dom0,建議使用此版本,因為kernel版本剛好有fuse支援)
在Server關機狀態下,先幫它加一個HDD(20G),加完後透過下面指令,
可以知道多了一筆記錄(new HDD c1t1d0)

1.查到HDD的ID
# format
Searching for disks...done


AVAILABLE DISK SELECTIONS:
0. c1t0d0
/pci@0,0/pci15ad,1976@10/sd@0,0
1. c1t1d0
/pci@0,0/pci15ad,1976@10/sd@1,0
Specify disk (enter its number):

2.為zfs建立storage pools
zfs的精神在於,要先建storage pool,再從pool抓來建立共用的Lun(以下注意,實作過程都沒有格式化)
# zpool create iscsi-1 c1t1d0

確認建立的結果
# zpool list
NAME SIZE USED AVAIL CAP HEALTH ALTROOT
iscsi-1 19.9G 194K 19.9G 0% ONLINE -

建立一個zfs
# zfs create iscsi-1/public
# zfs list
NAME USED AVAIL REFER MOUNTPOINT
iscsi-1 12.0G 7.56G 25.5K /iscsi-1
iscsi-1/public 12.0G 7.56G 24.5K /iscsi-1/public

3. 實作target server
把剛才抓出來的zfs利用iscsi共享出來,
(1)用這個方法共享,那這個zfs底下的所有Lun就會直接share至iscsi
也就是如果share在zfs,則底下的每個Lun就會直接被share至iscsi
# zfs set shareiscsi=on iscsi-1/public
建立第1個Lun
# zfs create -V 2g iscsi/public/sean
建立第2個Lun
# zfs create -V 10g iscsi/public/share
檢視結果
# iscsitadm list target
Target: iscsi-1/public/sean
iSCSI Name: iqn.1986-03.com.sun:02:cf6f7152-7468-4f02-e214-ff7d6784c92c
Connections: 0
Target: iscsi-1/public/share
iSCSI Name: iqn.1986-03.com.sun:02:15a4b01a-9fdf-4a42-ef74-e82a9cc81397
Connections: 0

(2)用這個方法共享,那這個每建一個Lun就要share一次
# zfs create -V 2g iscsi/public/sean
# zfs set shareiscsi=on iscsi-1/public/sean

共享設定完成後,接著要設定提供出來的iscsi管道
# iscsitadm create tpgt 1
1是target gruop id
在1這個target group設定pathing(連進來的都透過172.16.43.144這個網卡的IP)
# iscsitadm modify tpgt -i 172.16.43.144 1
如果要設定多網卡多IP(multi-pahting),那就上面的指令多敲幾個就好
確認設定結田
# iscsitadm list tpgt
TPGT: 1
IP Address count: 1

4.結果驗證,並確認RHEL可以抓得到
1)在OpenSolaris上看看target server shared狀態
# iscsitadm list target -v
Target: iscsi-1/public/sean
iSCSI Name: iqn.1986-03.com.sun:02:cf6f7152-7468-4f02-e214-ff7d6784c92c
Alias: iscsi-1/public/sean
Connections: 0
ACL list:
TPGT list:
LUN information:
LUN: 0
GUID: 0x0
VID: SUN
PID: SOLARIS
Type: disk
Size: 2.0G
Backing store: /dev/zvol/rdsk/iscsi-1/public/sean
Status: online
Target: iscsi-1/public/share
iSCSI Name: iqn.1986-03.com.sun:02:15a4b01a-9fdf-4a42-ef74-e82a9cc81397
Alias: iscsi-1/public/share
Connections: 0
ACL list:
TPGT list:
LUN information:
LUN: 0
GUID: 0x0
VID: SUN
PID: SOLARIS
Type: disk
Size: 10G
Backing store: /dev/zvol/rdsk/iscsi-1/public/share
Status: online
確認target server是不是開3260 port
# netstat -an | grep 3260
*.3260 *.* 0 0 49152 0 LISTEN
*.3260 *.* 0 0 49152 0 LISTEN

2)從RHEL上可以從下面操作來驗證
安裝iscsi套件
[root@localhost ~]# yum install iscsi-initiator-utils.i386 -y
啟動iscsi client服務
[root@localhost vlc-1.0.0-rc4]# service iscsid start
[root@localhost vlc-1.0.0-rc4]# chkconfig iscsid on
去找找到172.16.43.144是否真有提供iscsi
[root@localhost vlc-1.0.0-rc4]# iscsiadm --mode discovery --type sendtargets --portal 172.16.43.144
172.16.43.144:3260,1 iqn.1986-03.com.sun:02:cf6f7152-7468-4f02-e214-ff7d6784c92c
172.16.43.144:3260,1 iqn.1986-03.com.sun:02:15a4b01a-9fdf-4a42-ef74-e82a9cc81397

5.在RHEL上mount zfs

[root@localhost zfs]# ll
total 1468
-rwxrwxrwx 1 root root 1502751 Jun 18 16:27 zfs-fuse-0.6.0-6.el5.i386.rpm
[root@localhost zfs]# rpm -vih zfs-fuse-0.6.0-6.el5.i386.rpm
warning: zfs-fuse-0.6.0-6.el5.i386.rpm: Header V3 DSA signature: NOKEY, key ID 217521f6
Preparing... ########################################### [100%]
1:zfs-fuse ########################################### [100%]
[root@localhost zfs]#

備註:fuse版表示Filesystem in UserSpacE,那麼就表示不在Kernel space執行的意思了

啟動zfs服務
[root@localhost zfs]# service zfs-fuse status
zfs-fuse is stopped
[root@localhost zfs]# service zfs-fuse start
Starting zfs-fuse: [ OK ]
Immunizing zfs-fuse against OOM kills [ OK ]
Mounting zfs partitions: chkco [ OK ]
[root@localhost zfs]# chkconfig zfs-fuse on
[root@localhost zfs]# service zfs-fuse status
zfs-fuse (pid 2387) is running...
no pools available
[root@localhost zfs]#

登入target server(target name的iqn在前面就discover出來了)
[root@localhost zfs]# iscsiadm --mode node --targetname iqn.1986-03.com.sun:02:cf6f7152-7468-4f02-e214-ff7d6784c92c --portal 172.16.43.144 --login
Logging in to [iface: default, target: iqn.1986-03.com.sun:02:cf6f7152-7468-4f02-e214-ff7d6784c92c, portal: 172.16.43.144,3260]
Login to [iface: default, target: iqn.1986-03.com.sun:02:cf6f7152-7468-4f02-e214-ff7d6784c92c, portal: 172.16.43.144,3260]: successful

fdisk 會發現有無法解讀的table
[root@localhost zfs]# fdisk -l

Disk /dev/sda: 500.1 GB, 500106780160 bytes
255 heads, 63 sectors/track, 60801 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

Device Boot Start End Blocks Id System
/dev/sda1 * 1 13 102400 7 HPFS/NTFS
Partition 1 does not end on cylinder boundary.
/dev/sda2 13 13068 104857600 7 HPFS/NTFS
Partition 2 does not end on cylinder boundary.
/dev/sda3 13068 48053 281022464 7 HPFS/NTFS
Partition 3 does not end on cylinder boundary.
/dev/sda4 48054 60801 102392640 5 Extended
Partition 4 does not end on cylinder boundary.
/dev/sda5 48054 48067 105808+ 83 Linux
/dev/sda6 48067 60801 102286768+ 8e Linux LVM

Disk /dev/sdb: 2147 MB, 2147483648 bytes
67 heads, 62 sectors/track, 1009 cylinders
Units = cylinders of 4154 * 512 = 2126848 bytes

Disk /dev/sdb doesn't contain a valid partition table

有發現/dev/sdb這個,但無法解讀,不過沒關係就照作吧
[root@localhost zfs]# zpool status
no pools available
[root@localhost zfs]# zpool list
no pools available
[root@localhost zfs]# zpool create iscsi-clt /dev/sdb
[root@localhost zfs]# zpool list
NAME SIZE USED AVAIL CAP HEALTH ALTROOT
iscsi-clt 1.98G 75K 1.98G 0% ONLINE -
[root@localhost zfs]# zfs list
NAME USED AVAIL REFER MOUNTPOINT
iscsi-clt 70.5K 1.95G 21K /iscsi-clt

把它mount起來,並產生檔案試試
[root@localhost zfs]# zfs set mountpoint=/iscsi-mnt iscsi-clt
[root@localhost iscsi-mnt]# zfs mount iscsi-clt
[root@localhost iscsi-mnt]# df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/mapper/VolGroup00-LogVol00
94082868 8201004 81025648 10% /
/dev/sda5 102454 11983 85181 13% /boot
tmpfs 2068836 0 2068836 0% /dev/shm
/dev/sda3 281022460 201541340 79481120 72% /mnt/ntfs-280g
iscsi-clt 2047940 23 2047918 1% /iscsi-mnt

如果要umount可以下
[root@localhost iscsi-mnt]# zfs umount iscsi-clt

[root@localhost zfs]# cd /iscsi-mnt/
[root@localhost iscsi-mnt]# ls -l
total 0
[root@localhost iscsi-mnt]# touch 1234
-rw-r--r-- 1 root root 0 Jun 18 16:49 1234
[root@localhost iscsi-mnt]#[root@localhost iscsi-mnt]# cat 1234
fdklasjflasjdfkajsdfl;ajsdf
alsdfja;lsdkjf;aklsdf
askdf;jaskdf;jaskldf
vi 1234

可以把下列這幾行加到/etc/rc.local
iscsiadm --mode node --targetname iqn.1986-03.com.sun:02:cf6f7152-7468-4f02-e214-ff7d6784c92c --portal 172.16.43.144 --login
zpool create iscsi-clt /dev/sdb
#以下這行是為了保險,理當設定一次後就會KEEP下來,只要再zfs mount即可
zfs set mountpoint=/iscsi-mnt iscsi-clt
zfs mount iscsi-clt

如果要一寫多讀,那唯獨可以設為(在iscsi client)
zfs set readonly=on [pool/zfs]

重開機時zpool status 可以觀察到iscsi-clt的狀態,如果UNAVAIL那就表示可能iscsi client連線有問題嘍
重新login連線,再檢查一次zpool status應該可恢復正常

linux使用zfs所需套件
-rwxrwxrwx 1 root root 84548 May 6 04:38 fuse-2.7.4-8_12.el5.i386.rpm
-rwxrwxrwx 1 root root 27287 May 6 04:38 fuse-devel-2.7.4-8_12.el5.i386.rpm
-rwxrwxrwx 1 root root 28498 May 6 04:35 fuse-kmdl-2.6.18-164.el5-2.7.4-8_12.el5.i686.rpm
-rwxrwxrwx 1 root root 28560 May 6 04:36 fuse-kmdl-2.6.18-164.el5PAE-2.7.4-8_12.el5.i686.rpm
-rwxrwxrwx 1 root root 28545 May 6 04:36 fuse-kmdl-2.6.18-164.el5xen-2.7.4-8_12.el5.i686.rpm
-rwxrwxrwx 1 root root 28531 May 6 04:36 fuse-kmdl-2.6.18-194.el5-2.7.4-8_12.el5.i686.rpm
-rwxrwxrwx 1 root root 28562 May 6 04:36 fuse-kmdl-2.6.18-194.el5PAE-2.7.4-8_12.el5.i686.rpm
-rwxrwxrwx 1 root root 28570 May 6 04:36 fuse-kmdl-2.6.18-194.el5xen-2.7.4-8_12.el5.i686.rpm
-rwxrwxrwx 1 root root 72616 May 6 04:37 fuse-libs-2.7.4-8_12.el5.i386.rpm

-rwxrwxrwx 1 root root 1502751 Jun 18 16:27 zfs-fuse-0.6.0-6.el5.i386.rpm

如果在mount zfs有下面錯誤訊息時
[root@HTS171 ~]# zfs mount iscsi-clt
cannot mount 'iscsi-clt': Input/output error.
Make sure the FUSE module is loaded.
那表示fuse-kmdl-xxx沒安裝(它需要fuse.ko)
fuse-kmdl-xxx請特別注意要跟kernel版本搭配(uname -a)

文章:
http://blog.xuite.net/ibjenny.cheng/vserver/22157067?ref=rel
http://www.wretch.cc/blog/wenbinlai/11660199
http://expert.lccnet.com.tw/zone/viewthread.php?tid=13224
http://forum.homeserver.com.tw/index.php?PHPSESSID=4cb8l8i2ljeov46q76u5trdac5&board=29.0
http://ian.testers.homelinux.net/wiki/view/Cluster_filesystem
Solaris FileSystem Choice
[cluster filesystem]
GFS
Lustre
UFS(globe option)
[non-cluster filesystem]
ZFS
NTFS
EXT3

2010年6月10日 星期四

RHCA之路-第3篇叢集及倉儲資料管理

Cluster & Storage的Implementation一直是企業追求不中斷服務下的探詢的技術與方法,
這門課的學習對我來說也是具備十分的吸引力(講實在,RHCA的課我都很有興趣)
從開始工作以來,都是一直跟C/C++打轉,3年前才開始跟系統維護搭上關係,
也慢慢對作業系統、資料庫以及其他衍生的技術開始著迷。Cluster的學習也是讓我十分期待的課程。

在參與這個課程的期間,每天都是不斷的驚訝與興奮。無待過往的經驗不足,實際上的領會與吸收還是有限。
不過在經過Ex436的洗禮,還是有一些些的成果,自己還覺得過得去。
只是學習至今,真的感受到學海無涯,只有不斷的投入心血,不斷學習各方先進的經驗,才能了解與融會貫通。

這門課最大收獲大概有幾個
1. 當然就是cluster的概念,原理與實作。除了課堂上的理論,自己也跟谷哥討教了一些,
cluster的觀念算是理解。實作部分更是有趣,改天有空就把公司的產品也改成用cluster來運作看看,應該很有趣
2. Raid, 過去聽到 Raid都是只紙上談兵,從來沒有實地目睹過。這次的過程也逼著我要去對Raid的整個概念要瞭解。
在谷哥的教導下,也得到了一些概念。經過了一連串的LAB,更能體會實際的感受。
3. iScsi, 這個介面讓我後來對storage的想法更有深刻的瞭解,也應用在一些實務面上,真是窮人落實Storage方法的好工具。
4. udev, 只能說太實用了,對他的alias實在只能說讚

2010年6月9日 星期三

Mysql 系統訊息集中監控(syslog, syslog-ng)


Mysql 的系統訊息,在早期算是個孤兒,在/var/log/下的種種訊息檔,看不到mysql的(除了mysql自己寫的),
當然更遑論syslog/syslog-ng的監控作法上,更沒辦法做這一塊
在mysql 5.1.20版出來後,這件事情終於獲得解決(怎麼等這麼久),不過對於之前的版本系統維護人員只好自己想辦法了
[mysql訊息記錄在syslog/syslog-ng的方法]
這篇不是要講5.1.20之後的系統訊息集中監控,畢竟我們公司的系統是早期的5.0.X版,所以就寫舊版的方法
舊版的方法用的比較老土,簡單講,要放入syslog/syslog-ng,那就用tail + logger來實現,例如

tail -f -n 0 /var/log/mysqld.log | logger -p daemon.info -t mysql

-n 0: 是為了在啟動tail時,不想把原本的訊息又丟一次
/var/log/mysqld.log: 請自行決定要放入去的mysql錯誤訊息檔名
-p daemon.info: 這個是設定要放到syslog/syslog-ng的facility.priority
-t mysql: 把所指定的檔名資料都給予一個標記字串(tag),如果沒給,就會放上user id
| :用(pipe)的原因為要把tail的結果餵給logger(廢話,應該都知道吧)
以上的命令可以加在自己寫的/etc/init.d/mysqld裡,在啟動mysql之前先tail過
當然也可以在cronjob裡,定期去檢查, tail指令是否還存在(可以自定pid檔來確認),不在就再啟動tail指令

注意:syslog/syslog-ng的port預設是udp:514(/etc/services的syslog,/etc/syslog-ng/syslog-ng.conf)

[syslog集中訊息]


一般,Linux安裝完後預設就是syslogd來管控訊息記錄,在進行syslog集中(centerlization)訊息時,
可以朝以下步驟方向執行
(1)選定1台當syslog center server
在這台server的 /etc/sysconfig/syslog設定如下(注意SYSLOGD_OPTIONS多了-r)
Options to syslogd
# -m 0 disables 'MARK' messages.
# -r enables logging from remote machines
# -x disables DNS lookups on messages recieved with -r
# See syslogd(8) for more details
SYSLOGD_OPTIONS="-m 0 -r"
# Options to klogd
# -2 prints all kernel oops messages twice; once for klogd to decode, and
# once for processing with 'ksymoops'
# -x disables all klogd processing of oops messages entirely
# See klogd(8) for more details
KLOGD_OPTIONS="-x"
#
SYSLOG_UMASK=077
# set this to a umask value to use for all log files as in umask(1).
# By default, all permissions are removed for "group" and "other".
(2)訊息集中
剩下的其他主機設定要把log丟給center server,在這些機器的/etc/syslog.conf設定如下
# Log all kernel messages to the console.
# Logging much else clutters up the screen.
#kern.* /dev/console

# Log anything (except mail) of level info or higher.
# Don't log private authentication messages!
*.info;mail.none;authpriv.none;cron.none /var/log/messages

# The authpriv file has restricted access.
authpriv.* /var/log/secure

# Log all the mail messages in one place.
mail.* -/var/log/maillog


# Log cron stuff
cron.* /var/log/cron

# Everybody gets emergency messages
*.emerg *

# Save news errors of level crit and higher in a special file.
uucp,news.crit /var/log/spooler

# Save boot messages also to boot.log
local7.* /var/log/boot.log

*.* @1.1.1.10

(3)如果系統訊息還要導到其他主機,例如在windows 2003上的kiwi syslog server,
可以在/etc/syslog.conf最後一行增加設定如下(假設kiwi syslog server的IP為1.1.1.20)
*.* @1.1.1.20

很重要的一點是,設定*.*是為了避免遺漏了任何訊息,但是*.*的話訊息量真的很多,
在網路上流動的訊息也會很多,另外就是訊息內容的格式也沒辦法更改

[syslog-ng集中訊息]


syslog-ng的好處是他的訊息跟syslog互通,所以kiwi也能吃這個訊息,另外,他的設定更加彈性
syslog-ng官網:http://www.balabit.com/
(1)source設定,可以設定各種來源管道的訊息
source { sourcedriver params; sourcedriver params; ... };
含義:
:一個消息源的標識
sourcedriver:消息源驅動器,可以支持若干參數,並使用分號「;」隔離多個消息源驅動器

消息源驅動器有:
file (filename) : 從指定的文件讀取日誌訊息
unix-dgram (filename) : 打開指定的SOCK_DGRAM模式的unix socket,接收日誌訊息
unix-stream (filename) : 打開指定的SOCK_STREAM模式的unix socket,接收日誌訊息
udp ( (ip),(port) ) : 在指定的UDP接收日誌訊息
tcp ( (ip),(port) ) : 在指定的TCP接收日誌訊息
sun-streams (filename) : 在solaris系統中,打開一個(多個)指定的STREAM設備,從其中讀取日誌訊息
internal() : syslog-ng內部產生的訊息
pipe(filename),fifo(filename) : 從指定的管道或者FIFO設備,讀取日誌訊息

例如:
source s_sys {
file ("/proc/kmsg" log_prefix("kernel: "));
unix-stream ("/dev/log");
internal();
# udp(ip(0.0.0.0) port(514)); #如果取消註釋,則可以從udp的514 port獲得訊息
};
其他部份不多做解釋,可以在網路上找到syslog-ng administrative guide

(2)filter
filter { expression; };
含義:
:一個過濾器標識
expression:表達式

表達式支持:
邏輯操作符:and(和)、or(或)、not(非);
函數:可使用正規表達式描述內容

過濾函數有:
facility(,): 根據facility(設備)選擇日誌消息,使用逗號分割多個facility
level(,): 根據level(優先級)選擇日誌消息,使用逗號分割多個level,或使用「..」表示一個範圍
program(regexp): 日誌消息的程序名是否匹配一個正則表達式
host(regexp): 日誌消息的主機名是否和一個正則表達式匹配
match(regexp): 對日誌消息的內容進行正則匹配
filter(): 調用另一條過濾規則並判斷它的值

例如:
filter f_filter2 { level(info..emerg) and
not facility(mail,authpriv,cron); };

※這裡的level定義info,相當於syslog的.=info,並不包括更低的等級;
若需要包括更低的等級,請使用「..」表示一個等級範圍;
另外,filter(DEFAULT),用於捕獲所有沒有匹配上的日誌消息。filter(*)是無效的。

(3)destination
destination { destdriver params; destdriver params; ... ;};

含義:
:一個目的地的標識
destdriver :目的地驅動器

目的地驅動器有:
file (filename) :把日誌消息寫入指定的文件
unix-dgram (filename) :把日誌消息寫入指定的SOCK_DGRAM模式的unix套接字
unix-stream (filename) :把日誌消息寫入指定的SOCK_STREAM模式的unix套接字
udp (ip),(port) :把日誌消息發送到指定的UDP端口
tcp (ip),(port) :把日誌消息發送到指定的TCP端口
usertty(username) :把日誌消息發送到已經登陸的指定用戶終端窗口
pipe(filename),fifo(filename) :把日誌消息發送到指定的管道或者FIFO設備
program(parm) :啟動指定的程序,並把日誌消息發送到該進程的標準輸入

舉例:
destination d_mesg { file("/var/log/messages"); };
destination d_syslog { udp ("192.168.228.225" port(514)); };

※配合使用udp或tcp即可實現syslog-ng/syslog center server。注意,udp函數的寫法上和source語法中的定義不同。

(4)log
log { source S1; source S2; ... filter F1; filter F2; ... destination
D1; destination D2; ... };

把消息源、過濾器、消息目的組合起來就形成一條完整的指令。日誌路徑中的成員是順序執行的。
凡是來源於指定的消息源,匹配所有指定的過濾器,並送到指定的地址。
※同樣的,每條日誌消息都會經過所有的消息路徑,並不是匹配後就不再往下執行的,請留意。

舉例:
log { source(s_sys); filter(f_default); destination(d_syslogd); };

(5)options
options { opt1; opt2; ... };


選項有:
引用
chain_hostnames(yesno) :是否打開主機名鏈功能,打開後可在多網絡段轉發日誌時有效
long_hostnames(yesno) :是chain_hostnames的別名,已不建議使用
keep_hostname(yesno) :是否保留日誌消息中保存的主機名稱,否時,總是使用來源主機來作重寫日誌的主機名
use_dns(yesno) :是否打開DNS查詢功能,應使用防火牆保護使用syslog-ng的節點安全,
並確認所有主機都是可以通過dns解釋的,否則請關閉該選項。
use_fqdn(yesno) :是否使用完整的域名
check_hostname(yesno) :是否檢查主機名有沒有包含不合法的字符
bad_hostname(regexp) :可通過正規表達式指定某主機的信息不被接受
dns_cache(yesno) :是否打開DNS緩存功能
dns_cache_expire(n) :DNS緩存功能打開時,一個成功緩存的過期時間
dns_cache_expire_failed(n) :DNS緩存功能打開時,一個失敗緩存的過期時間
dns_cache_size(n) :DNS緩存保留的主機名數量
create_dirs(yesno) :當指定的目標目錄不存在時,是否創建該目錄
dir_owner(uid) :目錄的UID
dir_group(gid) :目錄的GID
dir_perm(perm) :目錄的權限,使用八進制方式標註,例如0644
owner(uid) :文件的UID
group(gid) :文件的GID
perm(perm) :文件的權限,同樣,使用八進制方式標註
gc_busy_threshold(n) :當syslog-ng忙時,其進入垃圾信息收集狀態的時間。
一旦分派的對象達到這個數字,syslog-ng就啟動垃圾信息收集狀態。默認值是:3000。
gc_idle_threshold(n) :當syslog-ng空閒時,其進入垃圾信息收集狀態的時間。
一旦被分派的對象到達這個數字,syslog-ng就會啟動垃圾信息收集狀態,默認值是:100
log_fifo_size(n) :輸出隊列的行數
log_msg_size(n) :消息日誌的最大值(bytes)
mark(n) :多少時間(秒)寫入兩行MARK信息供參考,目前沒有實現
stats(n) :多少時間(秒)寫入兩行STATUS信息供,默認值是:600
sync(n) :緩存多少行的信息再寫入文件中,0為不緩存,局部參數可以覆蓋該值。
time_reap(n) :在沒有消息前,到達多少秒,即關閉該文件的連接
time_reopen(n) :對於死連接,到達多少秒,會重新連接
use_time_recvd(yesno) :宏產生的時間是使用接受到的時間,還是日誌中記錄的時間;
建議使用R_的宏代替接收時間,S_的宏代替日誌記錄的時間,而不要依靠該值定義。

例如:
options {
sync (0);
time_reopen (10);
log_fifo_size (1000);
long_hostnames (off);
use_dns (no);
use_fqdn (no);
create_dirs (no);
keep_hostname (yes);
};

(6)template
template是配合destination的一個設定,可以對輸出訊息進行格式化,使用tempate時,
可以指定使用以下參數
$MACRO_NAME
description/type
example

$FACILITY
syslog facility name
daemon

$PRIORITY
the syslog priority name
debug

$LEVEL ; same output as $PRIORITY

$TAG
Hex representaiton of the 32-bit priority/facility pair (see
/usr/include/sys/syslog.h)
1f

(1f is the output for "daemon/debug" as above)

$DATE
The local system time
Jan 19 23:27:21

$FULLDATE
Same as $DATE but with %Y appended,
2001 Jan 19 23:27:21

$ISODATE
ISO-standard format date (strftime format "%Y-%m-%dT%H:%M:%S%z")
2001-01-19T23:27:21+1000

$YEAR
4-digit year string
2001

$MONTH
2-digit month string
01

$DAY
2-digit day string
19

$HOUR
2-digit hour string
23

$MIN
2-digit minutes string
27

$SEC
2-digit seconds string
21

$HOST
host string; not sure how to decode this function, in my example it's the
same as fullhost (?)
avrio

$FULLHOST
"full hostname" (msg->host->data)
avrio

$PROGRAM
If syslog-ng has pulled a 'program name' out of the message, this will
return that
qpage

$MSG $MESSAGE
The full syslog message
qpage[9366]: processing the page queue

例如:
destination d_format_test { file("/var/log/test" template("$FACILITY $PRIORITY \
$LEVEL $TAG $DATE $FULLDATE $ISODATE $YEAR $MONTH $DAY $HOUR $MIN $SEC $HOST \
$FULLHOST $PROGRAM $MSG\n")); };

要設定syslog-ng集中化訊息架構的方法說明如下:
(1)選定1台當syslog-ng center server
選定後,在這台server上安裝syslog-ng(用rpm安裝比較容易)
安裝後理論上syslog/klog的服務會自動卸載,不過還是檢查一下好
在下次開機時,也記得啟動syslog-ng
service syslog stop
chkconfig syslog off
service syslog status
chkconfig --list syslog
service syslog-ng start
chkconfig syslog-ng on

設定syslog-ng當syslog server,所以要修改/etc/syslog-ng/syslog-ng.conf
範例如下:
# syslog-ng configuration file.
#
# This should behave pretty much like the original syslog on RedHat. But
# it could be configured a lot smarter.
#
# See syslog-ng(8) and syslog-ng.conf(5) for more information.
#

options {
sync (0);
time_reopen (10);
log_fifo_size (1000);
long_hostnames (off);
use_dns (no);
use_fqdn (no);
create_dirs (no);
keep_hostname (yes);
};

source s_sys {
file ("/proc/kmsg" log_prefix("kernel: "));
unix-stream ("/dev/log");
internal();
#打開對514 udp來源的訊息接收
udp(ip(0.0.0.0) port(514));

# udp(ip(0.0.0.0) port(514));
};

destination d_cons { file("/dev/console"); };
#destination d_syslogd { file("/tmp/syslogd"); };
destination d_mysql { udp("1.1.1.20" port(514)); };

destination d_mesg { file("/var/log/messages"); };
destination d_auth { file("/var/log/secure"); };
destination d_mail { file("/var/log/maillog" sync(10)); };
destination d_spol { file("/var/log/spooler"); };
destination d_boot { file("/var/log/boot.log"); };
destination d_cron { file("/var/log/cron"); };
destination d_kern { file("/var/log/kern"); };
destination d_mlal { usertty("*"); };
destination d_format_test { file("/var/log/test" template("2|HTS-TEST|$HOUR:$MIN:$SEC\t$PROGRAM\t$MSG\n")); };


filter f_mysql { facility(daemon) and level(info) and match("mysql"); };
#filter f_mysql { match("mysql"); };

filter f_kernel { facility(kern); };
filter f_default { level(info..emerg) and
not (facility(mail)
or facility(authpriv)
or facility(cron)); };
filter f_auth { facility(authpriv); };
filter f_mail { facility(mail); };
filter f_emergency { level(emerg); };
filter f_news { facility(uucp) or
(facility(news)
and level(crit..emerg)); };
filter f_boot { facility(local7); };
filter f_cron { facility(cron); };
#log { source(s_sys); filter(f_kernel); destination(d_cons); };
#log { source(s_sys); filter(f_syslogd); destination(d_syslogd); };
#這個log範例是重新格式化系統訊息,並寫到指定檔案
log { source(s_sys); filter(f_mysql); destination(d_format_test); };
#這個log範例是把訊息再導到1.1.1.20
log { source(s_sys); filter(f_mysql); destination(d_mysql);
#如果要把重新格式化的訊息丟到1.1.1.20,那就綜合上面的destination設定};

log { source(s_sys); filter(f_kernel); destination(d_kern); };
log { source(s_sys); filter(f_default); destination(d_mesg); };
log { source(s_sys); filter(f_auth); destination(d_auth); };
log { source(s_sys); filter(f_mail); destination(d_mail); };
log { source(s_sys); filter(f_emergency); destination(d_mlal); };
log { source(s_sys); filter(f_news); destination(d_spol); };
log { source(s_sys); filter(f_boot); destination(d_boot); };
log { source(s_sys); filter(f_cron); destination(d_cron); };

# vim:ft=syslog-ng:ai:si:ts=4:sw=4:et:
設定完成後,要讓syslog-ng順利重啟
service syslog-ng restart

注意:如果syslog-ng要另外記錄檔名,請設定成logrotate,以免LOG太大佔空間

(2)訊息集中
剩下的其他主機設定要把log丟給center server,在這些機器的/etc/syslog.conf最後一行新增如下
*.* @1.1.1.10

[kiwi syslogd使用說明]
kiwi syslogd是windows下一個不錯用的工具,有免費版跟完整版2種.
持著使用綠色軟體的前提下,免費版當然受限功能. 如果能使用完整版,應該可以不要用syslog-ng
官網:http://www.kiwisyslog.com/

設定說明如下:
1.從File選單-> Setup,進入Setup對話框
2-1.選擇Formatting->Custom file formats, 在Custom file formats上按滑鼠右鍵,選Add new custom file format
2-2.只鉤選左邊的Message text欄位(意思只要訊息就好),Apply之後會多一個New Format項目

3-1.選擇Rules->Default->Log to file
3-2.在log file format 下拉式選單選擇Custom1 New Format

4.套用後,訊息便會在畫面(因為有鉤選Display)以及Logs目錄下(也有鉤選Log to file)產生
預設的路徑應該在c:\program files\syslogd\logs\下
如果要依照每天存一個檔,可以在Log to file的檔名設定如下
c:\program files\syslogd\logs\%DateY4%DateM2%DateD2.log
如果是2010年6月9日,檔名就會顯示成
c:\program files\syslogd\logs\20100609.log

注意:
1.kiwi在機器啟動時,要跟著帶起來
2.Log to file的檔案記得定期要清檔,以免吃硬碟空間

假使系統自己的monitor agent是利用讀檔的方式,把訊息傳給Monitor Server,那就可以在kiwi設定中,
在Log to file的設定時,把檔案寫到agent所指定的檔名跟位置,而訊息的格式內容則透過syslog-ng的
template來指定,就可以達到想要的結果

[使用相關的套件有]
1. Windows
Kiwi_Syslogd_8.1.6.setup.exe
2. syslog (@rhel 5.4)
預設的syslog套件
3. syslog-ng (@rhel 5.4)
syslog-ng-2.1.4-1.el5.i386.rpm

文章分類