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:
parent
28236ad8d1
commit
f9f0e6173e
3
configure
vendored
3
configure
vendored
@ -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
|
||||||
|
@ -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>
|
||||||
|
16
qga/main.c
16
qga/main.c
@ -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);
|
||||||
|
@ -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
9
qga/messages-win32.mc
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
LanguageNames=(
|
||||||
|
English=0x409:MSG00409
|
||||||
|
)
|
||||||
|
|
||||||
|
MessageId=1
|
||||||
|
SymbolicName=QEMU_GA_EVENTLOG_GENERAL
|
||||||
|
Language=English
|
||||||
|
%1
|
||||||
|
.
|
Loading…
Reference in New Issue
Block a user