]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
Add syslog support to Tools logging.
authorVMware, Inc <>
Mon, 22 Mar 2010 19:24:52 +0000 (12:24 -0700)
committerMarcelo Vanzin <mvanzin@vmware.com>
Mon, 22 Mar 2010 19:24:52 +0000 (12:24 -0700)
Signed-off-by: Marcelo Vanzin <mvanzin@vmware.com>
open-vm-tools/docs/api/services/utils.txt
open-vm-tools/libvmtools/Makefile.am
open-vm-tools/libvmtools/fileLogger.c
open-vm-tools/libvmtools/stdLogger.c
open-vm-tools/libvmtools/sysLogger.c [new file with mode: 0644]
open-vm-tools/libvmtools/vmtoolsInt.h
open-vm-tools/libvmtools/vmtoolsLog.c

index 2ff91b0de6e20e75d1b860c6da24e36d376ecb5e..3fb66488f72127ea21b44c03fe4bb76eeeb38a26 100644 (file)
@@ -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.
 
index 1cf617148b5dcbec5d9e2cba5eab796433ce5c37..15e4e0f10a9b54ab3f9fc91d065a77790c53121a 100644 (file)
@@ -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
index 187f7858c3fe55b9a37ef98687024c8130c7b567..4105a9f1dcf1eba748c733693b378996a17e805e 100644 (file)
@@ -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)
 {
index d87a5323d2c7c33e4e906a0e9cda1ec9949edf79..f8d73d220810a6a070acc40fb8d4de0e23e8785d 100644 (file)
@@ -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 (file)
index 0000000..3fa36ed
--- /dev/null
@@ -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 <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#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;
+}
+
index 3e7b840e2751d3baa39ce8b561db6c61921a2c44..1fefabe1487d0421beba5a27a0367b37992670e8 100644 (file)
@@ -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_ */
index 12788efefc856e0f03971322a13f03da8ef8e0e2..9d7bfe478d34d294847a96a6a1b58f35eb55ebd4 100644 (file)
@@ -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