syslog的用法

許多應用程序需要記錄它們的活動。系統程序經常需要向控制檯或日誌文件寫消息。這些消息可能指示錯誤、警告或是與系統狀態有關的一般信息。例如,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

實例代碼:

 

#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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章