Event Tracing for Windows(ETW) - 代码示例:创建会话和启动基于清单的提供者 译(8)

Example that Creates a Session and Enables a Manifest-based or Classic Provider

原文链接
作者:Microsoft
译者:塔塔塔塔塔

以下示例显示了如何启动跟踪会话,启用基于清单的提供程序或经典提供程序,禁用提供程序然后停止会话。

#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <strsafe.h>
#include <wmistr.h>
#include <evntrace.h>

#define LOGFILE_PATH L"<FULLPATHTOLOGFILE.etl>"
#define LOGSESSION_NAME L"My Event Trace Session"

// 根据GUID确认你的Session
// 记住要创建自己的会话GUID

// {AE44CB98-BD11-4069-8093-770EC9258A12}
static const GUID SessionGuid = 
{ 0xae44cb98, 0xbd11, 0x4069, { 0x80, 0x93, 0x77, 0xe, 0xc9, 0x25, 0x8a, 0x12 } };

// 标识所需的提供程序的GUID
// 启用您的会话

// {D8909C24-5BE9-4502-98CA-AB7BDC24899D}
static const GUID ProviderGuid = 
{ 0xd8909c24, 0x5be9, 0x4502, {0x98, 0xca, 0xab, 0x7b, 0xdc, 0x24, 0x89, 0x9d } };

void wmain(void)
{
    ULONG status = ERROR_SUCCESS;
    TRACEHANDLE SessionHandle = 0;
    EVENT_TRACE_PROPERTIES* pSessionProperties = NULL;
    ULONG BufferSize = 0;
    BOOL TraceOn = TRUE;

    // 创建一个Session属性的内存空间
    // 这内存空间必须足够大去包含日志文件名称和Session名称
    //  这些文件名和会话名将附加到会话属性结构的末尾
    
    BufferSize = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(LOGFILE_PATH) + sizeof(LOGSESSION_NAME);
    pSessionProperties = (EVENT_TRACE_PROPERTIES*) malloc(BufferSize);    
    if (NULL == pSessionProperties)
    {
        wprintf(L"Unable to allocate %d bytes for properties structure.\n", BufferSize);
        goto cleanup;
    }
    
    // 设置会话属性。您只需将日志文件名附加到属性结构中
    // StartTrace函数为您添加Session名称
    
    ZeroMemory(pSessionProperties, BufferSize);
    pSessionProperties->Wnode.BufferSize = BufferSize;
    pSessionProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
    pSessionProperties->Wnode.ClientContext = 1; //QPC clock resolution
    pSessionProperties->Wnode.Guid = SessionGuid; 
    pSessionProperties->LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL;
    pSessionProperties->MaximumFileSize = 1;  // 1 MB
    pSessionProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
    pSessionProperties->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(LOGSESSION_NAME); 
    StringCbCopy((LPWSTR)((char*)pSessionProperties + pSessionProperties->LogFileNameOffset), sizeof(LOGFILE_PATH), LOGFILE_PATH);

    // 创建Session

    status = StartTrace((PTRACEHANDLE)&SessionHandle, LOGSESSION_NAME, pSessionProperties);
    if (ERROR_SUCCESS != status)
    {
        wprintf(L"StartTrace() failed with %lu\n", status);
        goto cleanup;
    }

    // Enable the providers that you want to log events to your session.

    status = EnableTraceEx2(
        SessionHandle,
        (LPCGUID)&ProviderGuid,
        EVENT_CONTROL_CODE_ENABLE_PROVIDER,
        TRACE_LEVEL_INFORMATION,
        0,
        0,
        0,
        NULL
        );

    if (ERROR_SUCCESS != status)
    {
        wprintf(L"EnableTrace() failed with %lu\n", status);
        TraceOn = FALSE;
        goto cleanup;
    }

    wprintf(L"Run the provider application. Then hit any key to stop the session.\n");
    _getch();

cleanup:

    if (SessionHandle)
    {
        if (TraceOn)
        {
            status = EnableTraceEx2(
                SessionHandle,
                (LPCGUID)&ProviderGuid,
                EVENT_CONTROL_CODE_DISABLE_PROVIDER,
                TRACE_LEVEL_INFORMATION,
                0,
                0,
                0,
                NULL
                );
        }

        status = ControlTrace(SessionHandle, LOGSESSION_NAME, pSessionProperties, EVENT_TRACE_CONTROL_STOP);

        if (ERROR_SUCCESS != status)
        {
            wprintf(L"ControlTrace(stop) failed with %lu\n", status);
        }
    }

    if (pSessionProperties)
    {
        free(pSessionProperties);
        pSessionProperties = NULL;
    }
}

译者叙

参看Microsoft的Sample时要注意一些小问题。

易错点1: 错误代码24

错误提示:The program issued a command but the command length is incorrect. 命令长度不正确。

#define PATH L"123" 这样的Path长度是3+1 有一个EOF终止符。作者热衷与string,凡是遇到char*都尽可能的用string代替了,所以会遇到分配内存不足的情况。我在下面用代码进行了描述。关于Sizeof(String)=40是因为std::string内部其实是basic_string而sizeof是得到该类的大小,字符串是以char*的方式存在到其成员变量中,所以无论多长的字符串只会占basic_string4字节,这样描述可能会有歧义但是意会即可。

File: etwcontroller.cpp
#define LOGFILE_PATH L"<FULLPATHTOLOGFILE.etl>"
#define LOGSESSION_NAME L"My Event Trace Session"
bool EtwController::CreateSession(Session *session)
    {
        ULONG status = ERROR_SUCCESS;
        TRACEHANDLE SessionHandle = 0;
        EVENT_TRACE_PROPERTIES* pSessionProperties = NULL;
        ULONG BufferSize = 0;
        ULONG BufferSize2 = 0;
        BOOL TraceOn = TRUE;
        std::cout << "sizeof(session->file.name_) : " << sizeof(session->file.name_) << std::endl;
        std::cout << "session->file.name_.length() : " << session->file.name_.length() << std::endl;
        std::cout << "sizeof(session->name_) : " << sizeof(session->name_) << std::endl;
        std::cout << "session->name_.length() : " << session->name_.length() << std::endl;
        std::cout << "sizeof(LOGFILE_PATH) : " << sizeof(LOGFILE_PATH) << std::endl;
        std::cout << "sizeof(LOGSESSION_NAME) : " << sizeof(LOGSESSION_NAME) << std::endl;
        BufferSize = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(session->file.name_) + sizeof(session->name_);
        BufferSize2 = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(LOGFILE_PATH) + sizeof(LOGSESSION_NAME);
        pSessionProperties = (EVENT_TRACE_PROPERTIES*)malloc(BufferSize);
		... ...
        return false;
    }
    
File: etwtest.cpp
int main()
{
    auto dll = LoadLibrary("etw-log.dll");

    APICreateSession f = (APICreateSession)GetProcAddress(dll, "CreateSession");
    
    logs::Session session("My Event Trace Session","<FULLPATHTOLOGFILE.etl><FULLPATHTOLOGFILE.etl>","123");
    std::cout << "session name :" << session.name_ << std::endl;
    std::cout << "log file name :" << session.file.name_ << std::endl;
    f(&session);
    return 0;
}

Output:
session name :My Event Trace Session
log file name :<FULLPATHTOLOGFILE.etl><FULLPATHTOLOGFILE.etl><FULLPATHTOLOGFILE.etl>
sizeof(session->file.name_) : 40
session->file.name_.length() : 69
sizeof(session->name_) : 40
session->name_.length() : 22
sizeof(LOGFILE_PATH) : 24
sizeof(LOGSESSION_NAME) : 23
易错点2: 错误代码123

错误提示: The filename, directory name, or volume label syntax is incorrect. 文件名,目录名称或卷标签语法不正确。

File: etwcontroller.cpp
#define LOGFILE_PATH L"<FULLPATHTOLOGFILE.etl>"
#define LOGSESSION_NAME L"My Event Trace Session"

File: etwtest.cpp
logs::Session session("My Event Trace Session","<FULLPATHTOLOGFILE.etl>",guid);

这里官方给出的代码中有尖括号,不明白其用意,实际程序是不需要<>这个符号的。

易错点3: 错误代码183

Cannot create a file when that file already exists. 该文件已存在时无法创建该文件。
这里会有两种情况出现该错误:

  • 日志文件真的存在无法创建。
  • Session存在无法创建。

这个问题很容易在调试中出现,避免的办法一:

  • 删除已存在的文件
  • 关闭存在的Session

避免的办法二:

  • 按时间创建文件或文件夹,保证每次创建不会重名。
  • 不要强行退出应用,如果出现183错误可在程序中针对183错误进行停止Session。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值