許多應用程式需要記錄它們的活動。系統程式經常需要向控制台或記錄檔寫訊息。這些訊息可能指示錯誤、警告或是與系統狀態有關的一般資訊。例如,su程式會把某個使用者嘗試得到超級使用者權限但失敗的事實記錄下來。
通常這些日誌資訊被記錄在系統檔案中,而這些系統檔案又被儲存在專用於此目的的目錄中。它可能是/usr/adm或/var/log目錄。對一個典型的Linux安裝來說,檔案 /var/log/messages包含所有系統資訊,/var/log/mail包含來自郵件系統的其他日誌資訊,/var/log/debug可能包 含調試資訊。你可以通過查看/etc/syslog.conf檔案來檢查系統配置。
下面是一些日誌資訊的範例:
這裡,我們可以看到記錄的各種類型的資訊。前幾個是Linux核心在啟動和檢測已安裝硬體時自己報告的資訊。接著是任務安排程式cron報告它正在啟動。最後,su程式報告使用者neil獲得了超級使用者權限。
查看日誌資訊可能需要有超級使用者特權。
有些UNIX系統並不像上面這樣提供可讀的記錄檔,而是為管理員提供一些工具來讀取系統事件的資料庫。具體情況請參考系統文檔。
雖然系統訊息的格式和儲存方式不盡相同,可產生訊息的方法卻是標準的。UNIX規範為所有程式提供了一個介面,通過syslog函數來產生日誌資訊:
syslog函數向系統的日誌工具發送一條日誌資訊。每條資訊都有一個priority參數,該參數是一個嚴重層級與一個設施值的按位或。嚴重層級控制日誌資訊的處理,設施值記錄日誌資訊的來源。
定義在標頭檔syslog.h中的設施值包括LOG_USER(預設值)——它指出訊息來自一個使用者應用程式,以及LOG_LOCAL0、LOG_LOCAL1直到LOG_LOCAL7,它們的含義由本地管理員指定。
嚴重層級按優先順序遞減排列,如表4-6所示。
表 4-6
優 先 級
說 明
LOG_EMERG
緊急情況
LOG_ALERT
高優先順序故障,例如資料庫崩潰
LOG_CRIT
嚴重錯誤,例如硬體故障
LOG_ERR
錯誤
LOG_WARNING
警告
LOG_NOTICE
需要注意的特殊情況
LOG_INFO
一般資訊
LOG_DEBUG
調試資訊
根據系統配 置,LOG_EMERG資訊可能會廣播給所有使用者,LOG_ALERT資訊可能會EMAIL給管理員,LOG_DEBUG資訊可能會被忽略,而其他資訊則 寫入記錄檔。當我們編寫的程式需要使用日誌記錄功能時,只要在希望建立一條日誌資訊時簡單的調用syslog函數即可。
syslog建立的日誌資訊包含訊息頭和訊息體。消 息頭根據設施值及日期和時間建立。訊息體根據syslog的message參數建立,該參數的作用類似printf中的格式字串。syslog的其他參 數要根據message字串中printf風格的控制轉換符而定。此外,控制轉換符%m可用於插入與錯誤變數errno當前值對應的出錯訊息字串。這 對於記錄錯誤訊息很有用。
實驗:syslog函數
在這個程式中,我們試圖開啟一個不存在的檔案:
編譯並運行這個程式syslog.c,我們沒有看到輸出,但是/var/log/messages檔案現在在尾部有如下一行:
Feb 8 09:59:14 beast syslog: oops - No such file or directory
實驗解析
在這個程式中,我們試圖開啟一個不存在的檔案。在檔案開啟失敗後,我們調用syslog在系統日誌中記錄這一事件。
注意:日誌資訊並未指明是哪個程式調用了日誌功能,它僅僅記錄syslog被調用以記錄一條資訊的事實。%m轉換控制符被替換為一個錯誤描述,在本例中就是“檔案沒有找到”。這比僅僅報告一個原始的錯誤碼更有用。
在標頭檔syslog.h中還定義了一些能夠改變日誌記錄行為的其他函數。它們是:
我們可以通過調用openlog函數來改變日誌資訊 的表示方式。它允許我們設定一個字串ident,該字串會加在日誌資訊的前面。我們可以通過它來指明是哪個程式建立了這條資訊。facility參數 記錄一個設施值,它將作為後續syslog調用的預設設施值。它的預設值是LOG_USER。logopt參數對後續syslog調用的行為進行配置,它是0個或多個表4-7中值的按位或。
表 4-7
logopt參數
說 明
LOG_PID
在日誌資訊中包含進程標識符,這是系統分配給每個進程的一個唯一值
LOG_CONS
如果資訊不能被記錄到記錄檔中,就把它們發送到控制台
LOG_ODELAY
在第一次調用syslog時才開啟日誌功能
LOG_NDELAY
立即開啟日誌功能,而不是等到第一次記錄日誌時
openlog函數會分配並開啟一個檔案描述符,並通過它來寫日誌。你可以使用closelog函數來關閉它。注意,在調用syslog之前無需調用openlog,因為syslog會根據需要自行開啟日誌功能。
我們可以通過setlogmask函數來設定一個日誌掩碼,並通過它來控制日誌資訊的優先順序。優先順序未在日誌掩碼中置位的後續syslog調用都將被丟棄。例如,你可以通過這個方法關閉LOG_DEBUG訊息而不用改變程式主體。
我們可以用LOG_MASK(priority)為日誌資訊建立一個掩碼,它的作用是建立一個只包含一個優先順序的掩碼。我們還可以用LOG_UPTO(priority)來建立一個由指定優先順序之前的所有優先順序(包括指定優先順序)構成的掩碼。
實驗:logmask程式
在本例中,我們將看到日誌掩碼的作用:
logmask.c程式沒有輸出,但是在一個典型的Linux系統中,在/var/log/messages檔案尾部,我們會看到如下資訊:
Feb 8 10:00:50 beast logmask[1833]: informative message, pid = 1833
接收調試日誌資訊的檔案(根據日誌配置而定,通常是/var/log/debug,有時也可能是/var/log/messages)會包含如下資訊:
Feb 8 10:00:50 beast logmask[1833]: debug message, should appear
實驗解析
這個程式用它自己的名字logmask初始化日誌功 能,並要求日誌資訊中包含進程標識符。一般資訊記錄到檔案/var/log/messages,調試資訊記錄到檔案/var/log/debug。第二個 調試資訊沒有出現,因為我們調用setlogmask忽略了優先順序低於LOG_NOTICE的所有資訊(注意,這種做法在早期Linux核心中可能不支援)。
如果你的Linux安裝版本沒有啟用調試資訊日誌功 能,或者採用的是其他配置情況,你可能看不到調試資訊。要啟用所有的調試資訊,需把下面一行內容添加到/etc/syslog.conf檔案的尾部並重啟 系統(你也可以簡單地向syslogd進程發送一個掛起訊號)。然而,不管如何,最好認真查看你的系統文檔以瞭解設定檔的正確格式。
*.debug /var/log/debug
logmask.c用到了getpid函數,它和與其緊密相關的getppid函數的定義如下所示:
這兩個函數分別返回調用進程和調用進程的父進程的進程標識符(PID)。
使用syslog()函數處理日誌資訊
函式宣告:
#include <syslog.h>
void syslog(int priority, const char *message, arguments...);
priority參數的格式(severity level|facility code)
樣本:
LOG_ERR|LOG_USER
severity level:
Priority Level Description
LOG_EMERG An emergency situation
LOG_ALERT High-priority problem, such as database corruption
LOG_CRIT Critical error, such as hardware failure
LOG_ERR Errors
LOG_WARNING Warning
LOG_NOTICE Special conditions requiring attention
LOG_INFO Informational messages
LOG_DEBUG Debug messages
facility value(轉自syslog.h標頭檔):
/* facility codes */
#define LOG_KERN (0<<3) /* kernel messages */
#define LOG_USER (1<<3) /* random user-level messages */
#define LOG_MAIL (2<<3) /* mail system */
#define LOG_DAEMON (3<<3) /* system daemons */
#define LOG_AUTH (4<<3) /* security/authorization messages */
#define LOG_SYSLOG (5<<3) /* messages generated internally by syslogd */
#define LOG_LPR (6<<3) /* line printer subsystem */
#define LOG_NEWS (7<<3) /* network news subsystem */
#define LOG_UUCP (8<<3) /* UUCP subsystem */
#define LOG_CRON (9<<3) /* clock daemon */
#define LOG_AUTHPRIV (10<<3) /* security/authorization messages (private) */
#define LOG_FTP (11<<3) /* ftp daemon */
範例程式碼:
#include <syslog.h>
#include <stdio.h>
int main(void)
{
FILE *f;
f = fopen("abc","r");
if(!f)
syslog(LOG_ERR|LOG_USER,"test - %m/n");
}
上面的日誌資訊由系統自動給出,我們也可過濾日誌資訊。用到以下函數:
#include <syslog.h>
void closelog(void);
void openlog(const char *ident, int logopt, int facility);
int setlogmask(int maskpri);
logopt參數的選項:
logopt Parameter Description
LOG_PID Includes the process identifier, a unique number allocated to each process by the system, in the messages.
LOG_CONS Sends messages to the console if they can’t be logged.
LOG_ODELAY Opens the log facility at first call to .
LOG_NDELAY Opens the log facility immediately, rather than at first log.
範例程式碼:
#include <syslog.h>
#include <stdio.h>
#include <unistd.h>
int main(void)
{
int logmask;
openlog("logmask", LOG_PID|LOG_CONS, LOG_USER); /*日誌資訊會包含進程id。*/
syslog(LOG_INFO, "informative message, pid=%d", getpid());
syslog(LOG_DEBUG,"debug message, should appear"); /*記錄該日誌資訊。*/
logmask = setlogmask(LOG_UPTO(LOG_NOTICE)); /*設定屏蔽低於NOTICE層級的日誌資訊。*/
syslog(LOG_DEBUG, "debug message, should not appear"); /*該日誌資訊被屏蔽,不記錄。*/
}
不同安全層級的日誌資訊存放在/var/log目錄下的哪個檔案中是由/etc/syslog.conf檔案控制的,下面是我系統中syslog.conf檔案的內容:
# /etc/syslog.conf Configuration file for syslogd.
#
# For more information see syslog.conf(5)
# manpage.
#
# First some standard logfiles. Log by facility.
#
auth,authpriv.* /var/log/auth.log
*.*;auth,authpriv.none -/var/log/syslog
#cron.* /var/log/cron.log
daemon.* -/var/log/daemon.log
kern.* -/var/log/kern.log
lpr.* -/var/log/lpr.log
mail.* -/var/log/mail.log
user.* -/var/log/user.log
uucp.* /var/log/uucp.log
#
# Logging for the mail system. Split it up so that
# it is easy to write scripts to parse these files.
#
mail.info -/var/log/mail.info
mail.warn -/var/log/mail.warn
mail.err /var/log/mail.err
# Logging for INN news system
#
news.crit /var/log/news/news.crit
news.err /var/log/news/news.err
news.notice -/var/log/news/news.notice
#
# Some `catch-all' logfiles.
#
*.=debug;/
auth,authpriv.none;/
news.none;mail.none -/var/log/debug
*.=info;*.=notice;*.=warn;/
auth,authpriv.none;/
cron,daemon.none;/
mail,news.none -/var/log/messages
#
# Emergencies are sent to everybody logged in.
#
*.emerg *
#
# I like to have messages displayed on the console, but only on a virtual
# console I usually leave idle.
#
#daemon,mail.*;/
# news.=crit;news.=err;news.=notice;/
# *.=debug;*.=info;/
# *.=notice;*.=warn /dev/tty8
# The named pipe /dev/xconsole is for the `xconsole' utility. To use it,
# you must invoke `xconsole' with the `-file' option:
#
# $ xconsole -file /dev/xconsole [...]
#
# NOTE: adjust the list below, or you'll go crazy if you have a reasonably
# busy site..
#
daemon.*;mail.*;/
news.crit;news.err;news.notice;/
*.=debug;*.=info;/
*.=notice;*.=warn |/dev/xconsole
執行個體代碼:
1 #include <string>
2 #include <iostream>
3 #include <algorithm>
4 #include <list>
5 #include <syslog.h>
6 using namespace std ;
7
8 //===============================================
9
10 class TLOG
11 {
12 public:
13 TLOG() ;
14 ~TLOG() ;
15 TLOG& operator<<( const char * p ) ;
16 TLOG& operator<<( string & s ) ;
17 TLOG& operator<<( TLOG& (* pfun)(TLOG&) ) ;
18
19 void debug( const char * p ) ;
20 void debug( string & s ) ;
21
22 void log( const char * p ) ;
23 void log( string & s ) ;
24 } ;
25 TLOG& endl( TLOG& object ) ;
26
27 const char * LOG_PREFIX = "root_log : " ;
28
29 TLOG glog ;
30
31 TLOG::TLOG()
32 {
33 #ifdef LOG_SYSLOGD
34 openlog( LOG_PREFIX, LOG_PID, LOG_USER ) ;
35 #endif
36 }
37 TLOG::~TLOG()
38 {
39 #ifdef LOG_SYSLOGD
40 closelog() ;
41 #endif
42 }
43
44 TLOG& TLOG::operator<<( const char * p )
45 {
46 #ifdef LOG_STDOUT
47 cout << p ;
48 #endif
49 return *this ;
50 }
51
52 TLOG& TLOG::operator<<( string & s )
53 {
54 #ifdef LOG_STDOUT
55 cout << s ;
56 #endif
57 return *this ;
58 }
59 TLOG& TLOG::operator<<( TLOG& (* pfun)(TLOG&) )
60 {
61 return pfun(*this) ;
62 }
63 TLOG& endl( TLOG& object )
64 {
65 #ifdef LOG_STDOUT
66 cout << endl ;
67 #endif
68 return object ;
69 }
70
71 void TLOG::debug( const char * p )
72 {
73 *this << p ;
74 return ;
75 }
76 void TLOG::debug( string & s )
77 {
78 *this << s ;
79 return ;
80 }
81
82 void TLOG::log( const char * p )
83 {
84 *this << LOG_PREFIX << p << endl ;
85
86 #ifdef LOG_SYSLOG
87 syslog( LOG_INFO, p ) ;
88 #endif
89 return ;
90 }
91 void TLOG::log( string & s )
92 {
93 *this << LOG_PREFIX << s << endl ;
94
95 #ifdef LOG_SYSLOG
96 syslog( LOG_INFO, s.c_str() ) ;
97 #endif
98 return ;
99 }
100
101 int
102 main(void)
103 {
104 glog.log("yeetec" );
105 // glog.debug(__func__);
106 string word;
107 cout<<"Enter a line:";
108 cin>>word;
109 while(cin.get()!='/n')
110 continue;
111 cout<<word<<"is all"<<"wanted!/n";
112
113 string line;
114 cout<<"Enter a line:(really)";
115 getline(cin,line);
116 cout<<"line:"<<line<<endl;
117 return 0;
118 }
結果:
ct 16 16:01:42 zerk a.out: yeetec
本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/telehiker/archive/2007/10/18/1830575.aspx