How to manage debugging messages at run-time

P

pozzugno

I'd like to have debug messages during execution of my applications. I'd also like to enable/disable these messages at run-time with a command-line parameter (i.e., -d), or exclude them all with a #define (in order to improveperformance).

Moreover, it should be nice if the user that launches the application couldselect a "debug level" (with -d option at command line) to choose the verbosity of output messages. So, each message has an associated level: if thedebug level set by the user is greater or equal the message debug level, it will be printed on stderr.

Do you have any suggestions how to implement these functionalities with pre-processor macros or C code? It would be nice if this works also for "multi-files" projects.

Thank you
 
E

Eric Sosman

I'd like to have debug messages during execution of my applications. I'd also like to enable/disable these messages at run-time with a command-line parameter (i.e., -d), or exclude them all with a #define (in order to improve performance).

Moreover, it should be nice if the user that launches the application could select a "debug level" (with -d option at command line) to choose the verbosity of output messages. So, each message has an associated level: if the debug level set by the user is greater or equal the message debug level, it will be printed on stderr.

Do you have any suggestions how to implement these functionalities with pre-processor macros or C code? It would be nice if this works also for "multi-files" projects.

The straightforward approach is to produce all the debug
output through a single function, like

void debug(int level, const char *format, ...);

(You could make the first parameter an enum if you like, or
perhaps a bit-mask of different message types.) This function
would check `level' against a global debug level set by your
command-line processing, and decide whether to generate output
or just do nothing.

You probably shouldn't worry too much about the performance
of a do-nothing debug() call. It will evaluate the arguments
and enter the function and return from it, and yes: That will
take some amount of time. Also, the mere presence of the call
might inhibit some compiler optimizations. But the effect is
not likely to be huge unless the call is executed a very large
number of times -- in which case it wouldn't be very useful,
because if you ever enabled it you'd drown in the output. But
if you really, Really, REALLY wanted to eliminate it you could
#define a varargs macro named debug that expanded to nothing.
(Leave the command-line processing in place, though, so as not
to antagonize people who've got `-d 0' in their scripts.)
 
B

Ben Bacarisse

I'd like to have debug messages during execution of my
applications. I'd also like to enable/disable these messages at
run-time with a command-line parameter (i.e., -d), or exclude them all
with a #define (in order to improve performance).

Moreover, it should be nice if the user that launches the application
could select a "debug level" (with -d option at command line) to
choose the verbosity of output messages. So, each message has an
associated level: if the debug level set by the user is greater or
equal the message debug level, it will be printed on stderr.

Do you have any suggestions how to implement these functionalities
with pre-processor macros or C code? It would be nice if this works
also for "multi-files" projects.

On simple way:

/* In the debug header: */
#define DBG_INFO 0
#define DBG_WARNING 1
#define DBG_ERROR 2
#define DBG_FATAL 3

#ifndef DBG_MIN_LEVEL
#define DBG_MIN_LEVEL 0
#endif

#define DBG_PRINT(level, ...) \
(void)(level >= DBG_MIN_LEVEL ? debug_print(level, __VA_ARGS__) : 0)

/* In the error reporting module: */
#include <stdarg.h>
#include <stdio.h>

int users_min_debug_level;

int debug_print(int level, const char *fmt, ...)
{
static const char *level_str[] = {
"info", "warning", "error", "fatal"
};
if (level >= users_min_debug_level) {
va_list args;
va_start(args, fmt);
fprintf(stderr, "my_prog %s: ", level_str[level]);
vfprintf(stderr, fmt, args);
va_end(args);
return fputc('\n', stderr);
}
else return 0;
}

/* Example use: */
/* Include the debug header */
#include <stdlib.h>

int main(int argc, char **argv)
{
if (argc > 1)
users_min_debug_level = atoi(argv[1]);
DBG_PRINT(DBG_INFO, "program starting");
if (argc > 2)
DBG_PRINT(DBG_WARNING, "too many args: %d", argc);
DBG_PRINT(DBG_ERROR, "entirely made up!");
DBG_PRINT(DBG_FATAL, "stopping");
exit(!0);
}


This relies on a basic compile optimisation and C99's __VA_ARGS__
mechanism. In C90 use the "double parentheses" trick (ask if you don't
know it). Obviously you can define shorthands for
DBG_PRINT(DBG_ERROR...) and so on, as well as doing things like never
turning off fatal error messages, but I wanted to keep things simple.
 
B

Barry Schwarz

I'd like to have debug messages during execution of my applications. I'd also like to enable/disable these messages at run-time with a command-line parameter (i.e., -d), or exclude them all with a #define (in order to improve performance).

Moreover, it should be nice if the user that launches the application could select a "debug level" (with -d option at command line) to choose the verbosity of output messages. So, each message has an associated level: if the debug level set by the user is greater or equal the message debug level, it will be printed on stderr.

Do you have any suggestions how to implement these functionalities with pre-processor macros or C code? It would be nice if this works also for "multi-files" projects.

You have requested two completely different control mechanisms. First
you describe a run-time option by specifying a parameter on the
command line. Second you describe a compile time option using
#define. Both are doable but you need to realize they are almost
completely independent.

Assume that you encapsulate displaying the debug messages in a
separate function with a prototype of
void debug_func(int level, char* message);
and you control the generation of calls to this function with a
compile time macro named debug_status.

Then in your debug header file (that you will include with every
source file that might display debug messages) you specify code of the
form
#if defined(debug_status)
#define debug_macro(a,b) debug_func(a,b)
#else
#define debug_macro(a,b) ((void)0)
#endif
During compilation of a source file, you define debug_status or not
depending on whether or not you want calls to the function generated.

In main(), you evaluate the command line parameter and store the
desired level in a global variable named debug_level. If the
parameter is not present, you set debug_level either very high or very
low depending on whether the default is print all debug messages or
print none.

Any place you want a debug message to be optionally displayed, you add
code of the form
debug_macro(desired_debug_level, "desired debug text");

In debug_func, you perform an initial test on level of the form
if level < debug_level
return;

This allows you to determine if any debug code gets generated at all.
If the code gets generated, it allows the user to determine what level
of messages clutter his output.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,981
Messages
2,570,188
Members
46,731
Latest member
MarcyGipso

Latest Threads

Top