Trac is being migrated to new services! Issues can be found in our new YouTrack instance and WIKI pages can be found on our website.

Changes between Version 1 and Version 2 of CHowTo/DebugAPIHowTo


Ignore:
Timestamp:
Jul 18, 2007, 4:42:10 PM (17 years ago)
Author:
John Bailey
Comment:

Debug API How-To document is complete; comments appreciated.

Legend:

Unmodified
Added
Removed
Modified
  • CHowTo/DebugAPIHowTo

    v1 v2  
    11= Debug API How-To =
    2 This page is a temporary placeholder pending completion of this document.
     2One question that we used to see quite frequently with plugin development was, "How do I get debugging messages?"  Libpurple already provides a facility for this.  It's called the Debug API.  In this document we'll dig into this API with a brand-new plugin.
     3
     4[[TOC(inline,noheading)]]
     5
     6== About Debugging with Libpurple's Debug API ==
     7The beauty of the debug API in libpurple is that you can print as much information as is necessary to help you find bugs in your code without worrying about distracting the user--the user interface decides when and where to display the debugging information.  Once you have the bugs worked out, you can still leave the debugging messages there and it won't hurt anything.
     8
     9Libpurple provides a generic `purple_debug()` function for use in printing messages, but at the same time provides convenience functions for each debugging level.  This How-To will focus on using the convenience functions for the convenience and simplicity they provide, as well as for their attractiveness to the lazy typist.
     10
     11== Debug Levels ==
     12The documentation for the [/doxygen/dev/html/debug_8h.html debug.h] header file shows an enumeration listing each of the 6 debug levels defined.  Only the last five are typically used when writing debug messages, leaving `PURPLE_DEBUG_ALL` primarily for the UI's use.
     13
     14The other debugging levels are fairly straightforward, and I'll leave it to you to read the [/doxygen/dev/html/debug_8h.html#e4789d7a365e1d70da6f232248a08259 enum's documentation] for the brief descriptions.  For the most part we're going to want to use `PURPLE_DEBUG_MISC` and `PURPLE_DEBUG_INFO` for plugin messages, but there are obviously situations in which we'll need other levels.
     15
     16== Using the Debug Functions ==
     17If you browse the [/doxygen/dev/html/debug_8h.html debug.h] doxygen documentation further, you will see that all of the debug functions provided show a `...` for their final parameter.  This means that the function is a variadic function, which can take a variable number of parameters.  These functions are defined as such because they behave like the standard library's `printf()` function in many ways.  You will see the evidence of this once we show the actual source of the plugin.
     18
     19You will also notice that the functions take a category parameter.  The category makes it easy to tell what generated each specific debug message when reading the debug log.  You can use pretty much anything you want here, but for the purposes of demonstration, we're going to stick with the plugin ID for the category.  The recommended best practice is to use the plugin's ID or static name.
     20
     21== Writing the Debug Example Plugin ==
     22This plugin will eventually be included as an example plugin in the libpurple source, but it is not part of Pidgin 2.0.2, which the rest of the How-To documents assume you are using.  We are going to continue this assumption here.  In fact, we're going to continue all the assumptions set forth in the [wiki:CHowTo/BasicPluginHowto Basic C Plugin How-To]
     23
     24Go back to `~/development/pidgin-2.0.2/libpurple/plugins` and fire up your favorite editor on a new file called `debug-example.c`.  The contents of the file will be this:
     25 {{{
     26#!c
     27/* We're including glib.h again for the gboolean type. */
     28#include <glib.h>
     29
     30/* This is the required definition of PURPLE_PLUGINS as required for a plugin */
     31#define PURPLE_PLUGINS
     32
     33/* Here we're including the necessary libpurple headers for this plugin.  Note
     34 * that we're including them in alphabetical order.  This isn't necessary but
     35 * we do this throughout our source for consistency. */
     36#include "debug.h"
     37#include "plugin.h"
     38#include "version.h"
     39
     40/* It's more convenient to type PLUGIN_ID all the time than it is to type
     41 * "core-debugexample", so define this convenience macro. */
     42#define PLUGIN_ID "core-debugexample"
     43
     44/* Common practice in third-party plugins is to define convenience macros for
     45 * many of the fields of the plugin info struct, so we'll do that for the
     46 * purposes of demonstration. */
     47#define PLUGIN_AUTHOR "John Bailey <rekkanoryo@rekkanoryo.org>"
     48
     49/* As we've covered before, libpurple calls this function, if present, when it
     50 * loads the plugin.  Here we're using it to show off the capabilities of the
     51 * debug API and just blindly returning TRUE to tell libpurple it's safe to
     52 * continue loading. */
     53static gboolean
     54plugin_load(PurplePlugin *plugin)
     55{
     56    /* Define these for convenience--we're just using them to show the
     57     * similarities of the debug functions to the standard printf(). */
     58    gint i = 256;
     59    gfloat f = 512.1024;
     60    const gchar *s = "example string";
     61
     62    /* Introductory message */
     63    purple_debug_info(PLUGIN_ID,
     64            "Called plugin_load.  Beginning debug demonstration\n");
     65
     66    /* Show off the debug API a bit */
     67    purple_debug_misc(PLUGIN_ID,
     68            "MISC level debug message.  i = %d, f = %f, s = %s\n", i, f, s);
     69
     70    purple_debug_info(PLUGIN_ID,
     71            "INFO level debug message.  i = %d, f = %f, s = %s\n", i, f, s);
     72
     73    purple_debug_warning(PLUGIN_ID,
     74            "WARNING level debug message.  i = %d, f = %f, s = %s\n", i, f, s);
     75
     76    purple_debug_error(PLUGIN_ID,
     77            "ERROR level debug message.  i = %d, f = %f, s = %s\n", i, f, s);
     78
     79    purple_debug_fatal(PLUGIN_ID,
     80            "FATAL level debug message. i = %d, f = %f, s = %s\n", i, f, s);
     81
     82    /* Now just return TRUE to tell libpurple to finish loading. */
     83    return TRUE;
     84}
     85
     86static PurplePluginInfo info = {
     87    PURPLE_PLUGIN_MAGIC,        /* magic number */
     88    PURPLE_MAJOR_VERSION,       /* purple major */
     89    PURPLE_MINOR_VERSION,       /* purple minor */
     90    PURPLE_PLUGIN_STANDARD,     /* plugin type */
     91    NULL,                       /* UI requirement */
     92    0,                          /* flags */
     93    NULL,                       /* dependencies */
     94    PURPLE_PRIORITY_DEFAULT,    /* priority */
     95
     96    PLUGIN_ID,                  /* id */
     97    "Debug API Example",        /* name */
     98    "1.0",                      /* version */
     99    "Debug API Example",        /* summary */
     100    "Debug API Example",        /* description */
     101    PLUGIN_AUTHOR,              /* author */
     102    "http://pidgin.im",         /* homepage */
     103
     104    plugin_load,                /* load */
     105    NULL,                       /* unload */
     106    NULL,                       /* destroy */
     107
     108    NULL,                       /* ui info */
     109    NULL,                       /* extra info */
     110    NULL,                       /* prefs info */
     111    NULL,                       /* actions */
     112    NULL,                       /* reserved */
     113    NULL,                       /* reserved */
     114    NULL,                       /* reserved */
     115    NULL                        /* reserved */
     116};
     117
     118static void
     119init_plugin(PurplePlugin *plugin)
     120{
     121}
     122
     123PURPLE_INIT_PLUGIN(debugexample, init_plugin, info)
     124 }}}
     125
     126Now that we have the plugin, we need to compile and install it.
     127
     128== Compiling, Installing, and Testing the Plugin ==
     129As before, run `make debug-example.so` (`make -f Makefile.mingw debug-example.dll` for you Windows types) to build the plugin.  Copy the resulting `debug-example.so` to `~/.purple/plugins`, or copy the resulting `debug-example.dll` to `%APPDATA%\.purple\plugins`.
     130
     131Since we're continuing our assumptions, we're going to still assume that you're using Pidgin.  Open the Debug Window (located on the Help menu).  Resize it so it's rather large so we can easily see all the messages.  Now open the Plugins dialog.  In the Debug Window you'll see a ''lot'' of information about plugins scroll by as libpurple reprobes all the plugins available to it.  Now find the "Debug API Example" entry in the dialog.  Check the box and watch what appears in the Debug Window.  You may need to scroll back just a bit to see the six messages that print.  You should see something like this:
     132
     133  {{{
     134#!html
     135<div class="code">
     136<font color="black">(10:17:36) core-debugexample: Called plugin_load.  Beginning debug demonstration</font><br /><font color="gray">(10:17:36) core-debugexample: MISC level debug message.  i = 256, f = 512.102417, s = example string</font><br /><font color="black">(10:17:36) core-debugexample: INFO level debug message.  i = 256, f = 512.102417, s = example string</font><br /><font color="brown">(10:17:36) core-debugexample: WARNING level debug message.  i = 256, f = 512.102417, s = example string</font><br /><font color="red">(10:17:36) core-debugexample: ERROR level debug message.  i = 256, f = 512.102417, s = example string</font><br /><font color="red"><b>(10:17:36) core-debugexample: FATAL level debug message. i = 256, f = 512.102417, s = example string</b></font>
     137</div>
     138 }}}
     139
     140As you can see, the similarities to `printf()` are obvious and quite useful.  You probably also noticed that we assigned the value of 512.1024 to the variable `f`, yet the debug statement printed 512.102417 (or similar, depending on a number of factors).  This is expected; floating-point values are not exact.  Most C tutorials will cover this in much better detail than we can here, so if this is confusing or you're a bit rusty in that area, your favorite search engine can turn up information for your consumption on the subject.  The value of `f` being slightly off here doesn't really matter--all this was for demonstrative purposes only, and could have been corrected by using `%.4f` as the conversion specifier instead of simply `%f`.
     141
     142The output in the debug window shows that the different debug levels are handled differently depending on their severity, with colors changing, and finally bold-faced type at the FATAL level.  Finch and other UIs will handle this differently.
     143
     144== Additional Functions in the Debug API ==
     145There are additional functions in the Debug API that have not been covered here.  The functions `purple_debug_set_enabled()`, `purple_debug_is_enabled()`, `purple_debug_get_ui_ops()`, `purple_debug_set_ui_ops()`, and `purple_debug_init()` are all functions that plugins generally won't need or want to touch.  These functions are mainly intended for use in libpurple UIs.  In theory, a plugin could replace the UI's existing debug handling by replacing the ui_ops structure that the UI supplied to libpurple, but that is beyond the scope of this document and likely completely unnecessary.
     146
     147== Beyond the Debug API ==
     148The Debug API is a quite useful subset of the libpurple API, but it is far from the end of things you can do in plugins.  This document is finished, but other documents in the [wiki:CHowTo C Plugin How-To] will build upon these examples and the previous examples in the series while introducing more features of libpurple.
All information, including names and email addresses, entered onto this website or sent to mailing lists affiliated with this website will be public. Do not post confidential information, especially passwords!