forked from microsoft/CLRInstrumentationEngine
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEventLoggingBase.cpp
221 lines (182 loc) · 6.44 KB
/
EventLoggingBase.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "stdafx.h"
#include "EventLoggingBase.h"
using namespace CommonLib;
CEventLoggingBase::CEventLoggingBase() :
// We use a small spin count here for when lock contention occurs.
// Since this lock guards reads and writes to the buffer, contention is short.
// This spincount allows the thread to spin briefly in hopes that the lock is
// released quickly and we avoid context switching.
m_cs(10),
m_eventQueueLength(0),
// Event used to tell the processing thread to process the current items
// on the queue.
m_hEventQueueProcessEvent(FALSE, FALSE), // auto-reset, initially unsignaled
m_hEventSource(nullptr),
m_isShutdown(false)
{
}
CEventLoggingBase::~CEventLoggingBase()
{
}
HRESULT CEventLoggingBase::InitializeEventSource(_In_ LPCWSTR wszEventSourceName)
{
HRESULT hr = S_OK;
m_hEventSource = RegisterEventSource(NULL, wszEventSourceName);
if (!m_hEventSource)
{
return HRESULT_FROM_WIN32(GetLastError());
}
HANDLE hEventQueueThread = CreateThread(
nullptr, // default security
0, // default stack size
LogEventThreadProc, // name of the thread function
this, // instance of CEventLogSink
0, // default startup flags
nullptr // thread id
);
if (nullptr == hEventQueueThread)
{
return HRESULT_FROM_WIN32(GetLastError());
}
m_hEventQueueThread.Attach(hEventQueueThread);
return S_OK;
}
//static
DWORD WINAPI CEventLoggingBase::LogEventThreadProc(_In_ LPVOID lpParam)
{
CEventLoggingBase* pThis = static_cast<CEventLoggingBase*>(lpParam);
// Since ReportEvent requires CoInitialize(NULL) due to their detouring logic of eventlogging messages
// and since we live inside the user's process (which is not guaranteed to be STA), we must run this logging inside a separate thread.
// S_OK indicates success
// S_FALSE indicates already initialized
HRESULT hr;
if (FAILED(hr = CoInitialize(nullptr)))
{
return HRESULT_CODE(hr);
}
bool fShutdown = false;
while (!fShutdown)
{
// Wait to be signaled
DWORD dwWaitResult = WaitForSingleObject(
pThis->m_hEventQueueProcessEvent,
INFINITE);
if (dwWaitResult != WAIT_OBJECT_0)
{
return GetLastError();
}
// Get copy of queued items and check if shutdown requested
std::queue<EventLogItem> eventQueue;
// Block scope used to release critical section before processing queue items.
{
CCriticalSectionHolder holder(&pThis->m_cs);
// Swap contents of queue
eventQueue.swap(pThis->m_eventQueue);
// Reset total queue length; since it was swapped with empty queue
// the starting length is zero.
pThis->m_eventQueueLength = 0;
// Check if shutdown requested
fShutdown = pThis->m_isShutdown;
}
// Report each item in the swapped queue
while (!eventQueue.empty())
{
EventLogItem& logItem = eventQueue.front();
// Ignore empty items
if (!logItem.tsEventLog.empty())
{
pThis->LogEvent(logItem);
}
eventQueue.pop();
}
}
CoUninitialize();
return 0;
}
HRESULT CEventLoggingBase::TerminateEventSource()
{
// Signal event source thread to shutdown.
// Block scope used to release critical section before end of method.
{
CCriticalSectionHolder holder(&m_cs);
// Signal shutdown first
m_isShutdown = true;
// Signal thread to process items
if (!SetEvent(m_hEventQueueProcessEvent))
{
return HRESULT_FROM_WIN32(GetLastError());
}
}
// Allow thread to drain the queue
if (m_hEventQueueThread)
{
WaitForSingleObject(m_hEventQueueThread, 15 * 1000 /* 15 second timeout */);
}
// Block scope used to release critical section before end of method.
{
CCriticalSectionHolder holder(&m_cs);
if (m_hEventSource)
{
if (!DeregisterEventSource(m_hEventSource))
{
return HRESULT_FROM_WIN32(GetLastError());
}
}
}
return S_OK;
}
void CEventLoggingBase::LogEvent(_In_ const tstring& tsEntry)
{
EventLogItem eventLogItem(EVENTLOG_ERROR_TYPE, tsEntry);
LogEvent(eventLogItem);
}
void CEventLoggingBase::LogEvent(_In_ const EventLogItem& eventLogItem)
{
if (m_hEventSource)
{
// Each event source can use event ids 0-65535. An event id is used to associate with an
// event description registered in the registry by a message file. Since we don't have
// access to the registry on Antares and the event description wouldn't be very useful
// (we just spit out the error messages of any instrumentation method), the event id
// is arbitrarily set.
const DWORD dwEventId = 1000;
LPCWSTR wszEntry = eventLogItem.tsEventLog.c_str();
// Write to event log. Note: if this fails, we're out of luck
const BOOL fReport = ReportEvent(
m_hEventSource, // handle to event log
eventLogItem.wEventType, // event type
0, // event category
dwEventId, // event id
nullptr, // SID of the current user
1, // number of strings in szStringData
0, // size of binary data in hrErr
&wszEntry, // string data in the event
nullptr // binary data in the event
);
}
}
HRESULT CEventLoggingBase::AppendToQueue(_In_ WORD wEventType, _In_ tstring tsEventLog)
{
CCriticalSectionHolder holder(&m_cs);
if (!m_isShutdown)
{
// Aribtrarily allow max of 64KB
if (m_eventQueueLength < 64 * (1 << 10) && !tsEventLog.empty())
{
EventLogItem logItem(wEventType, tsEventLog);
m_eventQueue.push(logItem);
m_eventQueueLength += tsEventLog.length();
if (!SetEvent(m_hEventQueueProcessEvent))
{
return HRESULT_FROM_WIN32(GetLastError());
}
}
else
{
return E_NOT_SUFFICIENT_BUFFER;
}
}
return S_OK;
}