编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

spdlog与Windows事件日志实操(windows 事件日志)

wxchong 2024-10-11 19:10:50 开源技术 12 ℃ 0 评论

spdlog大家并陌生,是一个好用且易扩展的开源日志模块。它提供了很多默认的sink,省去很多功夫。本篇就讲讲通过它使用windows event log来记录日志时碰到的一些细节问题吧。

事件日志调用方式,类似下面:

std::shared_ptr<spdlog::logger> logger;
logger->sinks.push_back(std::sharedPtr<spdlog::sinks::win_eventlog_sink_mt>("Event Source", 1000));

其事件日志模块在sinks\win_eventlog_sink.h文件中。从中我们可以看到,初始化时它会调用Win32 API RegisterEventSource注册事件源,在写日志时调用ReportEvent通知系统事件日志服务,最后退出时调用DeregisterEventSource注销事件源。

template<typename Mutex>
class win_eventlog_sink : public base_sink<Mutex>
{
  ......
    HANDLE event_log_handle()
    {
        if (!hEventLog_)
        {
            hEventLog_ = ::RegisterEventSourceA(nullptr, source_.c_str());
            if (!hEventLog_ || hEventLog_ == (HANDLE)ERROR_ACCESS_DENIED)
            {
                SPDLOG_THROW(internal::win32_error("RegisterEventSource"));
            }
        }

        return hEventLog_;
    }

protected:
    void sink_it_(const details::log_msg &msg) override
    {
			......
      
      LPCSTR lp_str = formatted.data();
        succeeded = ::ReportEventA(event_log_handle(), eventlog::get_event_type(msg), eventlog::get_event_category(msg), event_id_,
            current_user_sid_.as_sid(), 1, 0, &lp_str, nullptr);
      ......
    }

public:
    win_eventlog_sink(std::string const &source, WORD event_id = 1000 /* according to mscoree.dll */)
        : source_(source)
        , event_id_(event_id)
    {
      ......
    }

    ~win_eventlog_sink()
    {
        if (hEventLog_)
            DeregisterEventSource(hEventLog_);
    }
};

实操中,碰到的细节问题有几个:

  1. 自定义事件源

默认情况下如果不指定事件源或找不到事件源,日志会写到系统的应用程序日志下,如下图位置:

  1. 如果要显示到系统事件查看器自定义的目录下,就需要在注册表中注册事件源,如下图注册表中添加了一个test日志,有两个事件源:

注册成功后,可在日志查看器的test目录下查看日志信息:

3.事件日志查看器是通过注册表中指定的DLL文件来解析日志的。前面"2."图中EventMessageFile指定了DLL的路径, TypeSupported表示支持信息,告警,严重等类型的日志。DLL文件是由微软定义的.mc文件编译生成的,本质上是一个仅含资源的DLL。如下是一个典型的的mc文件:

MessageIdTypedef=DWORD


SeverityNames=(

Success=0x0:STATUS_SEVERITY_SUCCESS

Informational=0x1:STATUS_SEVERITY_INFORMATIONAL

Warning=0x2:STATUS_SEVERITY_WARNING

Error=0x3:STATUS_SEVERITY_ERROR

)


LanguageNames=(

English=0x409:MSG00409

SimplifiedChinese=0x804:MSG00804

)


MessageId=1

SymbolicName=HS_Debug

Language=English

Debug level

.

Language=SimplifiedChinese

调试级别

.

MessageId=2

SymbolicName=HS_Info

Language=English

Info level

.

Language=SimplifiedChinese

信息级别

.

MessageId=3

SymbolicName=HS_Warn

Language=English

Warn level

.

Language=SimplifiedChinese

警告级别

.

MessageId=4

SymbolicName=HS_Error

Language=English

Error level

.

Language=SimplifiedChinese

错误级别

.

MessageId=1000

SymbolicName=HS_Service

Language=English

Log from hsservice:%r%n

%1

.

Language=SimplifiedChinese

来自hsservice的日志:%r

%1

.

要注意的是:

  • SymbolicName必须和注册表中的键值对应,否则事件日志查看器在日志项解析那里会有找不到事件源的提示
  • 句号圆点是用来分隔不同语言的日志信息
  • 如果不想对任务类别也定义一个mc文件并生成一个资源DLL, 那么任务类别(Category)定义可以和普通消息定义到一起,但消息ID不能重复(上面的mc文件就是)。要注意任务类别ID一般从1开始要连续。
  • mc文件必须末尾必须换行,否则可能提示编译错误
  • 4.DLL的编译和生成。有了上述mc文件后,可启动visual studio编译环境后,运行mc, rc,link工具生成DLL,如:

    call "%programfiles%\Microsoft Visual Studio\2022\Professional\VC\Auxiliary\Build\vcvars64.bat" x64

    mc.exe hsevtlog.mc

    rc.exe /r hsevtlog.rc

    link /MACHINE:x64 -dll -noentry -out:hsevtlog.dll hsevtlog.res

    Tags:

    本文暂时没有评论,来添加一个吧(●'◡'●)

    欢迎 发表评论:

    最近发表
    标签列表