[gnome-builder/wip/libide] libide: add logging and debug helpers to libide



commit c66f718225df9054ac1a19e4e720038121b9bfe6
Author: Christian Hergert <christian hergert me>
Date:   Mon Mar 2 13:49:49 2015 -0800

    libide: add logging and debug helpers to libide
    
    Now we can sprinkle these throughout libide to get various debug messages.
    For programs that initialize the log and add the verbosity hook, you'll
    be able to increase logging using -vvvv (up to 4 times). Any more than
    4 is idempotent.
    
    Note that debug and trace macros will be compiled out of production builds,
    so anything more than -vv in those builds will likely be unhelpful.

 libide/Makefile.am |    3 +
 libide/ide-debug.h |   80 ++++++++++++++++
 libide/ide-log.c   |  261 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 libide/ide-log.h   |   33 +++++++
 libide/ide.h       |    1 +
 5 files changed, 378 insertions(+), 0 deletions(-)
---
diff --git a/libide/Makefile.am b/libide/Makefile.am
index 2aa86ed..e2a824d 100644
--- a/libide/Makefile.am
+++ b/libide/Makefile.am
@@ -91,6 +91,8 @@ libide_1_0_la_public_sources = \
        libide/ide-indenter.h \
        libide/ide-language.c \
        libide/ide-language.h \
+       libide/ide-log.c \
+       libide/ide-log.h \
        libide/ide-object.c \
        libide/ide-object.h \
        libide/ide-process.c \
@@ -176,6 +178,7 @@ libide_1_0_la_SOURCES = \
        libide/autotools/ide-makecache.h \
        libide/c/c-parse-helper.c \
        libide/c/c-parse-helper.h \
+       libide/ide-debug.h \
        libide/editorconfig/editorconfig-glib.c \
        libide/editorconfig/editorconfig-glib.h \
        libide/fuzzy/fuzzy.c \
diff --git a/libide/ide-debug.h b/libide/ide-debug.h
new file mode 100644
index 0000000..ceba8a6
--- /dev/null
+++ b/libide/ide-debug.h
@@ -0,0 +1,80 @@
+/* ide-debug.h
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This file 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; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This file 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 GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef IDE_DEBUG_H
+#define IDE_DEBUG_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#ifndef G_LOG_LEVEL_TRACE
+# define G_LOG_LEVEL_TRACE (1 << G_LOG_LEVEL_USER_SHIFT)
+#endif
+
+#ifdef IDE_ENABLE_DEBUG
+# define IDE_DEBUG(...)                                                \
+   g_log(G_LOG_DOMAIN, G_LOG_LEVEL_TRACE, ##__VA_ARGS__)
+#else
+# define IDE_DEBUG(...)
+#endif
+
+#ifdef IDE_ENABLE_TRACE
+# define IDE_TRACE_MSG(fmt, ...)                                       \
+   g_log(G_LOG_DOMAIN, G_LOG_LEVEL_TRACE, "TRACE: %s():%d: "fmt,       \
+         G_STRFUNC, __LINE__, ##__VA_ARGS__)
+# define IDE_TRACE                                                     \
+   g_log(G_LOG_DOMAIN, G_LOG_LEVEL_TRACE, "TRACE: %s():%d",            \
+         G_STRFUNC, __LINE__)
+# define IDE_TODO(_msg)                                                \
+   g_log(G_LOG_DOMAIN, G_LOG_LEVEL_TRACE, " TODO: %s():%d: %s",        \
+         G_STRFUNC, __LINE__, _msg)
+# define IDE_ENTRY                                                     \
+   g_log(G_LOG_DOMAIN, G_LOG_LEVEL_TRACE, "ENTRY: %s():%d",            \
+         G_STRFUNC, __LINE__)
+# define IDE_EXIT                                                      \
+   G_STMT_START {                                                      \
+      g_log(G_LOG_DOMAIN, G_LOG_LEVEL_TRACE, " EXIT: %s():%d",         \
+            G_STRFUNC, __LINE__);                                      \
+      return;                                                          \
+   } G_STMT_END
+# define IDE_GOTO(_l)                                                  \
+   G_STMT_START {                                                      \
+      g_log(G_LOG_DOMAIN, G_LOG_LEVEL_TRACE, " GOTO: %s():%d ("#_l")", \
+            G_STRFUNC, __LINE__);                                      \
+      goto _l;                                                         \
+   } G_STMT_END
+# define IDE_RETURN(_r)                                                \
+   G_STMT_START {                                                      \
+      g_log(G_LOG_DOMAIN, G_LOG_LEVEL_TRACE, " EXIT: %s():%d ",        \
+            G_STRFUNC, __LINE__);                                      \
+      return _r;                                                       \
+   } G_STMT_END
+#else
+# define IDE_TODO(_msg)
+# define IDE_TRACE
+# define IDE_TRACE_MSG(fmt, ...)
+# define IDE_ENTRY
+# define IDE_GOTO(_l)   goto _l
+# define IDE_EXIT       return
+# define IDE_RETURN(_r) return _r
+#endif
+
+G_END_DECLS
+
+#endif /* IDE_DEBUG_H */
diff --git a/libide/ide-log.c b/libide/ide-log.c
new file mode 100644
index 0000000..6e58ce2
--- /dev/null
+++ b/libide/ide-log.c
@@ -0,0 +1,261 @@
+/* ide-log.c
+ *
+ * Copyright (C) 2009-2015 Christian Hergert <christian hergert me>
+ *
+ * This file 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; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This file 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 GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+
+#ifdef __linux__
+# include <sys/utsname.h>
+# include <sys/types.h>
+# include <sys/syscall.h>
+#elif defined __FreeBSD__
+# include <sys/utsname.h>
+#endif /* !__linux__ && !__FreeBSD__ */
+
+#include <glib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "ide-debug.h"
+#include "ide-log.h"
+
+static GPtrArray *channels = NULL;
+static gchar hostname[64] = "";
+static GLogFunc last_handler = NULL;
+static int log_verbosity = 0;
+
+G_LOCK_DEFINE (channels_lock);
+
+/**
+ * ide_log_get_thread:
+ *
+ * Retrieves task id for the current thread. This is only supported on Linux.
+ * On other platforms, the current current thread pointer is retrieved.
+ *
+ * Returns: The task id.
+ */
+static inline gint
+ide_log_get_thread (void)
+{
+#if __linux__
+  return (gint) syscall (SYS_gettid);
+#else
+  return GPOINTER_TO_INT (g_thread_self ());
+#endif /* __linux__ */
+}
+
+/**
+ * ide_log_level_str:
+ * @log_level: A #GLogLevelFlags.
+ *
+ * Retrieves the log level as a string.
+ *
+ * Returns: A string which shouldn't be modified or freed.
+ * Side effects: None.
+ */
+static inline const gchar *
+ide_log_level_str (GLogLevelFlags log_level)
+{
+#define CASE_LEVEL_STR(_l) case G_LOG_LEVEL_ ## _l: return #_l
+  switch (((gulong)log_level & G_LOG_LEVEL_MASK))
+    {
+    CASE_LEVEL_STR (ERROR);
+    CASE_LEVEL_STR (CRITICAL);
+    CASE_LEVEL_STR (WARNING);
+    CASE_LEVEL_STR (MESSAGE);
+    CASE_LEVEL_STR (INFO);
+    CASE_LEVEL_STR (DEBUG);
+    CASE_LEVEL_STR (TRACE);
+
+    default:
+      return "UNKNOWN";
+    }
+#undef CASE_LEVEL_STR
+}
+
+/**
+ * ide_log_write_to_channel:
+ * @channel: A #GIOChannel.
+ * @message: A string log message.
+ *
+ * Writes @message to @channel and flushes the channel.
+ */
+static void
+ide_log_write_to_channel (GIOChannel  *channel,
+                         const gchar *message)
+{
+  g_io_channel_write_chars (channel, message, -1, NULL, NULL);
+  g_io_channel_flush (channel, NULL);
+}
+
+/**
+ * ide_log_handler:
+ * @log_domain: A string containing the log section.
+ * @log_level: A #GLogLevelFlags.
+ * @message: The string message.
+ * @user_data: User data supplied to g_log_set_default_handler().
+ *
+ * Default log handler that will dispatch log messages to configured logging
+ * destinations.
+ *
+ * Returns: None.
+ * Side effects: None.
+ */
+static void
+ide_log_handler (const gchar   *log_domain,
+                GLogLevelFlags log_level,
+                const gchar   *message,
+                gpointer       user_data)
+{
+  struct timespec ts;
+  struct tm tt;
+  time_t t;
+  const gchar *level;
+  gchar ftime[32];
+  gchar *buffer;
+
+  if (G_LIKELY (channels->len))
+    {
+      switch ((int)log_level)
+        {
+        case G_LOG_LEVEL_MESSAGE:
+          if (log_verbosity < 1)
+            return;
+          break;
+
+        case G_LOG_LEVEL_INFO:
+          if (log_verbosity < 2)
+            return;
+          break;
+
+        case G_LOG_LEVEL_DEBUG:
+          if (log_verbosity < 3)
+            return;
+          break;
+
+        case G_LOG_LEVEL_TRACE:
+          if (log_verbosity < 4)
+            return;
+          break;
+
+        default:
+          break;
+        }
+
+      level = ide_log_level_str (log_level);
+      clock_gettime (CLOCK_REALTIME, &ts);
+      t = (time_t) ts.tv_sec;
+      tt = *localtime (&t);
+      strftime (ftime, sizeof (ftime), "%Y/%m/%d %H:%M:%S", &tt);
+      buffer = g_strdup_printf ("%s.%04ld  %s: %20s[%d]: %8s: %s\n",
+                                ftime, ts.tv_nsec / 100000,
+                                hostname, log_domain,
+                                ide_log_get_thread (), level, message);
+      G_LOCK (channels_lock);
+      g_ptr_array_foreach (channels, (GFunc) ide_log_write_to_channel, buffer);
+      G_UNLOCK (channels_lock);
+      g_free (buffer);
+    }
+}
+
+/**
+ * ide_log_init:
+ * @stdout_: Indicates logging should be written to stdout.
+ * @filename: An optional file in which to store logs.
+ *
+ * Initializes the logging subsystem.
+ */
+void
+ide_log_init (gboolean     stdout_,
+              const gchar *filename)
+{
+  static gsize initialized = FALSE;
+  struct utsname u;
+  GIOChannel *channel;
+
+  if (g_once_init_enter (&initialized))
+    {
+      channels = g_ptr_array_new ();
+      if (filename)
+        {
+          channel = g_io_channel_new_file (filename, "a", NULL);
+          g_ptr_array_add (channels, channel);
+        }
+      if (stdout_)
+        {
+          channel = g_io_channel_unix_new (STDOUT_FILENO);
+          g_ptr_array_add (channels, channel);
+        }
+
+#if defined __linux__ || defined __FreeBSD__
+      uname (&u);
+      memcpy (hostname, u.nodename, sizeof (hostname));
+#else
+# ifdef __APPLE__
+      gethostname (hostname, sizeof (hostname));
+# else
+#  error "Target platform not supported"
+# endif /* __APPLE__ */
+#endif /* __linux__ */
+
+      g_log_set_default_handler (ide_log_handler, NULL);
+      g_once_init_leave (&initialized, TRUE);
+    }
+}
+
+/**
+ * ide_log_shutdown:
+ *
+ * Cleans up after the logging subsystem.
+ */
+void
+ide_log_shutdown (void)
+{
+  if (last_handler)
+    {
+      g_log_set_default_handler (last_handler, NULL);
+      last_handler = NULL;
+    }
+}
+
+/**
+ * ide_log_increase_verbosity:
+ *
+ * Increases the amount of logging that will occur. By default, only
+ * warning and above will be displayed.
+ *
+ * Calling this once will cause G_LOG_LEVEL_MESSAGE to be displayed.
+ * Calling this twice will cause G_LOG_LEVEL_INFO to be displayed.
+ * Calling this thrice will cause G_LOG_LEVEL_DEBUG to be displayed.
+ * Calling this four times will cause G_LOG_LEVEL_TRACE to be displayed.
+ *
+ * Note that many DEBUG and TRACE level log messages are only compiled into
+ * debug builds, and therefore will not be available in release builds.
+ *
+ * This method is meant to be called for every -v provided on the command
+ * line.
+ *
+ * Calling this method more than four times is acceptable.
+ */
+void
+ide_log_increase_verbosity (void)
+{
+  log_verbosity++;
+}
diff --git a/libide/ide-log.h b/libide/ide-log.h
new file mode 100644
index 0000000..0957976
--- /dev/null
+++ b/libide/ide-log.h
@@ -0,0 +1,33 @@
+/* ide-log.h
+ *
+ * Copyright (C) 2009-2015 Christian Hergert <christian hergert me>
+ *
+ * This file 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; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This file 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 GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef IDE_LOG_H
+#define IDE_LOG_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+void ide_log_init               (gboolean     stdout_,
+                                 const gchar *filename);
+void ide_log_increase_verbosity (void);
+void ide_log_shutdown           (void);
+
+G_END_DECLS
+
+#endif /* IDE_LOG_H */
diff --git a/libide/ide.h b/libide/ide.h
index e07fbd8..5f7ba98 100644
--- a/libide/ide.h
+++ b/libide/ide.h
@@ -50,6 +50,7 @@ G_BEGIN_DECLS
 #include "ide-highlighter.h"
 #include "ide-indenter.h"
 #include "ide-language.h"
+#include "ide-log.h"
 #include "ide-object.h"
 #include "ide-process.h"
 #include "ide-progress.h"


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]