2006-07-22 Jonathan Matthew <jonathan@kaolin.wh9.net>
[rhythmbox.git] / lib / rb-debug.c
blobc1faeb711d67be5284d8661bd152d0b9be99d670
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
3 * arch-tag: Implementation of simple Rhythmbox debugging interface
5 * Copyright (C) 2002 Jorn Baayen
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21 * NOTES: log domain hack stolen from nautilus
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdarg.h>
29 #include <signal.h>
30 #include <time.h>
32 #include <glib.h>
34 #include "rb-debug.h"
36 static void log_handler (const char *domain,
37 GLogLevelFlags level,
38 const char *message,
39 gpointer data);
41 static const char *debug_everything = "everything";
42 static const char *debug_match = NULL;
44 /* Our own funky debugging function, should only be used when something
45 * is not going wrong, if something *is* wrong use g_warning.
47 void
48 rb_debug_real (const char *func,
49 const char *file,
50 const int line,
51 gboolean newline,
52 const char *format, ...)
54 va_list args;
55 char buffer[1025];
56 char *str_time;
57 time_t the_time;
59 if (debug_match == NULL ||
60 (debug_match != debug_everything &&
61 (strstr (file, debug_match) == NULL) &&
62 (strstr (func, debug_match) == NULL)))
63 return;
65 va_start (args, format);
67 g_vsnprintf (buffer, 1024, format, args);
69 va_end (args);
71 time (&the_time);
72 str_time = g_new0 (char, 255);
73 strftime (str_time, 254, "%H:%M:%S", localtime (&the_time));
75 g_printerr (newline ? "(%s) [%p] [%s] %s:%d: %s\n" : "(%s) [%p] [%s] %s:%d: %s",
76 str_time, g_thread_self (), func, file, line, buffer);
78 g_free (str_time);
81 void
82 rb_debug_init (gboolean debug)
84 rb_debug_init_match (debug ? debug_everything : NULL);
87 void
88 rb_debug_init_match (const char *match)
90 guint i;
92 /* This is a workaround for the fact that there is not way to
93 * make this useful debugging feature happen for ALL domains.
95 * What we did here is list all the ones we could think of that
96 * were interesting to us. It's OK to add more to the list.
98 static const char * const standard_log_domains[] = {
99 "",
100 "Bonobo",
101 "BonoboUI",
102 "Echo",
103 "Eel",
104 "GConf",
105 "GConf-Backends",
106 "GConf-Tests",
107 "GConfEd",
108 "GLib",
109 "GLib-GObject",
110 "GModule",
111 "GThread",
112 "GStreamer",
113 "Gdk",
114 "Gdk-Pixbuf",
115 "GdkPixbuf",
116 "Glib",
117 "Gnome",
118 "GnomeCanvas",
119 "GnomePrint",
120 "GnomeUI",
121 "GnomeVFS",
122 "GnomeVFS-CORBA",
123 "GnomeVFS-pthread",
124 "GnomeVFSMonikers",
125 "Gtk",
126 "Rhythmbox",
127 "RhythmDB",
128 "MonkeyMedia",
129 "ORBit",
130 "ZVT",
131 "libIDL",
132 "libgconf-scm",
133 "libglade",
134 "libgnomevfs",
135 "librsvg",
138 debug_match = match;
140 if (debug_match != NULL)
141 for (i = 0; i < G_N_ELEMENTS (standard_log_domains); i++)
142 g_log_set_handler (standard_log_domains[i], G_LOG_LEVEL_MASK, log_handler, NULL);
144 rb_debug ("Debugging enabled");
147 /* Raise a SIGINT signal to get the attention of the debugger.
148 * When not running under the debugger, we don't want to stop,
149 * so we ignore the signal for just the moment that we raise it.
151 void
152 rb_debug_stop_in_debugger (void)
154 void (* saved_handler) (int);
156 saved_handler = signal (SIGINT, SIG_IGN);
157 raise (SIGINT);
158 signal (SIGINT, saved_handler);
161 /* Stop in the debugger after running the default log handler.
162 * This makes certain kinds of messages stop in the debugger
163 * without making them fatal (you can continue).
165 static void
166 log_handler (const char *domain,
167 GLogLevelFlags level,
168 const char *message,
169 gpointer data)
171 g_log_default_handler (domain, level, message, data);
172 if ((level & (G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING)) != 0)
174 rb_debug_stop_in_debugger ();
178 struct RBProfiler
180 GTimer *timer;
181 char *name;
184 RBProfiler *
185 rb_profiler_new (const char *name)
187 RBProfiler *profiler;
189 if (debug_match == NULL)
190 return NULL;
192 profiler = g_new0 (RBProfiler, 1);
193 profiler->timer = g_timer_new ();
194 profiler->name = g_strdup (name);
196 g_timer_start (profiler->timer);
198 return profiler;
201 void
202 rb_profiler_dump (RBProfiler *profiler)
204 gulong elapsed;
205 double seconds;
207 if (debug_match == NULL)
208 return;
209 if (profiler == NULL)
210 return;
212 seconds = g_timer_elapsed (profiler->timer, &elapsed);
214 rb_debug ("PROFILER %s %ld ms (%f s) elapsed", profiler->name,
215 elapsed / (G_USEC_PER_SEC / 1000), seconds);
218 void
219 rb_profiler_reset (RBProfiler *profiler)
221 if (debug_match == NULL)
222 return;
223 if (profiler == NULL)
224 return;
226 g_timer_start (profiler->timer);
229 void
230 rb_profiler_free (RBProfiler *profiler)
232 if (debug_match == NULL)
233 return;
234 if (profiler == NULL)
235 return;
237 g_timer_destroy (profiler->timer);
238 g_free (profiler->name);
239 g_free (profiler);
242 /* Profiling */
244 static int profile_indent;
246 static void
247 profile_add_indent (int indent)
249 profile_indent += indent;
250 if (profile_indent < 0) {
251 g_error ("You screwed up your indentation");
255 void
256 _rb_profile_log (const char *func,
257 const char *file,
258 int line,
259 int indent,
260 const char *msg1,
261 const char *msg2)
263 char *str;
265 if (indent < 0) {
266 profile_add_indent (indent);
269 if (profile_indent == 0) {
270 str = g_strdup_printf ("MARK: [%s %s %d] %s %s", file, func, line, msg1 ? msg1 : "", msg2 ? msg2 : "");
271 } else {
272 str = g_strdup_printf ("MARK: %*c [%s %s %d] %s %s", profile_indent - 1, ' ', file, func, line, msg1 ? msg1 : "", msg2 ? msg2 : "");
275 access (str, F_OK);
277 g_free (str);
279 if (indent > 0) {
280 profile_add_indent (indent);