Photon 1.0.0
Loading...
Searching...
No Matches
win_eventlog_sink.h
Go to the documentation of this file.
1// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
2// Distributed under the MIT License (http://opensource.org/licenses/MIT)
3
4// Writing to Windows Event Log requires the registry entries below to be present, with the following modifications:
5// 1. <log_name> should be replaced with your log name (e.g. your application name)
6// 2. <source_name> should be replaced with the specific source name and the key should be duplicated for
7// each source used in the application
8//
9// Since typically modifications of this kind require elevation, it's better to do it as a part of setup procedure.
10// The snippet below uses mscoree.dll as the message file as it exists on most of the Windows systems anyway and
11// happens to contain the needed resource.
12//
13// You can also specify a custom message file if needed.
14// Please refer to Event Log functions descriptions in MSDN for more details on custom message files.
15
16/*---------------------------------------------------------------------------------------
17
18Windows Registry Editor Version 5.00
19
20[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog<log_name>]
21
22[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog<log_name><source_name>]
23"TypesSupported"=dword:00000007
24"EventMessageFile"=hex(2):25,00,73,00,79,00,73,00,74,00,65,00,6d,00,72,00,6f,\
25 00,6f,00,74,00,25,00,5c,00,53,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,\
26 5c,00,6d,00,73,00,63,00,6f,00,72,00,65,00,65,00,2e,00,64,00,6c,00,6c,00,00,\
27 00
28
29-----------------------------------------------------------------------------------------*/
30
31#pragma once
32
35
37#include <winbase.h>
38
39#include <mutex>
40#include <string>
41#include <vector>
42
43namespace spdlog
44{
45 namespace sinks
46 {
47
48 namespace win_eventlog
49 {
50
51 namespace internal
52 {
53
55 {
56 HLOCAL hlocal_;
57
61
62 local_alloc_t(local_alloc_t const&) = delete;
64
66 {
67 if (hlocal_)
68 {
69 LocalFree(hlocal_);
70 }
71 }
72 };
73
75 struct win32_error : public spdlog_ex
76 {
78 static std::string format(std::string const& user_message, DWORD error_code = GetLastError())
79 {
80 std::string system_message;
81
82 local_alloc_t format_message_result{};
83 auto format_message_succeeded =
84 ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr,
85 error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&format_message_result.hlocal_, 0, nullptr);
86
87 if (format_message_succeeded && format_message_result.hlocal_)
88 {
89 system_message = fmt_lib::format(" ({})", (LPSTR)format_message_result.hlocal_);
90 }
91
92 return fmt_lib::format("{}: {}{}", user_message, error_code, system_message);
93 }
94
95 explicit win32_error(std::string const& func_name, DWORD error = GetLastError())
96 : spdlog_ex(format(func_name, error))
97 {
98 }
99 };
100
102 struct sid_t
103 {
104 std::vector<char> buffer_;
105
106 public:
108 {
109 }
110
112 static sid_t duplicate_sid(PSID psid)
113 {
114 if (!::IsValidSid(psid))
115 {
116 throw_spdlog_ex("sid_t::sid_t(): invalid SID received");
117 }
118
119 auto const sid_length{::GetLengthSid(psid)};
120
121 sid_t result;
122 result.buffer_.resize(sid_length);
123 if (!::CopySid(sid_length, (PSID)result.as_sid(), psid))
124 {
125 SPDLOG_THROW(win32_error("CopySid"));
126 }
127
128 return result;
129 }
130
132 SID* as_sid() const
133 {
134 return buffer_.empty() ? nullptr : (SID*)buffer_.data();
135 }
136
139 {
140 /* create and init RAII holder for process token */
141 struct process_token_t
142 {
143 HANDLE token_handle_ = INVALID_HANDLE_VALUE;
144 explicit process_token_t(HANDLE process)
145 {
146 if (!::OpenProcessToken(process, TOKEN_QUERY, &token_handle_))
147 {
148 SPDLOG_THROW(win32_error("OpenProcessToken"));
149 }
150 }
151
152 ~process_token_t()
153 {
154 ::CloseHandle(token_handle_);
155 }
156
157 } current_process_token(::GetCurrentProcess()); // GetCurrentProcess returns pseudohandle, no leak here!
158
159 // Get the required size, this is expected to fail with ERROR_INSUFFICIENT_BUFFER and return the token size
160 DWORD tusize = 0;
161 if (::GetTokenInformation(current_process_token.token_handle_, TokenUser, NULL, 0, &tusize))
162 {
163 SPDLOG_THROW(win32_error("GetTokenInformation should fail"));
164 }
165
166 // get user token
167 std::vector<unsigned char> buffer(static_cast<size_t>(tusize));
168 if (!::GetTokenInformation(current_process_token.token_handle_, TokenUser, (LPVOID)buffer.data(), tusize, &tusize))
169 {
170 SPDLOG_THROW(win32_error("GetTokenInformation"));
171 }
172
173 // create a wrapper of the SID data as stored in the user token
174 return sid_t::duplicate_sid(((TOKEN_USER*)buffer.data())->User.Sid);
175 }
176 };
177
178 struct eventlog
179 {
180 static WORD get_event_type(details::log_msg const& msg)
181 {
182 switch (msg.level)
183 {
184 case level::trace:
185 case level::debug:
186 return EVENTLOG_SUCCESS;
187
188 case level::info:
189 return EVENTLOG_INFORMATION_TYPE;
190
191 case level::warn:
192 return EVENTLOG_WARNING_TYPE;
193
194 case level::err:
195 case level::critical:
196 case level::off:
197 return EVENTLOG_ERROR_TYPE;
198
199 default:
200 return EVENTLOG_INFORMATION_TYPE;
201 }
202 }
203
204 static WORD get_event_category(details::log_msg const& msg)
205 {
206 return (WORD)msg.level;
207 }
208 };
209
210 } // namespace internal
211
212 /*
213 * Windows Event Log sink
214 */
215 template <typename Mutex>
216 class win_eventlog_sink : public base_sink<Mutex>
217 {
218 private:
221 std::string source_;
223
225 {
226 if (!hEventLog_)
227 {
228 hEventLog_ = ::RegisterEventSourceA(nullptr, source_.c_str());
229 if (!hEventLog_ || hEventLog_ == (HANDLE)ERROR_ACCESS_DENIED)
230 {
231 SPDLOG_THROW(internal::win32_error("RegisterEventSource"));
232 }
233 }
234
235 return hEventLog_;
236 }
237
238 protected:
239 void sink_it_(const details::log_msg& msg) override
240 {
241 using namespace internal;
242
243 bool succeeded;
244 memory_buf_t formatted;
245 base_sink<Mutex>::formatter_->format(msg, formatted);
246 formatted.push_back('\0');
247
248#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
249 wmemory_buf_t buf;
250 details::os::utf8_to_wstrbuf(string_view_t(formatted.data(), formatted.size()), buf);
251
252 LPCWSTR lp_wstr = buf.data();
253 succeeded = static_cast<bool>(::ReportEventW(event_log_handle(), eventlog::get_event_type(msg), eventlog::get_event_category(msg), event_id_,
254 current_user_sid_.as_sid(), 1, 0, &lp_wstr, nullptr));
255#else
256 LPCSTR lp_str = formatted.data();
257 succeeded = static_cast<bool>(::ReportEventA(event_log_handle(), eventlog::get_event_type(msg), eventlog::get_event_category(msg), event_id_,
258 current_user_sid_.as_sid(), 1, 0, &lp_str, nullptr));
259#endif
260
261 if (!succeeded)
262 {
263 SPDLOG_THROW(win32_error("ReportEvent"));
264 }
265 }
266
267 void flush_() override
268 {
269 }
270
271 public:
272 win_eventlog_sink(std::string const& source, DWORD event_id = 1000 /* according to mscoree.dll */)
273 : source_(source), event_id_(event_id)
274 {
275 try
276 {
278 }
279 catch (...)
280 {
281 // get_current_user_sid() is unlikely to fail and if it does, we can still proceed without
282 // current_user_sid but in the event log the record will have no user name
283 }
284 }
285
287 {
288 if (hEventLog_)
289 DeregisterEventSource(hEventLog_);
290 }
291 };
292
293 } // namespace win_eventlog
294
297
298 } // namespace sinks
299} // namespace spdlog
Definition core.h:1032
FMT_CONSTEXPR auto data() noexcept -> T *
Definition core.h:1102
Definition base_sink.h:22
Definition win_eventlog_sink.h:217
HANDLE event_log_handle()
Definition win_eventlog_sink.h:224
win_eventlog_sink(std::string const &source, DWORD event_id=1000)
Definition win_eventlog_sink.h:272
internal::sid_t current_user_sid_
Definition win_eventlog_sink.h:220
std::string source_
Definition win_eventlog_sink.h:221
~win_eventlog_sink()
Definition win_eventlog_sink.h:286
void sink_it_(const details::log_msg &msg) override
Definition win_eventlog_sink.h:239
DWORD event_id_
Definition win_eventlog_sink.h:222
void flush_() override
Definition win_eventlog_sink.h:267
HANDLE hEventLog_
Definition win_eventlog_sink.h:219
Definition common.h:298
#define SPDLOG_NOEXCEPT
Definition common.h:69
#define SPDLOG_CONSTEXPR
Definition common.h:70
#define SPDLOG_THROW(ex)
Definition common.h:108
@ critical
Definition common.h:239
@ err
Definition common.h:238
@ warn
Definition common.h:237
@ info
Definition common.h:236
@ off
Definition common.h:240
@ trace
Definition common.h:234
@ debug
Definition common.h:235
Definition async.h:26
void error(format_string_t< Args... > fmt, Args &&... args)
Definition spdlog.h:181
fmt::basic_string_view< char > string_view_t
Definition common.h:172
SPDLOG_INLINE void throw_spdlog_ex(const std::string &msg, int last_errno)
Definition common-inl.h:75
fmt::basic_memory_buffer< char, 250 > memory_buf_t
Definition common.h:173
#define NULL
Definition strtod.cpp:30
Definition log_msg.h:14
level::level_enum level
Definition log_msg.h:23
Definition win_eventlog_sink.h:179
static WORD get_event_category(details::log_msg const &msg)
Definition win_eventlog_sink.h:204
static WORD get_event_type(details::log_msg const &msg)
Definition win_eventlog_sink.h:180
SPDLOG_CONSTEXPR local_alloc_t() SPDLOG_NOEXCEPT
Definition win_eventlog_sink.h:58
~local_alloc_t() SPDLOG_NOEXCEPT
Definition win_eventlog_sink.h:65
local_alloc_t & operator=(local_alloc_t const &)=delete
HLOCAL hlocal_
Definition win_eventlog_sink.h:56
Definition win_eventlog_sink.h:103
std::vector< char > buffer_
Definition win_eventlog_sink.h:104
static sid_t duplicate_sid(PSID psid)
Definition win_eventlog_sink.h:112
sid_t()
Definition win_eventlog_sink.h:107
SID * as_sid() const
Definition win_eventlog_sink.h:132
static sid_t get_current_user_sid()
Definition win_eventlog_sink.h:138
static std::string format(std::string const &user_message, DWORD error_code=GetLastError())
Definition win_eventlog_sink.h:78
win32_error(std::string const &func_name, DWORD error=GetLastError())
Definition win_eventlog_sink.h:95
source
Definition tag_strings.h:83