30 struct EventLogStoreEntry {
35 DateTimeOffset dtTimeGenerated;
47 : m_sMessage(sMessage), m_eEntryType(eType), m_iInstanceId(iInstanceId), m_sSource(sSource), m_dtTimeGenerated(dtTimeGenerated) {
51 : m_sLogName(
"Application"), m_sMachineName(
"."), m_sSource(
"") {
55 : m_sLogName(sLogName), m_sMachineName(
"."), m_sSource(
"") {
56 if (m_sLogName.IsEmpty()) m_sLogName =
"Application";
60 : m_sLogName(sLogName), m_sMachineName(sMachineName), m_sSource(
"") {
61 if (m_sLogName.IsEmpty()) m_sLogName =
"Application";
62 if (m_sMachineName.IsEmpty()) m_sMachineName =
".";
66 : m_sLogName(sLogName), m_sMachineName(sMachineName), m_sSource(sSource) {
67 if (m_sLogName.IsEmpty()) m_sLogName =
"Application";
68 if (m_sMachineName.IsEmpty()) m_sMachineName =
".";
84 EventLogEntry EventLog::ParseWin32Record(
const PEVENTLOGRECORD pRec) {
89 if (pRec->NumStrings > 0) {
91 sMsg =
String(sNarrowMsg.c_str());
95 int64_t iTicks = ((int64_t)pRec->TimeGenerated + 62135596800LL) * 10000000LL;
96 return EventLogEntry(sMsg, eType, (
int)pRec->EventID, String(sSrc.c_str()), DateTimeOffset(iTicks));
99 void EventLog::ProcessWin32EventBuffer(BYTE* buffer, DWORD dwBytesRead, Collections::Generic::List<EventLogEntry>& lstEntries) {
102 while (dwOffset < dwBytesRead) {
103 PEVENTLOGRECORD pRec = (PEVENTLOGRECORD)&buffer[dwOffset];
104 lstEntries.Add(ParseWin32Record(pRec));
105 dwOffset += pRec->Length;
115 return EVENTLOG_INFORMATION_TYPE;
121 if (dwErr == ERROR_ACCESS_DENIED) {
131 std::wstring wLogName(sStdLogName.begin(), sStdLogName.end());
132 HANDLE h = ::OpenEventLogW(NULL, wLogName.c_str());
134 DWORD dwErr = ::GetLastError();
136 if (dwErr == ERROR_FILE_NOT_FOUND || dwErr == ERROR_PATH_NOT_FOUND)
throw ArgumentException(
"EventLog not found: " + sLogName);
145 DWORD dwBytesRead = 0, dwNeeded = 0;
146 BYTE buffer[0x10000];
147 while (::ReadEventLogW(hEventLog, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_BACKWARDS_READ, 0, buffer,
sizeof(buffer), &dwBytesRead, &dwNeeded)) {
148 ProcessWin32EventBuffer(buffer, dwBytesRead, lstEntries);
150 ::CloseEventLog(hEventLog);
156 std::wstring wSource(sStdSource.begin(), sStdSource.end());
157 HANDLE h = ::RegisterEventSourceW(NULL, wSource.c_str());
159 DWORD dwErr = ::GetLastError();
170 std::wstring wMsg(sStdMsg.begin(), sStdMsg.end());
171 LPCWSTR pStrings[1] = { wMsg.c_str() };
173 DWORD dwErr = ::GetLastError();
174 ::DeregisterEventSource(hEventLog);
178 bool EventLog::CreateWin32EventSource(
const String& sSource,
const String& sLogName) {
180 std::string sStdLog(sLogName.GetRawString() ? sLogName.GetRawString() :
"");
181 std::string sStdSrc(sSource.GetRawString() ? sSource.GetRawString() :
"");
182 std::wstring wSubKey = L
"SYSTEM\\CurrentControlSet\\Services\\EventLog\\" +
183 std::wstring(sStdLog.begin(), sStdLog.end()) + L
"\\" +
184 std::wstring(sStdSrc.begin(), sStdSrc.end());
186 LONG lRes = ::RegCreateKeyExW(HKEY_LOCAL_MACHINE, wSubKey.c_str(), 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL);
187 if (lRes == ERROR_SUCCESS) {
191 if (lRes == ERROR_ACCESS_DENIED) {
192 throw UnauthorizedAccessException(
"Access denied creating EventLog source in registry under HKLM. Administrator privileges required.");
197 bool EventLog::Win32SourceExists(
const String& sSource) {
199 std::string sStdSrc(sSource.GetRawString() ? sSource.GetRawString() :
"");
200 const wchar_t* subKeys[] = { L
"Application", L
"System", L
"Security" };
201 for (
const wchar_t* pLog : subKeys) {
202 std::wstring wSubKey = L
"SYSTEM\\CurrentControlSet\\Services\\EventLog\\" + std::wstring(pLog) + L
"\\" + std::wstring(sStdSrc.begin(), sStdSrc.end());
204 if (::RegOpenKeyExW(HKEY_LOCAL_MACHINE, wSubKey.c_str(), 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
212 void EventLog::DeleteWin32EventSource(
const String& sSource) {
214 const wchar_t* subKeys[] = { L
"Application", L
"System", L
"Security" };
215 for (
const wchar_t* pLog : subKeys) {
216 std::wstring wSubKey = L
"SYSTEM\\CurrentControlSet\\Services\\EventLog\\" + std::wstring(pLog) + L
"\\" + std::wstring(sSource.GetRawString(), sSource.GetRawString() + sSource.GetLength());
217 LONG lRes = ::RegDeleteKeyW(HKEY_LOCAL_MACHINE, wSubKey.c_str());
218 if (lRes == ERROR_ACCESS_DENIED) {
219 throw UnauthorizedAccessException(
"Access denied deleting EventLog source from registry under HKLM. Administrator privileges required.");
224 void EventLog::WriteLinuxSyslog(
const String& sSource,
const String& sMessage,
EventLogEntryType eType,
int iEventID) {
226 int iPriority = LOG_INFO;
227 const char* szLevelStr =
"Information";
232 const char* pSrc = sSource.GetRawString() ? sSource.GetRawString() :
"";
233 const char* pMsg = sMessage.GetRawString() ? sMessage.GetRawString() :
"";
234 openlog(pSrc, LOG_PID | LOG_CONS, LOG_USER);
235 syslog(iPriority,
"[%s] [EventID %d] %s", szLevelStr, iEventID, pMsg);
239 EventLogEntry EventLog::ParseSyslogLine(
const String& sLine) {
242 std::string line = sLine.GetRawString() ? sLine.GetRawString() :
"";
244 if (line.find(
"error") != std::string::npos || line.find(
"ERR") != std::string::npos || line.find(
"err") != std::string::npos || line.find(
"Error") != std::string::npos) {
246 }
else if (line.find(
"warn") != std::string::npos || line.find(
"WARN") != std::string::npos || line.find(
"Warn") != std::string::npos) {
251 size_t posId = line.find(
"[EventID ");
252 if (posId != std::string::npos) {
253 iEventId = std::atoi(line.c_str() + posId + 9);
259 void EventLog::ReadLinuxSyslogFile(
const String& sFilePath, Collections::Generic::List<EventLogEntry>& lstEntries) {
261 std::ifstream infile(sFilePath.GetRawString() ? sFilePath.GetRawString() :
"");
262 if (!infile.is_open())
return;
265 while (std::getline(infile, line)) {
266 if (line.empty())
continue;
267 lstEntries.Add(ParseSyslogLine(
String(line.c_str())));
271 void EventLog::ReadLinuxSyslog(Collections::Generic::List<EventLogEntry>& lstEntries) {
273 const char* syslogPaths[] = {
"/var/log/syslog",
"/var/log/messages" };
274 for (
const char* path : syslogPaths) {
276 if (stat(path, &st) == 0) {
277 ReadLinuxSyslogFile(path, lstEntries);
289 ReadWin32EventLog(m_sLogName, lstEntries);
291 ReadLinuxSyslog(lstEntries);
296 for (
const auto& entry : it->second) {
297 lstEntries.
Add(
EventLogEntry(entry.sMessage, entry.eType, entry.iInstanceId, entry.sSource, entry.dtTimeGenerated));
312 String sEffectiveSource = m_sSource.
IsEmpty() ? m_sLogName : m_sSource;
313 WriteEntry(sEffectiveSource, sMessage, eType, iEventID);
326 String sTargetLog =
"Application";
329 sTargetLog = itSource->second;
345 WriteWin32EventLog(sSource, sMessage, eType, iEventID);
347 WriteLinuxSyslog(sSource, sMessage, eType, iEventID);
351 RecordInternalLogEntry(sSource, sMessage, eType, iEventID);
360 if (sSource.
IsEmpty())
return false;
362 if (Win32SourceExists(sSource))
return true;
374 CreateWin32EventSource(sSource, sEffectiveLog);
394 void EventLog::PurgeSourcesForLog(
const String& sLogName) {
396 std::vector<String> vSourcesToRemove;
398 if (pair.second == sLogName) vSourcesToRemove.push_back(pair.first);
400 for (
const auto& sSource : vSourcesToRemove) {
410 std::wstring wLogKey = L
"SYSTEM\\CurrentControlSet\\Services\\EventLog\\" + std::wstring(sStdLog.begin(), sStdLog.end());
411 ::RegDeleteKeyW(HKEY_LOCAL_MACHINE, wLogKey.c_str());
415 PurgeSourcesForLog(sLogName);
427 DeleteWin32EventSource(sSource);
440 return Exists(sLogName,
".");
445 if (sLogName.
IsEmpty())
return false;
448 std::wstring wSubKey = L
"SYSTEM\\CurrentControlSet\\Services\\EventLog\\" + std::wstring(sStdLog.begin(), sStdLog.end());
450 if (::RegOpenKeyExW(HKEY_LOCAL_MACHINE, wSubKey.c_str(), 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
455 if (sLogName ==
"Application" || sLogName ==
"System")
return true;
478 std::string sStdLog(m_sLogName.GetRawString() ? m_sLogName.GetRawString() :
"");
479 std::wstring wLog(sStdLog.begin(), sStdLog.end());
480 HANDLE hLog = ::OpenEventLogW(NULL, wLog.c_str());
482 ::ClearEventLogW(hLog, NULL);
483 ::CloseEventLog(hLog);
Defines the exception thrown when an invalid argument is provided to a method.
Provides information about, and means to manipulate, the current environment and platform.
Provides static methods for the creation, copying, deletion, moving, and opening of a single file.
Defines the exception thrown when a method call is invalid for the object's current state.
Utility routines for high-performance UTF-8, UTF-16, and wide-character string conversions.
Provides an abstraction for time, timestamps, and elapsed time calculation.
The exception that is thrown when the operating system denies access because of an I/O error or a spe...
Exception thrown for a Win32 or platform-native error code.
ArgumentException(const String &sMessage)
Initializes a new instance of the ArgumentException class with a specified error message.
Represents a strongly typed list of objects accessible by index.
void Add(const T &item)
Adds an object to the end of the List.
Exception thrown for a Win32 or POSIX platform error code.
Represents a point in time, typically expressed as a date and time of day, relative to Coordinated Un...
static DateTimeOffset Now()
Gets a DateTimeOffset object that is set to the current date and time on the current computer,...
Encapsulates a single record in the event log.
EventLogEntry()
Default constructor initializing an empty entry.
static void DeleteEventSource(const String &sSource)
Removes an event source registration from the local computer.
void Close()
Closes the event log and releases read/write handles.
EventLog()
Initializes a new instance of the EventLog class targeting the Application log.
static Collections::Generic::List< EventLog > GetEventLogs()
Searches for all event logs on the local computer.
static void Delete(const String &sLogName)
Removes an event log from the local computer.
void Clear()
Removes all entries from the event log.
void WriteEntry(const String &sMessage)
Writes an information entry with the specified message to the event log.
static bool SourceExists(const String &sSource)
Determines whether the specified event source is registered on the local computer.
virtual ~EventLog()
Virtual destructor.
static void CreateEventSource(const String &sSource, const String &sLogName)
Establishes the specified source name as a valid event source for writing to a log.
static bool Exists(const String &sLogName)
Determines whether the log exists on the local computer.
Collections::Generic::List< EventLogEntry > GetEntries() const
Gets the contents of the event log as a list of entries.
Represents text as a sequence of UTF-8 code units with culture-invariant operations.
String()
Initializes a new instance of the String class to an empty string.
const char * GetRawString() const
The exception that is thrown when the operating system denies access because of an I/O or security er...
UnauthorizedAccessException()
Initializes a new instance of the UnauthorizedAccessException class with a default message.
static std::string WCharToUtf8(const wchar_t *pWStr)
Converts a null-terminated UTF-16 wchar_t string into a UTF-8 std::string.
static std::map< String, std::vector< EventLogStoreEntry > > s_mapLogEntries
static std::map< String, String > s_mapSourceToLog
static std::mutex s_mtxEventLog
EventLogEntryType
Defines the event type of an event log entry.
@ Warning
A warning event indicating a potential problem.
@ Error
An error event indicating significant problem.
@ Information
An informational event representing successful milestones.
@ FailureAudit
An audit event tracking failed security access.
@ SuccessAudit
An audit event tracking successful security access.
static WORD MapEventLogEntryTypeToWin32(EventLogEntryType eType)
static void ValidateWin32ReportResult(BOOL bReported, DWORD dwErr, const String &sSource)
static HANDLE OpenWin32EventLogHandle(const String &sLogName)
static HANDLE RegisterWin32EventSourceHandle(const String &sSource)