IIS 的高级日志记录

您所在的位置:网站首页 请求启用实时转录 IIS 的高级日志记录

IIS 的高级日志记录

2024-07-17 21:11| 来源: 网络整理| 查看: 265

IIS 的高级日志记录 - 实时日志记录 项目 03/14/2024

作者:Vishal Sood

IIS 高级日志记录可以扩展 Web 平台以支持实时分析,帮助向客户提供实时报告或与合作伙伴合作提供实时报告。 高级日志记录功能包含的一个选项可实时消耗日志条目。 此选项能聚合在每个请求期间发送给它的所有事件,日志定义属性 publishLogEvent 控制针对其他应用程序使用的情况引发实时事件。

要求 本文面向开发人员,并假定读者具备基本的本机代码编写技能。 不需要了解 IIS 管道;但最好是查看参考部分中列出的文章,详细了解所使用的方法和数据结构。 IIS 高级日志记录是 Internet Information Services (IIS) 7 的扩展,后者已不再可用。 我们建议使用 IIS 8.5 的增强型日志记录。 启用实时日志记录

实时日志记录是 IIS 高级日志记录中的每日志定义设置。 要为日志定义启用实时日志记录,请执行以下操作:

在 IIS 管理器中,打开高级日志记录功能。 单击“连接”窗格中的服务器,然后双击“主页”上的“高级日志记录”图标。

启用高级日志记录功能。 在“操作”窗格中,单击“启用高级日志记录”。

选择要为其启用实时日志记录的日志定义。

在 IIS 管理器中,在服务器、网站、目录或应用程序级别打开高级日志记录功能。 在“高级日志记录”功能页中,单击日志定义,然后在“操作”窗格中单击“编辑日志定义”。

选中“发布实时事件”复选框,为所选日志定义启用事件的实时日志记录。

编写实时使用事件的 IIS 模块,如下节所述。

编写 IIS 模块以使用实时事件

若要记录高级日志记录功能引发的实时事件,必须创建 IIS 模块。 本部分将回顾 IIS 跟踪基础结构,并在压缩的(压缩)文件夹中提供示例代码,以便创建一个可以用作引用的简单模块。

注意

示例代码仅供参考,尚未针对内存泄漏和其他问题进行测试。

IIS 跟踪基础结构

本部分介绍用于记录实时事件的一些 IIS 跟踪概念。

IGlobalTraceEventProvider::GetTraceEvent 方法

要使用高级日志记录引发的实时事件,必须为全局事件注册创建的 IIS 模块。 对于系统引发的每个事件,应调用 OnGlobalTraceEvent 方法。 注册此方法后便可以访问实时日志记录事件。 有关详细信息,请参阅 CGlobalModule::OnGlobalTraceEvent 方法。

数据结构 HTTP_TRACE_EVENT 结构

HTTP_TRACE_EVENT 结构构成了实时日志记录基础结构的主干。 实时日志记录信息以这种结构的形式传递。

struct HTTP_TRACE_EVENT{ LPCGUID pProviderGuid; DWORD dwArea; LPCGUID pAreaGuid; DWORD dwEvent; LPCWSTR pszEventName; DWORD dwEventVersion; DWORD dwVerbosity; LPCGUID pActivityGuid; LPCGUID pRelatedActivityGuid; DWORD dwTimeStamp; DWORD dwFlags; DWORD cEventItems; __field_ecount(cEventItems) HTTP_TRACE_EVENT_ITEM * pEventItems; };

有关此结构的详细信息,请参阅 HTTP_TRACE_EVENT 结构。

HTTP_TRACE_EVENT_ITEM 结构

HTTP_TRACE_EVENT 结构包含一个或多个 HTTP_TRACE_EVENT_ITEM 结构,具体取决于生成日志的日志定义中包含的日志记录字段数。

struct HTTP_TRACE_EVENT_ITEM{ LPCWSTR pszName; HTTP_TRACE_TYPE dwDataType; PBYTE pbData; DWORD cbData; LPCWSTR pszDataDescription; };

有关此结构的详细信息,请参阅 HTTP_TRACE_EVENT_ITEM 结构。

pProviderGuid

HTTP_TRACE_EVENT 结构包含 pProviderGuid 属性,这是一个包含提供程序标识符的 LPCGUID。 务必了解它的重要性。

如 CAnalyticsGlobalModule::OnGlobalTraceEvent 中所述,会针对系统引发的每个事件调用 OnGlobalTraceEvent。 这意味着必须从传入事件中筛选不需要的事件,以便只有感兴趣的事件(实时日志记录事件)可供使用。 可以使用 pProviderGuid 属性值 3C729B22-F9A9-4096-92A4-07E0DDF403EB 执行此操作。

// // {3C729B22-F9A9-4096-92A4-07E0DDF403EB} // static const GUID _LOGGING_PUBLISHING_GUID = { 0x3c729b22, 0xf9a9, 0x4096, { 0x92, 0xa4, 0x7, 0xe0, 0xdd, 0xf4, 0x3, 0xeb } }; ……………… ……………… if ((pTraceEvent->pProviderGuid != &_LOGGING_PUBLISHING_GUID) && (!IsEqualGUID(*(pTraceEvent->pProviderGuid), _LOGGING_PUBLISHING_GUID))) { goto Finished; }

示例代码使用此值来筛选掉不需要的事件。

代码示例

本部分显示演示本文前面介绍的实时日志记录概念的示例代码。 下载 CAnalyticsGlobalModule.zip,这是压缩(zip 格式)文件夹中示例代码的副本。

注意

示例代码仅供参考,尚未针对内存泄漏和其他问题进行测试。

CAnalyticsGlobalModule::OnGlobalTraceEvent // // {3C729B22-F9A9-4096-92A4-07E0DDF403EB} // static const GUID _LOGGING_PUBLISHING_GUID = { 0x3c729b22, 0xf9a9, 0x4096, { 0x92, 0xa4, 0x7, 0xe0, 0xdd, 0xf4, 0x3, 0xeb } }; // // This call is happening on the same thread (synchronous/blocking call) as // the call to RaiseTraceEvent, so bail a.s.a.p. if this isn't something // we want to handle, and minimize the work we do here // // GLOBAL_NOTIFICATION_STATUS CAnalyticsGlobalModule::OnGlobalTraceEvent( __in IGlobalTraceEventProvider * pProvider) { HRESULT hr = S_OK; IHttpContext * pHttpContext = NULL; HTTP_TRACE_EVENT * pTraceEvent = NULL; DBG_ASSERT(pProvider != NULL // // We only want to handle trace events that are raised for // logging purposes, so bail a.s.a.p. if this event isn't // for us // hr = pProvider->GetTraceEvent(&pTraceEvent if (FAILED(hr)) { TRACEHR(hr goto Finished; } if (pTraceEvent->pProviderGuid == NULL) { TRACEMSG(SS_DEFAULT, TRACE_LEVEL_INFORMATION, L"Not handling trace event - NULL value for provider GUID" goto Finished; } if ((pTraceEvent->pProviderGuid != &_LOGGING_PUBLISHING_GUID) && (!IsEqualGUID(*(pTraceEvent->pProviderGuid), _LOGGING_PUBLISHING_GUID))) { goto Finished; } // // We now need the HTTP context which is used to get the site info later // hr = pProvider->GetCurrentHttpRequestContext(&pHttpContext if (FAILED(hr)) { TRACEHR(hr goto Finished; } ProcessLogEvent(pTraceEvent, pHttpContext Finished: return GL_NOTIFICATION_CONTINUE; } ProcessLogEvent

ProcessLogEvent 方法会将日志记录数据复制到本地数据结构中,这样以后便可以使用此方法将数据推送到 Web 服务或数据库。

注意

不应处理请求本身中的数据,因为这可能会使请求对客户端的响应速度变慢。

注意

请注意 ProcessLogEvent 的代码,事件使用的内存可能是由 AllocateRequestMemory 分配的临时内存。 要取消阻止线程,应复制数据。

void ProcessLogEvent( __in HTTP_TRACE_EVENT * pHttpTraceEvent, __in IHttpContext * pHttpContext) { HRESULT hr = S_OK; DWORD cchName = 0; HTTP_TRACE_EVENT * pNewHttpTraceEvent = NULL; LPCSTR pszHostName = NULL; pNewHttpTraceEvent = new HTTP_TRACE_EVENT; if (pNewHttpTraceEvent == NULL) { goto Finished; } pNewHttpTraceEvent->pEventItems = new HTTP_TRACE_EVENT_ITEM[pHttpTraceEvent->cEventItems]; if (pNewHttpTraceEvent->pEventItems == NULL) { goto Finished; } ZeroMemory(pNewHttpTraceEvent->pEventItems, sizeof(HTTP_TRACE_EVENT_ITEM) * pHttpTraceEvent->cEventItems); for (DWORD ix = 0; ix < pHttpTraceEvent->cEventItems; ix++) { if (pHttpTraceEvent->pEventItems[ix].pszName == NULL) { pNewHttpTraceEvent->pEventItems[ix].pszName = NULL; pNewHttpTraceEvent->pEventItems[ix].cbData = 0; pNewHttpTraceEvent->pEventItems[ix].pbData = NULL; continue; } // // Copy the name of this event item // cchName = wcslen(pHttpTraceEvent->pEventItems[ix].pszName); pNewHttpTraceEvent->pEventItems[ix].pszName = new WCHAR[cchName + 1]; if (pNewHttpTraceEvent->pEventItems[ix].pszName == NULL) { goto Finished; } memcpy((VOID *)pNewHttpTraceEvent->pEventItems[ix].pszName, pHttpTraceEvent->pEventItems[ix].pszName, (cchName+1) * sizeof(WCHAR)); // // If there's no data to copy, mark it empty // if ((pHttpTraceEvent->pEventItems[ix].cbData == 0) || (pHttpTraceEvent->pEventItems[ix].pbData == NULL)) { pNewHttpTraceEvent->pEventItems[ix].cbData = 0; pNewHttpTraceEvent->pEventItems[ix].pbData = NULL; continue; } pNewHttpTraceEvent->pEventItems[ix].pbData = new BYTE[pHttpTraceEvent->pEventItems[ix].cbData]; if (pNewHttpTraceEvent->pEventItems[ix].pbData == NULL) { goto Finished; } memcpy(pNewHttpTraceEvent->pEventItems[ix].pbData, pHttpTraceEvent->pEventItems[ix].pbData, pHttpTraceEvent->pEventItems[ix].cbData); pNewHttpTraceEvent->pEventItems[ix].cbData = pHttpTraceEvent->pEventItems[ix].cbData; pNewHttpTraceEvent->pEventItems[ix].dwDataType = pHttpTraceEvent->pEventItems[ix].dwDataType; } // // At this point, you've copied the event into your memory and can now process your copy, queue it, etc. // // WriteEventViewerLog(pHttpTraceEvent->pszEventName); // Can write to eventViewer log to verify that event is processed... Finished: return; }

总结

在本演练中,我们回顾了 IIS 高级日志记录功能中的实时日志记录的工作原理,以及如何通过创建简单的 IIS 模块来实时使用日志记录数据。

参考 创建本机代码 HTTP 模块 IGlobalTraceEventProvider::GetTraceEvent 方法 HTTP_TRACE_EVENT 结构 HTTP_TRACE_EVENT_ITEM 结构 CGlobalModule::OnGlobalTraceEvent 方法 开发适用于 IIS 的本机 C\\C++ 模块 CAnalyticsGlobalModule.zip(示例代码的副本)


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3