2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2000 Wim Taymans <wtay@chello.be>
5 * gstinfo.c: INFO, ERROR, and DEBUG systems
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library 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 GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
24 #include "gst_private.h"
25 #include "gstelement.h"
28 extern gchar *_gst_progname;
31 /***** Categories and colorization *****/
32 static gchar *_gst_info_category_strings[] = {
66 * gst_get_category_name:
67 * @category: the category to return the name of
69 * Returns: string containing the name of the category
72 gst_get_category_name (gint category) {
73 if ((category >= 0) && (category < GST_CAT_MAX_CATEGORY))
74 return _gst_info_category_strings[category];
82 * 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed
84 * 30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white
85 * Background color codes:
86 * 40=black 41=red 42=green 43=yellow 44=blue 45=magenta 46=cyan 47=white
88 const gchar *_gst_category_colors[32] = {
89 [GST_CAT_GST_INIT] = "07;37",
90 [GST_CAT_COTHREADS] = "00;32",
91 [GST_CAT_COTHREAD_SWITCH] = "00;37;42",
92 [GST_CAT_AUTOPLUG] = "00;34",
93 [GST_CAT_AUTOPLUG_ATTEMPT] = "00;36;44",
94 [GST_CAT_PARENTAGE] = "01;37;41", // !!
95 [GST_CAT_STATES] = "00;31",
96 [GST_CAT_PLANNING] = "07;35",
97 [GST_CAT_SCHEDULING] = "00;35",
98 [GST_CAT_DATAFLOW] = "00;32",
99 [GST_CAT_BUFFER] = "00;32",
100 [GST_CAT_CAPS] = "04;34",
101 [GST_CAT_CLOCK] = "00;33", // !!
102 [GST_CAT_ELEMENT_PADS] = "01;37;41", // !!
103 [GST_CAT_ELEMENTFACTORY] = "01;37;41", // !!
104 [GST_CAT_PADS] = "01;37;41", // !!
105 [GST_CAT_PIPELINE] = "01;37;41", // !!
106 [GST_CAT_PLUGIN_LOADING] = "00;36",
107 [GST_CAT_PLUGIN_ERRORS] = "05;31",
108 [GST_CAT_PLUGIN_INFO] = "00;36",
109 [GST_CAT_PROPERTIES] = "00;37;44", // !!
110 [GST_CAT_THREAD] = "00;31",
111 [GST_CAT_TYPES] = "01;37;41", // !!
112 [GST_CAT_XML] = "01;37;41", // !!
113 [GST_CAT_NEGOTIATION] = "07;34",
114 [GST_CAT_REFCOUNTING] = "00;34:42",
115 [GST_CAT_EVENT] = "01;37;41", // !!
116 [GST_CAT_PARAMS] = "00;30;43", // !!
118 [GST_CAT_CALL_TRACE] = "",
122 /* colorization hash - DEPRACATED in favor of above */
123 inline gint _gst_debug_stringhash_color(gchar *file) {
125 while (file[0]) filecolor += *(char *)(file++);
126 filecolor = (filecolor % 6) + 31;
132 /***** DEBUG system *****/
133 GstDebugHandler _gst_debug_handler = gst_default_debug_handler;
134 guint32 _gst_debug_categories = 0x00000000;
137 * gst_default_debug_handler:
138 * @category: category of the DEBUG message
139 * @incore: if the debug handler is for core code.
140 * @file: the file the DEBUG occurs in
141 * @function: the function the DEBUG occurs in
142 * @line: the line number in the file
143 * @debug_string: the current debug_string in the function, if any
144 * @element: pointer to the #GstElement in question
145 * @string: the actual DEBUG string
147 * Prints out the DEBUG mesage in a variant of the following form:
149 * DEBUG(pid:cid):gst_function:542(args): [elementname] something neat happened
152 gst_default_debug_handler (gint category, gboolean incore,
153 const gchar *file, const gchar *function,
154 gint line, const gchar *debug_string,
155 void *element, gchar *string)
156 __attribute__ ((no_instrument_function));
159 gst_default_debug_handler (gint category, gboolean incore,
160 const gchar *file, const gchar *function,
161 gint line, const gchar *debug_string,
162 void *element, gchar *string)
165 gchar *elementname = empty,*location = empty;
166 int pthread_id = getpid();
167 int cothread_id = cothread_getcurrent();
168 #ifdef GST_DEBUG_COLOR
169 int pthread_color = pthread_id%6 + 31;
170 int cothread_color = (cothread_id < 0) ? 37 : (cothread_id%6 + 31);
173 if (debug_string == NULL) debug_string = "";
174 // if (category != GST_CAT_GST_INIT)
175 location = g_strdup_printf("%s:%d%s:",function,line,debug_string);
176 if (element && GST_IS_ELEMENT (element))
177 #ifdef GST_DEBUG_COLOR
178 elementname = g_strdup_printf (" \033[04m[%s]\033[00m", GST_OBJECT_NAME (element));
180 elementname = g_strdup_printf (" [%s]", GST_OBJECT_NAME (element));
183 #ifdef GST_DEBUG_COLOR
184 fprintf(stderr,"DEBUG(\033[00;%dm%5d\033[00m:\033[00;%dm%2d\033[00m)\033["
185 "%s;%sm%s%s\033[00m %s",
186 pthread_color,pthread_id,cothread_color,cothread_id,incore?"00":"01",
187 _gst_category_colors[category],location,elementname,string);
189 fprintf(stderr,"DEBUG(%5d:%2d)%s%s %s",
190 pthread_id,cothread_id,location,elementname,string);
191 #endif /* GST_DEBUG_COLOR */
193 if (location != empty) g_free(location);
194 if (elementname != empty) g_free(elementname);
201 * gst_debug_set_categories:
202 * @categories: bitmask of DEBUG categories to enable
204 * Enable the output of DEBUG categories based on the given bitmask.
205 * The bit for any given category is (1 << GST_CAT_...).
208 gst_debug_set_categories (guint32 categories) {
209 _gst_debug_categories = categories;
211 GST_INFO (0, "setting DEBUG categories to 0x%08X",categories);
215 * gst_debug_get_categories:
217 * Returns: the current bitmask of enabled DEBUG categories
218 * The bit for any given category is (1 << GST_CAT_...).
221 gst_debug_get_categories () {
222 return _gst_debug_categories;
226 * gst_debug_enable_category:
227 * @category: the category to enable
229 * Enables the given GST_CAT_... DEBUG category.
232 gst_debug_enable_category (gint category) {
233 _gst_debug_categories |= (1 << category);
234 if (_gst_debug_categories)
235 GST_INFO (0, "setting DEBUG categories to 0x%08X",_gst_debug_categories);
239 * gst_debug_disable_category:
240 * @category: the category to disable
242 * Disables the given GST_CAT_... DEBUG category.
245 gst_debug_disable_category (gint category) {
246 _gst_debug_categories &= ~ (1 << category);
247 if (_gst_debug_categories)
248 GST_INFO (0, "setting DEBUG categories to 0x%08X",_gst_debug_categories);
254 /***** INFO system *****/
255 GstInfoHandler _gst_info_handler = gst_default_info_handler;
256 guint32 _gst_info_categories = 0x00000001;
260 * gst_default_info_handler:
261 * @category: category of the INFO message
262 * @incore: if the info handler is for core code.
263 * @file: the file the INFO occurs in
264 * @function: the function the INFO occurs in
265 * @line: the line number in the file
266 * @debug_string: the current debug_string in the function, if any
267 * @element: pointer to the #GstElement in question
268 * @string: the actual INFO string
270 * Prints out the INFO mesage in a variant of the following form:
272 * INFO:gst_function:542(args): [elementname] something neat happened
275 gst_default_info_handler (gint category, gboolean incore,
276 const gchar *file, const gchar *function,
277 gint line, const gchar *debug_string,
278 void *element, gchar *string)
281 gchar *elementname = empty,*location = empty;
282 int pthread_id = getpid();
283 int cothread_id = cothread_getcurrent();
284 #ifdef GST_DEBUG_COLOR
285 int pthread_color = pthread_id%6 + 31;
286 int cothread_color = (cothread_id < 0) ? 37 : (cothread_id%6 + 31);
289 if (debug_string == NULL) debug_string = "";
290 if (category != GST_CAT_GST_INIT)
291 location = g_strdup_printf("%s:%d%s:",function,line,debug_string);
292 if (element && GST_IS_ELEMENT (element))
293 elementname = g_strdup_printf (" \033[04m[%s]\033[00m", GST_OBJECT_NAME (element));
296 #ifdef GST_DEBUG_ENABLED
298 #ifdef GST_DEBUG_COLOR
299 fprintf(stderr,"\033[01mINFO\033[00m (\033[00;%dm%5d\033[00m:\033[00;%dm%2d\033[00m)\033["
300 GST_DEBUG_CHAR_MODE ";%sm%s%s\033[00m %s\n",
301 pthread_color,pthread_id,cothread_color,cothread_id,
302 _gst_category_colors[category],location,elementname,string);
304 fprintf(stderr,"INFO (%5d:%2d)%s%s %s\n",
305 pthread_id,cothread_id,location,elementname,string);
306 #endif // GST_DEBUG_COLOR
309 #ifdef GST_DEBUG_COLOR
310 fprintf(stderr,"\033[01mINFO\033[00m:\033[" GST_DEBUG_CHAR_MODE ";%sm%s%s\033[00m %s\n",
311 location,elementname,_gst_category_colors[category],string);
313 fprintf(stderr,"INFO:%s%s %s\n",
314 location,elementname,string);
315 #endif // GST_DEBUG_COLOR
319 if (location != empty) g_free(location);
320 if (elementname != empty) g_free(elementname);
326 * gst_info_set_categories:
327 * @categories: bitmask of INFO categories to enable
329 * Enable the output of INFO categories based on the given bitmask.
330 * The bit for any given category is (1 << GST_CAT_...).
333 gst_info_set_categories (guint32 categories) {
334 _gst_info_categories = categories;
336 GST_INFO (0, "setting INFO categories to 0x%08X",categories);
340 * gst_info_get_categories:
342 * Returns: the current bitmask of enabled INFO categories
343 * The bit for any given category is (1 << GST_CAT_...).
346 gst_info_get_categories () {
347 return _gst_info_categories;
351 * gst_info_enable_category:
352 * @category: the category to enable
354 * Enables the given GST_CAT_... INFO category.
357 gst_info_enable_category (gint category) {
358 _gst_info_categories |= (1 << category);
359 if (_gst_info_categories)
360 GST_INFO (0, "setting INFO categories to 0x%08X",_gst_info_categories);
364 * gst_info_disable_category:
365 * @category: the category to disable
367 * Disables the given GST_CAT_... INFO category.
370 gst_info_disable_category (gint category) {
371 _gst_info_categories &= ~ (1 << category);
372 if (_gst_info_categories)
373 GST_INFO (0, "setting INFO categories to 0x%08X",_gst_info_categories);
378 /***** ERROR system *****/
379 GstErrorHandler _gst_error_handler = gst_default_error_handler;
382 * gst_default_error_handler:
383 * @file: the file the ERROR occurs in
384 * @function: the function the INFO occurs in
385 * @line: the line number in the file
386 * @debug_string: the current debug_string in the function, if any
387 * @element: pointer to the #GstElement in question
388 * @object: pointer to a related object
389 * @string: the actual ERROR string
391 * Prints out the given ERROR string in a variant of the following format:
393 * ***** GStreamer ERROR ***** in file gstsomething.c at gst_function:399(arg)
394 * Element: /pipeline/thread/element.src
395 * Error: peer is null!
396 * ***** attempting to stack trace.... *****
398 * At the end, it attempts to print the stack trace via GDB.
401 gst_default_error_handler (gchar *file, gchar *function,
402 gint line, gchar *debug_string,
403 void *element, void *object, gchar *string)
409 // if there are NULL pointers, point them to null strings to clean up output
410 if (!debug_string) debug_string = "";
411 if (!string) string = "";
413 // print out a preamble
414 fprintf(stderr,"***** GStreamer ERROR ***** in file %s at %s:%d%s\n",
415 file,function,line,debug_string);
417 // if there's an element, print out the pertinent information
419 if (GST_IS_OBJECT(element)) {
420 path = gst_object_get_path_string(element);
421 fprintf(stderr,"Element: %s",path);
422 chars = 9 + strlen(path);
425 fprintf(stderr,"Element ptr: %p",element);
426 chars = 15 + sizeof(void*)*2;
430 // if there's an object, print it out as well
432 // attempt to pad the line, or create a new one
434 for (i=0;i<(40-chars)/8+1;i++) fprintf(stderr,"\t");
436 fprintf(stderr,"\n");
438 if (GST_IS_OBJECT(object)) {
439 path = gst_object_get_path_string(object);
440 fprintf(stderr,"Object: %s",path);
443 fprintf(stderr,"Object ptr: %p",object);
447 fprintf(stderr,"\n");
448 fprintf(stderr,"Error: %s\n",string);
452 fprintf(stderr,"***** attempting to stack trace.... *****\n");
454 g_on_error_stack_trace (_gst_progname);
461 /***** DEBUG system *****/
462 GHashTable *__gst_function_pointers = NULL;
463 // FIXME make this thread specific
464 static GSList* stack_trace = NULL;
466 gchar *_gst_debug_nameof_funcptr (void *ptr) __attribute__ ((no_instrument_function));
469 _gst_debug_nameof_funcptr (void *ptr)
473 if (__gst_function_pointers && (ptrname = g_hash_table_lookup(__gst_function_pointers,ptr))) {
474 return g_strdup(ptrname);
475 } else if (dladdr(ptr,&dlinfo) && dlinfo.dli_sname) {
476 return g_strdup(dlinfo.dli_sname);
478 return g_strdup_printf("%p",ptr);
484 #ifdef GST_ENABLE_FUNC_INSTRUMENTATION
485 void __cyg_profile_func_enter(void *this_fn,void *call_site) __attribute__ ((no_instrument_function));
486 void __cyg_profile_func_enter(void *this_fn,void *call_site)
488 gchar *name = _gst_debug_nameof_funcptr (this_fn);
489 gchar *site = _gst_debug_nameof_funcptr (call_site);
491 GST_DEBUG(GST_CAT_CALL_TRACE, "entering function %s from %s\n", name, site);
492 stack_trace = g_slist_prepend (stack_trace, g_strdup_printf ("%8p in %s from %p (%s)", this_fn, name, call_site, site));
498 void __cyg_profile_func_exit(void *this_fn,void *call_site) __attribute__ ((no_instrument_function));
499 void __cyg_profile_func_exit(void *this_fn,void *call_site)
501 gchar *name = _gst_debug_nameof_funcptr (this_fn);
503 GST_DEBUG(GST_CAT_CALL_TRACE, "leaving function %s\n", name);
504 g_free (stack_trace->data);
505 stack_trace = g_slist_delete_link (stack_trace, stack_trace);
511 gst_debug_print_stack_trace (void)
513 GSList *walk = stack_trace;
517 walk = g_slist_next (walk);
520 gchar *name = (gchar *) walk->data;
522 g_print ("#%-2d %s\n", count++, name);
524 walk = g_slist_next (walk);
529 gst_debug_print_stack_trace (void)
533 #endif /* GST_ENABLE_FUNC_INTSTRUMENTATION */