]> git.0d.be Git - empathy.git/commitdiff
Implement o.fd.Tp.Debug. (Fixes #580631)
authorJonny Lamb <jonny.lamb@collabora.co.uk>
Wed, 17 Jun 2009 23:54:55 +0000 (00:54 +0100)
committerJonny Lamb <jonny.lamb@collabora.co.uk>
Thu, 18 Jun 2009 00:05:56 +0000 (01:05 +0100)
Signed-off-by: Jonny Lamb <jonny.lamb@collabora.co.uk>
libempathy/Makefile.am
libempathy/empathy-debug.c
libempathy/empathy-debug.h
libempathy/empathy-debugger.c [new file with mode: 0644]
libempathy/empathy-debugger.h [new file with mode: 0644]
src/empathy.c

index 6a42bba9a9720a61037a24ce33637cb1d881278f..87b7284643ebe58a4531569c58c45fcbf24461cd 100644 (file)
@@ -34,6 +34,7 @@ libempathy_la_SOURCES =                                       \
        empathy-contact-manager.c                       \
        empathy-contact-monitor.c                       \
        empathy-debug.c                                 \
+       empathy-debugger.c                              \
        empathy-dispatcher.c                            \
        empathy-dispatch-operation.c                    \
        empathy-ft-factory.c                            \
@@ -82,6 +83,7 @@ libempathy_headers =                          \
        empathy-contact-manager.h               \
        empathy-contact-monitor.h               \
        empathy-debug.h                         \
+       empathy-debugger.h                      \
        empathy-dispatcher.h                    \
        empathy-dispatch-operation.h            \
        empathy-ft-factory.h                    \
index 47482d5fc4e20e511e862a9fd16bedacbf8c51ef..99111deec90d2b3a84cb03eacdc96f59fdb2a0e5 100644 (file)
@@ -33,6 +33,8 @@
 
 #include "empathy-debug.h"
 
+#include "empathy-debugger.h"
+
 #ifdef ENABLE_DEBUG
 
 static EmpathyDebugFlags flags = 0;
@@ -75,18 +77,74 @@ empathy_debug_flag_is_set (EmpathyDebugFlags flag)
   return (flag & flags) != 0;
 }
 
+GHashTable *flag_to_keys = NULL;
+
+static const gchar *
+debug_flag_to_key (EmpathyDebugFlags flag)
+{
+  if (flag_to_keys == NULL)
+    {
+      guint i;
+
+      flag_to_keys = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+          NULL, g_free);
+
+      for (i = 0; keys[i].value; i++)
+        {
+          GDebugKey key = (GDebugKey) keys[i];
+          g_hash_table_insert (flag_to_keys, GUINT_TO_POINTER (key.value),
+              g_strdup (key.key));
+        }
+    }
+
+  return g_hash_table_lookup (flag_to_keys, GUINT_TO_POINTER (flag));
+}
+
+void
+empathy_debug_free (void)
+{
+  if (flag_to_keys == NULL)
+    return;
+
+  g_hash_table_destroy (flag_to_keys);
+  flag_to_keys = NULL;
+}
+
+static void
+log_to_debugger (EmpathyDebugFlags flag,
+    const gchar *message)
+{
+  EmpathyDebugger *dbg = empathy_debugger_get_singleton ();
+  gchar *domain;
+  GTimeVal now;
+
+  g_get_current_time (&now);
+
+  domain = g_strdup_printf ("%s/%s", G_LOG_DOMAIN, debug_flag_to_key (flag));
+
+  empathy_debugger_add_message (dbg, &now, domain, G_LOG_LEVEL_DEBUG, message);
+
+  g_free (domain);
+}
+
 void
 empathy_debug (EmpathyDebugFlags flag,
-               const gchar *format,
-               ...)
+    const gchar *format,
+    ...)
 {
+  gchar *message;
+  va_list args;
+
+  va_start (args, format);
+  message = g_strdup_vprintf (format, args);
+  va_end (args);
+
+  log_to_debugger (flag, message);
+
   if (flag & flags)
-    {
-      va_list args;
-      va_start (args, format);
-      g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format, args);
-      va_end (args);
-    }
+    g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s", message);
+
+  g_free (message);
 }
 
 #else
index 7d05db6abb58265844892f7b3d9c0c2883ec34ae..9df72892260a3a2aa7a3b80e3b4213bd1b916b67 100644 (file)
@@ -46,6 +46,7 @@ typedef enum
 gboolean empathy_debug_flag_is_set (EmpathyDebugFlags flag);
 void empathy_debug (EmpathyDebugFlags flag, const gchar *format, ...)
     G_GNUC_PRINTF (2, 3);
+void empathy_debug_free (void);
 void empathy_debug_set_flags (const gchar *flags_string);
 G_END_DECLS
 
@@ -88,4 +89,7 @@ G_END_DECLS
 #define DEBUGGING 0
 
 #endif /* !defined (ENABLE_DEBUG) */
+
+#define gabble_debug_free() G_STMT_START { } G_STMT_END
+
 #endif /* defined (DEBUG_FLAG) */
diff --git a/libempathy/empathy-debugger.c b/libempathy/empathy-debugger.c
new file mode 100644 (file)
index 0000000..0487312
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * Telepathy debug interface implementation
+ * Copyright (C) 2009 Collabora Ltd.
+ *
+ * This library 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 library 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 Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "empathy-debugger.h"
+#include "config.h"
+
+#include <telepathy-glib/dbus.h>
+
+#include "extensions/extensions.h"
+
+static EmpathyDebugger *singleton = NULL;
+
+static void
+debug_iface_init (gpointer g_iface, gpointer iface_data);
+
+G_DEFINE_TYPE_WITH_CODE (EmpathyDebugger, empathy_debugger, G_TYPE_OBJECT,
+    G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES,
+        tp_dbus_properties_mixin_iface_init);
+    G_IMPLEMENT_INTERFACE (EMP_TYPE_SVC_DEBUG, debug_iface_init));
+
+/* properties */
+enum
+{
+  PROP_ENABLED = 1,
+  NUM_PROPERTIES
+};
+
+static EmpDebugLevel
+log_level_flags_to_debug_level (GLogLevelFlags level)
+{
+  if (level & G_LOG_LEVEL_ERROR)
+    return EMP_DEBUG_LEVEL_ERROR;
+  else if (level & G_LOG_LEVEL_CRITICAL)
+    return EMP_DEBUG_LEVEL_CRITICAL;
+  else if (level & G_LOG_LEVEL_WARNING)
+    return EMP_DEBUG_LEVEL_WARNING;
+  else if (level & G_LOG_LEVEL_MESSAGE)
+    return EMP_DEBUG_LEVEL_MESSAGE;
+  else if (level & G_LOG_LEVEL_INFO)
+    return EMP_DEBUG_LEVEL_INFO;
+  else if (level & G_LOG_LEVEL_DEBUG)
+    return EMP_DEBUG_LEVEL_DEBUG;
+  else
+    /* Fall back to DEBUG if all else fails */
+    return EMP_DEBUG_LEVEL_DEBUG;
+}
+
+static EmpathyDebugMessage *
+debug_message_new (GTimeVal *timestamp,
+    const gchar *domain,
+    GLogLevelFlags level,
+    const gchar *string)
+{
+  EmpathyDebugMessage *msg;
+
+  msg = g_slice_new0 (EmpathyDebugMessage);
+  msg->timestamp = timestamp->tv_sec + timestamp->tv_usec / 1e6;
+  msg->domain = g_strdup (domain);
+  msg->level = log_level_flags_to_debug_level (level);
+  msg->string = g_strdup (string);
+  return msg;
+}
+
+static void
+debug_message_free (EmpathyDebugMessage *msg)
+{
+  g_free (msg->domain);
+  g_free (msg->string);
+  g_slice_free (EmpathyDebugMessage, msg);
+}
+
+static void
+empathy_debugger_get_property (GObject *object,
+    guint property_id,
+    GValue *value,
+    GParamSpec *pspec)
+{
+  EmpathyDebugger *self = EMPATHY_DEBUGGER (object);
+
+  switch (property_id)
+    {
+      case PROP_ENABLED:
+        g_value_set_boolean (value, self->enabled);
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+empathy_debugger_set_property (GObject *object,
+    guint property_id,
+    const GValue *value,
+    GParamSpec *pspec)
+{
+  EmpathyDebugger *self = EMPATHY_DEBUGGER (object);
+
+  switch (property_id)
+    {
+      case PROP_ENABLED:
+        self->enabled = g_value_get_boolean (value);
+        break;
+
+     default:
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+empathy_debugger_finalize (GObject *object)
+{
+  EmpathyDebugger *self = EMPATHY_DEBUGGER (object);
+
+  g_queue_foreach (self->messages, (GFunc) debug_message_free, NULL);
+  g_queue_free (self->messages);
+  self->messages = NULL;
+
+  G_OBJECT_CLASS (empathy_debugger_parent_class)->finalize (object);
+}
+
+static void
+empathy_debugger_class_init (EmpathyDebuggerClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  static TpDBusPropertiesMixinPropImpl debug_props[] = {
+      { "Enabled", "enabled", "enabled" },
+      { NULL }
+  };
+  static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
+      { EMP_IFACE_DEBUG,
+        tp_dbus_properties_mixin_getter_gobject_properties,
+        tp_dbus_properties_mixin_setter_gobject_properties,
+        debug_props,
+      },
+      { NULL }
+  };
+
+  object_class->get_property = empathy_debugger_get_property;
+  object_class->set_property = empathy_debugger_set_property;
+  object_class->finalize = empathy_debugger_finalize;
+
+  g_object_class_install_property (object_class, PROP_ENABLED,
+      g_param_spec_boolean ("enabled", "Enabled?",
+          "True if the new-debug-message signal is enabled.",
+          FALSE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  klass->dbus_props_class.interfaces = prop_interfaces;
+  tp_dbus_properties_mixin_class_init (object_class,
+      G_STRUCT_OFFSET (EmpathyDebuggerClass, dbus_props_class));
+}
+
+static void
+get_messages (EmpSvcDebug *self,
+    DBusGMethodInvocation *context)
+{
+  EmpathyDebugger *dbg = EMPATHY_DEBUGGER (self);
+  GPtrArray *messages;
+  static GType struct_type = 0;
+  GList *i;
+  guint j;
+
+  if (G_UNLIKELY (struct_type == 0))
+    {
+      struct_type = dbus_g_type_get_struct (
+          "GValueArray", G_TYPE_DOUBLE, G_TYPE_STRING, G_TYPE_UINT,
+          G_TYPE_STRING, G_TYPE_INVALID);
+    }
+
+  messages = g_ptr_array_sized_new (g_queue_get_length (dbg->messages));
+
+  for (i = dbg->messages->head; i; i = i->next)
+    {
+      GValue gvalue = { 0 };
+      EmpathyDebugMessage *message = (EmpathyDebugMessage *) i->data;
+
+      g_value_init (&gvalue, struct_type);
+      g_value_take_boxed (&gvalue,
+          dbus_g_type_specialized_construct (struct_type));
+      dbus_g_type_struct_set (&gvalue,
+          0, message->timestamp,
+          1, message->domain,
+          2, message->level,
+          3, message->string,
+          G_MAXUINT);
+      g_ptr_array_add (messages, g_value_get_boxed (&gvalue));
+    }
+
+  emp_svc_debug_return_from_get_messages (context, messages);
+
+  for (j = 0; j < messages->len; j++)
+    g_boxed_free (struct_type, messages->pdata[j]);
+
+  g_ptr_array_free (messages, TRUE);
+}
+
+static void
+debug_iface_init (gpointer g_iface,
+    gpointer iface_data)
+{
+  EmpSvcDebugClass *klass = (EmpSvcDebugClass *) g_iface;
+
+  emp_svc_debug_implement_get_messages (klass, get_messages);
+}
+
+static void
+empathy_debugger_init (EmpathyDebugger *self)
+{
+  self->messages = g_queue_new ();
+}
+
+EmpathyDebugger *
+empathy_debugger_get_singleton (void)
+{
+  if (G_UNLIKELY (singleton == NULL))
+    {
+      DBusGConnection *bus;
+
+      singleton = g_object_new (EMPATHY_TYPE_DEBUGGER, NULL);
+      bus = tp_get_bus ();
+      dbus_g_connection_register_g_object (bus,
+          "/org/freedesktop/Telepathy/debug", (GObject *) singleton);
+    }
+
+  return singleton;
+}
+
+void
+empathy_debugger_add_message (EmpathyDebugger *self,
+    GTimeVal *timestamp,
+    const gchar *domain,
+    GLogLevelFlags level,
+    const gchar *string)
+{
+  EmpathyDebugMessage *new_msg;
+
+  if (g_queue_get_length (self->messages) >= DEBUG_MESSAGE_LIMIT)
+    {
+      EmpathyDebugMessage *old_head =
+        (EmpathyDebugMessage *) g_queue_pop_head (self->messages);
+
+      debug_message_free (old_head);
+    }
+
+  new_msg = debug_message_new (timestamp, domain, level, string);
+  g_queue_push_tail (self->messages, new_msg);
+
+  if (self->enabled)
+    {
+      emp_svc_debug_emit_new_debug_message (self, new_msg->timestamp,
+          domain, new_msg->level, string);
+    }
+}
diff --git a/libempathy/empathy-debugger.h b/libempathy/empathy-debugger.h
new file mode 100644 (file)
index 0000000..f3fdc70
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * header for Telepathy debug interface implementation
+ * Copyright (C) 2009 Collabora Ltd.
+ *
+ * This library 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 library 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 Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef _EMPATHY_DEBUGGER
+#define _EMPATHY_DEBUGGER
+
+#include <glib-object.h>
+
+#include <telepathy-glib/properties-mixin.h>
+#include <telepathy-glib/dbus-properties-mixin.h>
+
+#include "extensions/extensions.h"
+
+G_BEGIN_DECLS
+
+#define EMPATHY_TYPE_DEBUGGER empathy_debugger_get_type()
+
+#define EMPATHY_DEBUGGER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), EMPATHY_TYPE_DEBUGGER, EmpathyDebugger))
+
+#define EMPATHY_DEBUGGER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), EMPATHY_TYPE_DEBUGGER, EmpathyDebuggerClass))
+
+#define EMPATHY_IS_DEBUGGER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EMPATHY_TYPE_DEBUGGER))
+
+#define EMPATHY_IS_DEBUGGER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), EMPATHY_TYPE_DEBUGGER))
+
+#define EMPATHY_DEBUGGER_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), EMPATHY_TYPE_DEBUGGER, EmpathyDebuggerClass))
+
+/* On the basis that messages are around 60 bytes on average, and that 50kb is
+ * a reasonable maximum size for a frame buffer.
+ */
+
+#define DEBUG_MESSAGE_LIMIT 800
+
+typedef struct {
+  gdouble timestamp;
+  gchar *domain;
+  EmpDebugLevel level;
+  gchar *string;
+} EmpathyDebugMessage;
+
+typedef struct {
+  GObject parent;
+
+  gboolean enabled;
+  GQueue *messages;
+} EmpathyDebugger;
+
+typedef struct {
+  GObjectClass parent_class;
+  TpDBusPropertiesMixinClass dbus_props_class;
+} EmpathyDebuggerClass;
+
+GType empathy_debugger_get_type (void);
+
+EmpathyDebugger *
+empathy_debugger_get_singleton (void);
+
+void
+empathy_debugger_add_message (EmpathyDebugger *self,
+    GTimeVal *timestamp,
+    const gchar *domain,
+    GLogLevelFlags level,
+    const gchar *string);
+
+G_END_DECLS
+
+#endif /* _EMPATHY_DEBUGGER */
index f23ce9145eb21a5d3c999989ef7f80f30b0d146a..fc6b5118c6ca064df0c126621a7cb2440bfe334f 100644 (file)
@@ -48,6 +48,7 @@
 #include <libempathy/empathy-call-factory.h>
 #include <libempathy/empathy-chatroom-manager.h>
 #include <libempathy/empathy-account-manager.h>
+#include <libempathy/empathy-debugger.h>
 #include <libempathy/empathy-dispatcher.h>
 #include <libempathy/empathy-dispatch-operation.h>
 #include <libempathy/empathy-log-manager.h>
@@ -450,6 +451,31 @@ new_call_handler_cb (EmpathyCallFactory *factory, EmpathyCallHandler *handler,
        gtk_widget_show (GTK_WIDGET (window));
 }
 
+#ifdef ENABLE_DEBUG
+static void
+default_log_handler (const gchar *log_domain,
+    GLogLevelFlags log_level,
+    const gchar *message,
+    gpointer user_data)
+{
+       g_log_default_handler (log_domain, log_level, message, NULL);
+
+       /* G_LOG_DOMAIN = "empathy". No need to send empathy messages to the
+        * debugger as they already have in empathy_debug. */
+       if (log_level != G_LOG_LEVEL_DEBUG
+           || tp_strdiff (log_domain, G_LOG_DOMAIN)) {
+               EmpathyDebugger *dbg;
+               GTimeVal now;
+
+               dbg = empathy_debugger_get_singleton ();
+               g_get_current_time (&now);
+
+               empathy_debugger_add_message (dbg, &now, log_domain,
+                                             log_level, message);
+       }
+}
+#endif /* ENABLE_DEBUG */
+
 int
 main (int argc, char *argv[])
 {
@@ -514,6 +540,11 @@ main (int argc, char *argv[])
        gtk_window_set_default_icon_name ("empathy");
        textdomain (GETTEXT_PACKAGE);
 
+#ifdef ENABLE_DEBUG
+       /* Set up debugger */
+       g_log_set_default_handler (default_log_handler, NULL);
+#endif
+
         /* Setting up the bacon connection */
        startup_timestamp = get_startup_timestamp ();
        connection = bacon_message_connection_new ("empathy");