From: VMware, Inc <> Date: Mon, 22 Mar 2010 19:24:52 +0000 (-0700) Subject: Add syslog support to Tools logging. X-Git-Tag: 2010.03.20-243334~30 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5c972fa538df2beec33afaae90a00350ec4e682a;p=thirdparty%2Fopen-vm-tools.git Add syslog support to Tools logging. Signed-off-by: Marcelo Vanzin --- diff --git a/open-vm-tools/docs/api/services/utils.txt b/open-vm-tools/docs/api/services/utils.txt index 2ff91b0de..3fb66488f 100644 --- a/open-vm-tools/docs/api/services/utils.txt +++ b/open-vm-tools/docs/api/services/utils.txt @@ -48,7 +48,7 @@ for each domain are: - This value is required when configuring a domain. - handler: the handler to use when logging. - Valid values: std, outputdebugstring (Win32-only), file, file+ - (same as "file", but appends to existing log file). + (same as "file", but appends to existing log file), syslog (Unix only). - Default: "std" on Unix, "outputdebugstring" on Windows. For file handlers, the following extra configuration information can be @@ -60,6 +60,14 @@ provided: - maxLogSize: maximum size of each log file, defaults to 10 (MB). A value of 0 disables log rotation. +When using syslog, the following options are available: + + - facility: either of "daemon", "user" or "local[0-7]". Controls whether to + connect to syslog as LOG_DAEMON, LOG_USER or LOG_LOCAL[0-7], respectively + (see syslog(3)). Defaults to "user". Any unknown value is mapped to + LOG_USER. This option should be defined for the application's default + log domain (it's ignored for all other domains). + Logging configuration should be under the "[logging]" group in the application's configuration file. diff --git a/open-vm-tools/libvmtools/Makefile.am b/open-vm-tools/libvmtools/Makefile.am index 1cf617148..15e4e0f10 100644 --- a/open-vm-tools/libvmtools/Makefile.am +++ b/open-vm-tools/libvmtools/Makefile.am @@ -58,6 +58,7 @@ libvmtools_la_SOURCES += fileLogger.c libvmtools_la_SOURCES += i18n.c libvmtools_la_SOURCES += signalSource.c libvmtools_la_SOURCES += stdLogger.c +libvmtools_la_SOURCES += sysLogger.c libvmtools_la_SOURCES += vmtools.c libvmtools_la_SOURCES += vmtoolsConfig.c libvmtools_la_SOURCES += vmtoolsLog.c diff --git a/open-vm-tools/libvmtools/fileLogger.c b/open-vm-tools/libvmtools/fileLogger.c index 187f7858c..4105a9f1d 100644 --- a/open-vm-tools/libvmtools/fileLogger.c +++ b/open-vm-tools/libvmtools/fileLogger.c @@ -362,9 +362,10 @@ VMFileLoggerDestroy(LogHandlerData *_data) * * Configures a new file logger based on the given configuration. * - * @param[in] domain Name of log domain. - * @param[in] name Name of log handler. - * @param[in] cfg Configuration data. + * @param[in] defaultDomain Unused. + * @param[in] domain Name of log domain. + * @param[in] name Name of log handler. + * @param[in] cfg Configuration data. * * @return The file logger data, or NULL on failure. * @@ -372,7 +373,8 @@ VMFileLoggerDestroy(LogHandlerData *_data) */ LogHandlerData * -VMFileLoggerConfig(const gchar *domain, +VMFileLoggerConfig(const gchar *defaultDomain, + const gchar *domain, const gchar *name, GKeyFile *cfg) { diff --git a/open-vm-tools/libvmtools/stdLogger.c b/open-vm-tools/libvmtools/stdLogger.c index d87a5323d..f8d73d220 100644 --- a/open-vm-tools/libvmtools/stdLogger.c +++ b/open-vm-tools/libvmtools/stdLogger.c @@ -63,9 +63,10 @@ VMStdLoggerLog(const gchar *domain, * * Configures a new std logger. * - * @param[in] domain Name of log domain. - * @param[in] name Name of log handler. - * @param[in] cfg Configuration data. + * @param[in] defaultDomain Unused. + * @param[in] domain Name of log domain. + * @param[in] name Name of log handler. + * @param[in] cfg Configuration data. * * @return The std logger data. * @@ -73,7 +74,8 @@ VMStdLoggerLog(const gchar *domain, */ LogHandlerData * -VMStdLoggerConfig(const gchar *domain, +VMStdLoggerConfig(const gchar *defaultDomain, + const gchar *domain, const gchar *name, GKeyFile *cfg) { diff --git a/open-vm-tools/libvmtools/sysLogger.c b/open-vm-tools/libvmtools/sysLogger.c new file mode 100644 index 000000000..3fa36eda5 --- /dev/null +++ b/open-vm-tools/libvmtools/sysLogger.c @@ -0,0 +1,220 @@ +/********************************************************* + * Copyright (C) 2010 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation version 2.1 and no later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + *********************************************************/ + +/** + * @file sysLogger.c + * + * Logger that writes to syslog(3). Since there's only one "syslog connection" + * for the whole application, this code does reference counting to allow + * different domains to be configured with a "syslog" handler, and still be + * able to call closelog(3) when appropriate. + */ + +#include +#include +#include +#include "vmware.h" +#include "vmtoolsInt.h" + +typedef struct SysLogData { + LogHandlerData handler; + gint refcount; +} SysLogData; + + +static SysLogData *gSysLogger; +static GStaticMutex gSysLoggerLock = G_STATIC_MUTEX_INIT; + + +/* + ****************************************************************************** + * VMSysLoggerLog -- */ /** + * + * Sends the given log message to syslog. + * + * @param[in] domain Unused. + * @param[in] level Log level. + * @param[in] message Message to log. + * @param[in] _data Unused. + * @param[in] errfn Unused. + * + * @return TRUE. + * + ****************************************************************************** + */ + +static gboolean +VMSysLoggerLog(const gchar *domain, + GLogLevelFlags level, + const gchar *message, + LogHandlerData *_data, + LogErrorFn errfn) +{ + int priority; + + /* glib and syslog disagree about critical / error. */ + if (level | G_LOG_LEVEL_ERROR) { + priority = LOG_CRIT; + } else if (level | G_LOG_LEVEL_CRITICAL) { + priority = LOG_ERR; + } else if (level | G_LOG_LEVEL_WARNING) { + priority = LOG_WARNING; + } else if (level | G_LOG_LEVEL_MESSAGE) { + priority = LOG_NOTICE; + } else if (level | G_LOG_LEVEL_INFO) { + priority = LOG_INFO; + } else { + priority = LOG_DEBUG; + } + + syslog(priority, "%s", message); + return TRUE; +} + + +/* + ****************************************************************************** + * VMSysLoggerUnref -- */ /** + * + * Decreases the ref count and closes syslog if it reaches 0. + * + * @param[in] _data Unused. + * + ****************************************************************************** + */ + +static void +VMSysLoggerUnref(LogHandlerData *_data) +{ + ASSERT(_data == (LogHandlerData *) gSysLogger); + g_static_mutex_lock(&gSysLoggerLock); + ASSERT(gSysLogger->refcount > 0); + gSysLogger->refcount -= 1; + if (gSysLogger->refcount == 0) { + closelog(); + g_free(gSysLogger); + gSysLogger = NULL; + } + g_static_mutex_unlock(&gSysLoggerLock); +} + + +/* + ****************************************************************************** + * VMSysLoggerConfig -- */ /** + * + * Initializes syslog if it hasn't been done yet. + * + * Since syslog is shared, it's not recommended to change the default domain + * during the lifetime of the application, since that may not reflect on the + * syslogs (and, when it does, it might be confusing). + * + * @param[in] defaultDomain Application name, used as the syslog identity. + * @param[in] domain Name of log domain. + * @param[in] name Name of log handler. + * @param[in] cfg Configuration data. + * + * @return Syslog logger data. + * + ****************************************************************************** + */ + +LogHandlerData * +VMSysLoggerConfig(const gchar *defaultDomain, + const gchar *domain, + const gchar *name, + GKeyFile *cfg) +{ + g_static_mutex_lock(&gSysLoggerLock); + if (gSysLogger == NULL) { + int facility = LOG_USER; + gchar *facstr; + gchar key[128]; + + g_snprintf(key, sizeof key, "%s.facility", defaultDomain); + facstr = g_key_file_get_string(cfg, LOGGING_GROUP, key, NULL); + if (facstr != NULL) { + int idx; + /* + * We only allow switching to LOG_DAEMON and LOG_LOCAL*. Since the + * facility is tied to the log domain configuration, we force using + * the default domain to retrieve this option. + */ + if (strcmp(facstr, "daemon") == 0) { + facility = LOG_DAEMON; + } else if (sscanf(facstr, "local%d", &idx) == 1) { + switch (idx) { + case 0: + facility = LOG_LOCAL0; + break; + + case 1: + facility = LOG_LOCAL1; + break; + + case 2: + facility = LOG_LOCAL2; + break; + + case 3: + facility = LOG_LOCAL3; + break; + + case 4: + facility = LOG_LOCAL4; + break; + + case 5: + facility = LOG_LOCAL5; + break; + + case 6: + facility = LOG_LOCAL6; + break; + + case 7: + facility = LOG_LOCAL7; + break; + + default: + g_message("Invalid local facility for %s: %s\n", defaultDomain, facstr); + break; + } + } else if (strcmp(facstr, "user") != 0) { + g_message("Invalid syslog facility for %s: %s\n", defaultDomain, facstr); + } + g_free(facstr); + } + + gSysLogger = g_new0(SysLogData, 1); + gSysLogger->handler.logfn = VMSysLoggerLog; + gSysLogger->handler.convertToLocal = TRUE; + gSysLogger->handler.timestamp = FALSE; + gSysLogger->handler.shared = FALSE; + gSysLogger->handler.copyfn = NULL; + gSysLogger->handler.dtor = VMSysLoggerUnref; + + gSysLogger->refcount = 1; + openlog(defaultDomain, LOG_CONS | LOG_PID, facility); + } else { + gSysLogger->refcount += 1; + } + g_static_mutex_unlock(&gSysLoggerLock); + return &gSysLogger->handler; +} + diff --git a/open-vm-tools/libvmtools/vmtoolsInt.h b/open-vm-tools/libvmtools/vmtoolsInt.h index 3e7b840e2..1fefabe14 100644 --- a/open-vm-tools/libvmtools/vmtoolsInt.h +++ b/open-vm-tools/libvmtools/vmtoolsInt.h @@ -81,25 +81,29 @@ typedef struct LogHandlerData { LogHandlerData * -VMFileLoggerConfig(const gchar *domain, +VMFileLoggerConfig(const gchar *defaultDomain, + const gchar *domain, const gchar *name, GKeyFile *cfg); LogHandlerData * -VMStdLoggerConfig(const gchar *domain, - const gchar *name, - GKeyFile *cfg); - -LogHandlerData * -VMSysLoggerConfig(const gchar *domain, +VMStdLoggerConfig(const gchar *defaultDomain, + const gchar *domain, const gchar *name, GKeyFile *cfg); #if defined(_WIN32) LogHandlerData * -VMDebugOutputConfig(const gchar *domain, +VMDebugOutputConfig(const gchar *defaultDomain, + const gchar *domain, const gchar *name, GKeyFile *cfg); +#else +LogHandlerData * +VMSysLoggerConfig(const gchar *defaultDomain, + const gchar *domain, + const gchar *name, + GKeyFile *cfg); #endif #endif /* _VMTOOLSINT_H_ */ diff --git a/open-vm-tools/libvmtools/vmtoolsLog.c b/open-vm-tools/libvmtools/vmtoolsLog.c index 12788efef..9d7bfe478 100644 --- a/open-vm-tools/libvmtools/vmtoolsLog.c +++ b/open-vm-tools/libvmtools/vmtoolsLog.c @@ -78,7 +78,8 @@ VMToolsLogOutputDebugString(const gchar *domain, gpointer _data); #endif -typedef LogHandlerData * (*LogHandlerConfigFn)(const gchar *domain, +typedef LogHandlerData * (*LogHandlerConfigFn)(const gchar *defaultDomain, + const gchar *domain, const gchar *name, GKeyFile *cfg); @@ -103,6 +104,7 @@ static LogHandler gHandlers[] = { { 3, "outputdebugstring", VMDebugOutputConfig }, { -1, NULL, VMDebugOutputConfig }, #else + { 3, "syslog", VMSysLoggerConfig }, { -1, NULL, VMStdLoggerConfig }, #endif }; @@ -423,7 +425,7 @@ VMToolsConfigLogDomain(const gchar *domain, goto exit; } - data = configfn(domain, handler, cfg); + data = configfn(gLogDomain, domain, handler, cfg); } else if (strcmp(domain, gLogDomain) == 0) { /* * If no handler defined and we're configuring the default domain, @@ -431,7 +433,7 @@ VMToolsConfigLogDomain(const gchar *domain, */ hid = DEFAULT_HANDLER->id; configfn = DEFAULT_HANDLER->configfn; - data = configfn(domain, NULL, cfg); + data = configfn(gLogDomain, domain, NULL, cfg); ASSERT(data != NULL); } else { /* An inherited handler. Just create a dummy instance. */ @@ -737,7 +739,7 @@ VMTools_ConfigLogging(const gchar *defaultDomain, } gLogDomain = g_strdup(defaultDomain); - gErrorData = DEFAULT_HANDLER->configfn(gLogDomain, NULL, NULL); + gErrorData = DEFAULT_HANDLER->configfn(gLogDomain, gLogDomain, NULL, NULL); /* * Configure the default domain first. See function documentation for