/* * 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 #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); } }