Windows下的日志机制

 

对于日志,大部分人的想法应当和我起初的想法一致,只要写个函数,在这个函数中打开一个文件,把需要记录的事件信息写到这个文件中。然后在需要记录日志的地方调用这个函数。

但此时需要考虑的问题有很多,包括文件名的定义,是每次写日志都创建一个新文件还是在一个文件中写所有的信息。如果是同一个文件如果控制多线程同时写的问题;还有当日志文件过大时,如果删除以前的记录。读日志的方式,包括检索的功能;安全问题等等。所以不要小看了仅是辅助功能的日志机制,但不用担心,windows已经为我们定义了很完善的日志架构。

Windows vista引入的CLFS ( Common Log File System)机制,另外一个就是从NT3.5就支持的Event Logging机制,里面的函数大多是以Elf(Event Log File)开头的,简称为ELF。

Windows XP中定义了3类日志,分别是应用程序日志(Application),安全日志(Security)和系统日志(system),文件名分别为AppEvent.Evt, SecEvent.Evt和SysEvent.Evt.这些文件都用于存储注册表文件和配置信息的CONFIG目录下%SystemRoot%\SYSTEM32\CONFIG\

Windows Vista增加了HardvareEvents和DFS Replication等日志类别,并且为所有的日志文件建立了一个单独的目录,即%SystemRoot%\SYSTEM32\winevt\Logs目录,日志文件的扩展名也由.EVT改为.EVTX。

日志的配置信息都是存储在注册表

HKEY_LOACAL_MACHINE\SYSTEM\CurrentControlSet\Sercices\Eventlog

 

下面看产生windows日志的API及其执行过程:

1.  在注册表中注册事件源。线介绍一下事件源,事件源都是注册在注册表HKLM\SYSTEM\CurrentControlSet\Services\EventLog\Application\下的,如果需要自己注册事件源就可以在这个注册表下添加一个新的键,再加两个项就可以了。来看个例子,outlook的事件源

它包含了三个键,EvetMessageFile用来指定这个事件源的消息文件(message file)的位置和名称。消息文件的作用可以使用模板来格式化日志事件或其他消息,与字符串资源和对话框资源差不多。可以使用后面介绍的事件ID(Event ID)来查找对应的显示信息,提供一种模板的支持。TypesSupported表示事件所支持的类型,包括EVENTLOG_ERROR_TYPE(0x0001), EVENTLOG_WARBUBG_TYPE(0x0002)等。Version表示事件源的版本。消息文件可以是DLL,exe等有效地PE文件,编写消息文件的方法这里就不介绍了,这里可以写应用程序本身的路径。

2.  调用RegisterEventSource API来取得事件源句柄,原型为:

HANDLE RegisterEventSource ( LPCTSTR lpUNCServerName, LPCTSTR lpSourceName)

其中lpUNCServerName表示机器名,如果是在本机操作,添NULL就可以了,lpSourceName为事件源的名称,填写前面创建的键名就可以了。如果事件源的名称在注册表中找不到,那么系统会默认使用应用类日志下的Application事件源。

3.  使用ReportEvent API来添加日志记录。原型为:

BOOL ReportEvent ( HANLE hEventLog, WORD wType, WORD wCategory, DWORD dwEventID, PSID lpUserSid, DWORD wNumStrings, DWORD dwDataSize, LPCTSTR* lpStrings, LPVOID lpRawData);

第一参数为hEventLog是使用RegisterEventSource得到的事件源句柄;第二个参数wType用来指定事件的类型,可以为如下的常量:EVENTLOG_SUCCESS,EVENTLOG_AUDIT_FAILURE等。第三个参数wCategory用来指定事件在事件源中的类属号,其分类规则是由应用程序自己定义的。第四个参数dwEventID用来指定事件的ID号,通过这个ID来定位消息文件中所对应的信息。所以ID也是有应用程序自己定义的。第五个参数lpUserSid用来指定用户的安全标识,可以设为NULL。第六个参数wNumStrings用来指定第八个参数lpStrings所指向的字符串数组所包含的字符串指针个数。第八个参数用在事件的Description字段中显示信息,如下图所示:

第七个参数dwDataSize用来指定第九个参数lpRawData所指向的原始数据缓冲区的数据长度。这两个参数一个设为0,另一个设为NULL就行了。

   这样就可以写入日子记录了,来看一下代码。

   首先是注册事件源的代码:

BOOL AddEventSource(CString csName, DWORD dwCategoryCount)

{

         HKEY         hRegKey = NULL;

         DWORD   dwError = 0;

         TCHAR     szPath[ MAX_PATH ];

 

         _stprintf( szPath, _T("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\%s"), csName );

 

         // Create the event source registry key

         dwError = RegCreateKey( HKEY_LOCAL_MACHINE, szPath, &hRegKey );

         if (dwError != 0)

         {

                   OutMsg("RegCreateKey failed for %d",GetLastError());

                   return E_FAIL;

         }

 

         // Name of the PE module that contains the message resource

         GetModuleFileName( NULL, szPath, MAX_PATH );

 

         // Register EventMessageFile

         dwError = RegSetValueEx( hRegKey, _T("EventMessageFile"), 0, REG_EXPAND_SZ, (PBYTE) szPath, (_tcslen( szPath) + 1) * sizeof TCHAR );

         if (dwError == 0)

         {

                   // Register supported event types

                   DWORD dwTypes = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;

                   dwError = RegSetValueEx( hRegKey, _T("TypesSupported"), 0, REG_DWORD, (LPBYTE) &dwTypes, sizeof dwTypes );

 

                   // If we want to support event categories, we have also to register     the CategoryMessageFile.

                   // and set CategoryCount. Note that categories need to have the message ids 1 to CategoryCount!

 

                   if(dwError == 0 && dwCategoryCount > 0 )

                   {

                            dwError = RegSetValueEx( hRegKey, _T("CategoryMessageFile"), 0, REG_EXPAND_SZ, (PBYTE) szPath, (_tcslen( szPath) + 1) * sizeof TCHAR );

                            if (dwError == 0)

                                     dwError = RegSetValueEx( hRegKey, _T("CategoryCount"), 0, REG_DWORD, (PBYTE) &dwCategoryCount, sizeof dwCategoryCount );

                   }

         }

 

         RegCloseKey( hRegKey );

 

         return TRUE;

}

来至《软件调试》

 

接下来是添加记录的过程:

         LPCTSTR ppszArgs[]={"I make a trick!!!!!!!"};  // 要显示的信息

         HANDLE  hLog = ::RegisterEventSource( NULL, "MyEventSource"); //之前注册的事件源

 

         BOOL bRet = ReportEvent(hLog, EVENTLOG_INFORMATION_TYPE,

                   0, 1024, NULL, 1, 0, ppszArgs,         NULL);    // 显示记录

 

除了显示日子记录的功能,当然还有其他的API来实现更多的功能,其他的API如下图所示:

 

你可能感兴趣的:(软件调试,系统安全,windows,application,system,null,api,file)