common: Add Windows ETW support

This patch adds generic ETW logging on top of syslog calls.

The events are described in the message compiler file `event_logging.mc`.

Using the cross platform utility `windmc`, we will generate the header file,
`event_logging.h`, needed by the ETW implementation, and the resource file
`event_logging.rc`.

Over the generated resource file we will run another utility called `windres`.
this tool is used to compile the binary objects needed by the OS utilities
(i.e. `Event Viewer`) to view the logged events.

On usage, a registry key needs to be added/removed on the target computer.
The registry looks like the following:
[HKLM\SYSTEM\CurrentControlSet\Services\EventLog\Application\<get_process_name>]
"EventMessageFile"="<Folder_location_to>\\event_logging.dll"

I.E.:
[HKLM\SYSTEM\CurrentControlSet\Services\EventLog\Application\rbd-wnbd]
"EventMessageFile"="C:\\Program Files\\Ceph\\bin\\event_logging.dll"

Signed-off-by: Alin Gabriel Serdean <aserdean@cloudbasesolutions.com>
Signed-off-by: Lucian Petrut <lpetrut@cloudbasesolutions.com>
Co-authored-by: Lucian Petrut <lpetrut@cloudbasesolutions.com>
This commit is contained in:
Alin Gabriel Serdean 2020-11-17 00:36:36 +02:00 committed by Alin Gabriel Serdean
parent 9ab1b5cb65
commit 8e7042f4ca
4 changed files with 141 additions and 6 deletions

View File

@ -104,13 +104,34 @@ set(common_srcs
version.cc)
if(WIN32)
if(MINGW)
set(CMAKE_MC_COMPILER x86_64-w64-mingw32-windmc)
set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)
endif()
add_custom_command(
OUTPUT ${CMAKE_BINARY_DIR}/src/common/event_logging.h
COMMAND ${CMAKE_MC_COMPILER} -b -e h -h ${CMAKE_BINARY_DIR}/src/common/
-r ${CMAKE_BINARY_DIR}/src/common ${CMAKE_SOURCE_DIR}/src/common/win32/event_logging.mc
COMMAND ${CMAKE_RC_COMPILER} ${CMAKE_BINARY_DIR}/src/common/event_logging.rc
-o ${CMAKE_BINARY_DIR}/src/common/event_logging.o
COMMAND ${CMAKE_CXX_COMPILER} -o ${CMAKE_BINARY_DIR}/bin/event_logging.dll -shared
${CMAKE_BINARY_DIR}/src/common/event_logging.o
DEPENDS ${CMAKE_SOURCE_DIR}/src/common/win32/event_logging.mc)
set_source_files_properties(${CMAKE_SOURCE_DIR}/src/common/win32/syslog.cc
APPEND PROPERTY OBJECT_DEPENDS ${CMAKE_BINARY_DIR}/src/common/event_logging.h)
include_directories(SYSTEM "${CMAKE_BINARY_DIR}/src/common/")
list(APPEND common_srcs
win32/blkdev.cc
win32/dns_resolve.cc
win32/ifaddrs.cc
win32/registry.cc
win32/service.cc
win32/SubProcess.cc)
win32/SubProcess.cc
win32/syslog.cc)
else()
list(APPEND common_srcs
blkdev.cc

View File

@ -0,0 +1,35 @@
SeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS
Informational=0x1:STATUS_SEVERITY_INFORMATIONAL
Warning=0x2:STATUS_SEVERITY_WARNING
Error=0x3:STATUS_SEVERITY_ERROR
)
MessageId=0x0001
Severity=Success
SymbolicName=SUCCESS_EVENTMSG
Language=English
%1
.
MessageId=0x0002
Severity=Informational
SymbolicName=INFO_EVENTMSG
Language=English
%1
.
MessageId=0x0003
Severity=Warning
SymbolicName=WARN_EVENTMSG
Language=English
%1
.
MessageId=0x0004
Severity=Error
SymbolicName=ERROR_EVENTMSG
Language=English
%1
.

View File

@ -0,0 +1,77 @@
#include <windows.h>
#include <syslog.h>
#include "event_logging.h"
#include "common/code_environment.h"
static HANDLE g_event_source = NULL;
bool get_event_source()
{
if (!g_event_source) {
HANDLE temp = RegisterEventSourceA(NULL, get_process_name_cpp().c_str());
if (!temp)
return false;
if (InterlockedCompareExchangePointer(&g_event_source, temp, NULL)) {
// There already was an event source, let's cleanup the one that we've
// just created.
DeregisterEventSource(temp);
}
}
return true;
}
void write_event_log_entry(int level, const char* msg)
{
if (!get_event_source()) {
return;
}
WORD type;
DWORD event_id;
switch (level) {
case LOG_DEBUG:
event_id = SUCCESS_EVENTMSG;
type = EVENTLOG_SUCCESS;
break;
case LOG_INFO:
case LOG_NOTICE:
event_id = INFO_EVENTMSG;
type = EVENTLOG_INFORMATION_TYPE;
break;
case LOG_WARNING:
event_id = WARN_EVENTMSG;
type = EVENTLOG_WARNING_TYPE;
break;
default:
event_id = ERROR_EVENTMSG;
type = EVENTLOG_ERROR_TYPE;
}
ReportEventA(g_event_source, type,
0, event_id, NULL, 1, 0, &msg, NULL);
}
void syslog(int priority, const char* format, ...)
{
va_list args;
va_start(args, format);
size_t length = (size_t)_vscprintf(format, args) + 1;
char* buffer = (char*) malloc(length);
if (NULL == buffer) {
va_end(args);
return;
}
vsnprintf_s(buffer, length, length - 1, format, args);
va_end(args);
write_event_log_entry(LOG_PRI(priority), buffer);
free(buffer);
}

View File

@ -25,7 +25,6 @@
#define LOG_NOTICE 5 /* normal but significant condition */
#define LOG_INFO 6 /* informational */
#define LOG_DEBUG 7 /* debug-level messages */
#define LOG_NDELAY 8 /* don't delay open */
#define LOG_KERN (0<<3) /* kernel messages */
#define LOG_USER (1<<3) /* user-level messages */
@ -49,14 +48,17 @@
#define LOG_LOCAL6 (22<<3) /* reserved for local use */
#define LOG_LOCAL7 (23<<3) /* reserved for local use */
#define LOG_PRIMASK 0x07 /* mask to extract priority part (internal) */
/* extract priority */
#define LOG_PRI(p) ((p) & LOG_PRIMASK)
static inline void
openlog(const char *ident, int option, int facility)
{
}
static inline void
syslog(int priority, const char *format, ...)
{
}
void
syslog(int priority, const char *format, ...);
#endif /* syslog.h */