qga-win: add logging to Windows event log

This commit allows QGA to write to Windows event log using Win32 API's
ReportEvent() [1], much like syslog() under *nix guests.

In order to generate log message definitions we use a very basic message
text file [2], so that every QGA's message gets ID 1.  The tools
"windmc" and "windres" respectively are used to generate ".rc" file and
COFF object file, and then the COFF file is linked into qemu-ga.exe.

[1] https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-reporteventa
[2] https://learn.microsoft.com/en-us/windows/win32/eventlog/message-text-files

Originally-by: Yuri Pudgorodskiy <yur@virtuozzo.com>
Signed-off-by: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Reviewed-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Tested-by: Konstantin Kostiuk <kkostiuk@redhat.com>
Signed-off-by: Konstantin Kostiuk <kkostiuk@redhat.com>
This commit is contained in:
Andrey Drobyshev 2022-11-29 19:38:08 +02:00 committed by Konstantin Kostiuk
parent 28236ad8d1
commit f9f0e6173e
5 changed files with 48 additions and 4 deletions

3
configure vendored
View File

@ -372,6 +372,7 @@ smbd="$SMBD"
strip="${STRIP-${cross_prefix}strip}" strip="${STRIP-${cross_prefix}strip}"
widl="${WIDL-${cross_prefix}widl}" widl="${WIDL-${cross_prefix}widl}"
windres="${WINDRES-${cross_prefix}windres}" windres="${WINDRES-${cross_prefix}windres}"
windmc="${WINDMC-${cross_prefix}windmc}"
pkg_config_exe="${PKG_CONFIG-${cross_prefix}pkg-config}" pkg_config_exe="${PKG_CONFIG-${cross_prefix}pkg-config}"
query_pkg_config() { query_pkg_config() {
"${pkg_config_exe}" ${QEMU_PKG_CONFIG_FLAGS} "$@" "${pkg_config_exe}" ${QEMU_PKG_CONFIG_FLAGS} "$@"
@ -2561,6 +2562,7 @@ if test "$skip_meson" = no; then
echo "strip = [$(meson_quote $strip)]" >> $cross echo "strip = [$(meson_quote $strip)]" >> $cross
echo "widl = [$(meson_quote $widl)]" >> $cross echo "widl = [$(meson_quote $widl)]" >> $cross
echo "windres = [$(meson_quote $windres)]" >> $cross echo "windres = [$(meson_quote $windres)]" >> $cross
echo "windmc = [$(meson_quote $windmc)]" >> $cross
if test "$cross_compile" = "yes"; then if test "$cross_compile" = "yes"; then
cross_arg="--cross-file config-meson.cross" cross_arg="--cross-file config-meson.cross"
echo "[host_machine]" >> $cross echo "[host_machine]" >> $cross
@ -2667,6 +2669,7 @@ preserve_env SMBD
preserve_env STRIP preserve_env STRIP
preserve_env WIDL preserve_env WIDL
preserve_env WINDRES preserve_env WINDRES
preserve_env WINDMC
printf "exec" >>config.status printf "exec" >>config.status
for i in "$0" "$@"; do for i in "$0" "$@"; do

View File

@ -110,6 +110,11 @@
<RegistryValue Type="string" Name="ProductID" Value="fb0a0d66-c7fb-4e2e-a16b-c4a3bfe8d13b" /> <RegistryValue Type="string" Name="ProductID" Value="fb0a0d66-c7fb-4e2e-a16b-c4a3bfe8d13b" />
<RegistryValue Type="string" Name="Version" Value="$(var.QEMU_GA_VERSION)" /> <RegistryValue Type="string" Name="Version" Value="$(var.QEMU_GA_VERSION)" />
</RegistryKey> </RegistryKey>
<RegistryKey Root="HKLM"
Key="System\CurrentControlSet\Services\EventLog\Application\qemu-ga">
<RegistryValue Type="integer" Name="TypesSupported" Value="7" />
<RegistryValue Type="string" Name="EventMessageFile" Value="[qemu_ga_directory]qemu-ga.exe" />
</RegistryKey>
</Component> </Component>
</Directory> </Directory>
</Directory> </Directory>

View File

@ -83,6 +83,7 @@ struct GAState {
#ifdef _WIN32 #ifdef _WIN32
GAService service; GAService service;
HANDLE wakeup_event; HANDLE wakeup_event;
HANDLE event_log;
#endif #endif
bool delimit_response; bool delimit_response;
bool frozen; bool frozen;
@ -324,13 +325,14 @@ static void ga_log(const gchar *domain, GLogLevelFlags level,
} }
level &= G_LOG_LEVEL_MASK; level &= G_LOG_LEVEL_MASK;
#ifndef _WIN32
if (g_strcmp0(domain, "syslog") == 0) { if (g_strcmp0(domain, "syslog") == 0) {
#ifndef _WIN32
syslog(LOG_INFO, "%s: %s", level_str, msg); syslog(LOG_INFO, "%s: %s", level_str, msg);
} else if (level & s->log_level) {
#else #else
if (level & s->log_level) { ReportEvent(s->event_log, EVENTLOG_INFORMATION_TYPE,
0, 1, NULL, 1, 0, &msg, NULL);
#endif #endif
} else if (level & s->log_level) {
g_autoptr(GDateTime) now = g_date_time_new_now_utc(); g_autoptr(GDateTime) now = g_date_time_new_now_utc();
g_autofree char *nowstr = g_date_time_format(now, "%s.%f"); g_autofree char *nowstr = g_date_time_format(now, "%s.%f");
fprintf(s->log_file, "%s: %s: %s\n", nowstr, level_str, msg); fprintf(s->log_file, "%s: %s: %s\n", nowstr, level_str, msg);
@ -1286,6 +1288,13 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation)
g_debug("Guest agent version %s started", QEMU_FULL_VERSION); g_debug("Guest agent version %s started", QEMU_FULL_VERSION);
#ifdef _WIN32 #ifdef _WIN32
s->event_log = RegisterEventSource(NULL, "qemu-ga");
if (!s->event_log) {
g_autofree gchar *errmsg = g_win32_error_message(GetLastError());
g_critical("unable to register event source: %s", errmsg);
return NULL;
}
/* On win32 the state directory is application specific (be it the default /* On win32 the state directory is application specific (be it the default
* or a user override). We got past the command line parsing; let's create * or a user override). We got past the command line parsing; let's create
* the directory (with any intermediate directories). If we run into an * the directory (with any intermediate directories). If we run into an
@ -1377,6 +1386,7 @@ static void cleanup_agent(GAState *s)
{ {
#ifdef _WIN32 #ifdef _WIN32
CloseHandle(s->wakeup_event); CloseHandle(s->wakeup_event);
CloseHandle(s->event_log);
#endif #endif
if (s->command_state) { if (s->command_state) {
ga_command_state_cleanup_all(s->command_state); ga_command_state_cleanup_all(s->command_state);

View File

@ -98,7 +98,24 @@ if targetos == 'windows'
endif endif
endif endif
qga = executable('qemu-ga', qga_ss.sources(), qga_objs = []
if targetos == 'windows'
windmc = find_program('windmc', required: true)
windres = find_program('windres', required: true)
msgrc = custom_target('messages-win32.rc',
input: 'messages-win32.mc',
output: ['messages-win32.rc', 'MSG00409.bin', 'messages-win32.h'],
command: [windmc, '-h', '@OUTDIR@', '-r', '@OUTDIR@', '@INPUT@'])
msgobj = custom_target('messages-win32.o',
input: msgrc[0],
output: 'messages-win32.o',
command: [windres, '-I', '@OUTDIR@', '-o', '@OUTPUT@', '@INPUT@'])
qga_objs = [msgobj]
endif
qga = executable('qemu-ga', qga_ss.sources() + qga_objs,
link_args: qga_libs, link_args: qga_libs,
dependencies: [qemuutil, libudev], dependencies: [qemuutil, libudev],
install: true) install: true)

9
qga/messages-win32.mc Normal file
View File

@ -0,0 +1,9 @@
LanguageNames=(
English=0x409:MSG00409
)
MessageId=1
SymbolicName=QEMU_GA_EVENTLOG_GENERAL
Language=English
%1
.