Include Debugging Code in Your Programs

From sasCommunity
Jump to: navigation, search

Many programmers will add debugging features (e.g., PROC PRINT, PROC FREQ, PROC CONTENTS) to their programs and then remove them or comment them out when they think they are done testing. Instead of doing this, consider using macros that can be controlled by a global macro variable to turn debugging output on/off.

A sample program is shown below, along with three sample macros for PROC PRINT, PROC FREQ, and PROC CONTENTS that can be added to your SAS autocall library.

Sample Program

Consider the following simple program that reads in some data, applies some logic, and includes debugging output based on a value being specified for the macro variable Debug. Note how the debugging macros use %GLOBAL to ensure that the macro variable exists. Thus, if the Debug macro is set to null or not defined at all, no debugging output is produced.

The programmer can easily turn debugging on/off by either updating or removing the %LET statement.

%let Debug = Y; /* turn debuggin on - any non-blank value turns debugging on */
 
data demoTest;
 set sashelp.class;
 if sex = 'M' and age le 12 then Category = '1';
 else if sex = 'F' and age le 13 then Category = '2';
 else if age lt 16 then Category = '3';
 else Category = '4';
run;
 
/* display all the rows */
%testPrint(data=demoTest);
run;
/* verify data set attributes */
%testContents(data=demoTest)
run;
/* verify recode logic */
%testFreq(data=demoTest,tables=Category*Sex*Age)
run;

testContents Macro

%macro testContents
    (data      = _last_,  /* data set to print if debugging turned on  */
     titleline = 3,       /* title line for test print title */
     options   =          /* used to pass in any other desired options */
    ); 
 
/*------------------------------------------------------------------------------------------
  Copyright (c) 2006 Henderson Consulting Services
            May be freely downloaded and distributed as long as the source is acknowledged.
  PROGRAMMER   : Don Henderson
  PURPOSE      : Invoke PROC CONTENTS if debugging option is enabled.
 
                 Debugging can be turned on by setting the global macro variable "debug"
                 to a non-null value.
 
                 No run; statement is included after the PROC CONTENTS so the programmer can
                 follow the testContents macro call with their own title and footnote
                 statements. If debugging is not turned on, the title/footnote statements
                 will only be used for later output if they are not over-written.
 
|------------------------------------------------------------------------------------------|
|  MAINTENANCE HISTORY                                                                     |
|------------------------------------------------------------------------------------------|
|  DATE    |     BY    | DESCRIPTION                                                       |
|----------|-----------|-------------------------------------------------------------------|  
| Dec 2006 |  Don H    | Original Creation
|-----------------------------------------------------------------------------------------*/
 
 %global Debug;  /* ensure it exists */
 
 %if %length(&Debug) gt 0 %then
 %do;  /* flag set - produce debugging output */
 
    run;
    proc contents data=&data &options;
     title&titleLine "Test PROC CONTENTS for &data";
 
   /* no run; statement provided so the macro call call be followed by
      programmer specfied title and footnote statements which are then
      followed by a run; statement
   */
 
 %end; /* flag set - produce debugging output */
 
%mend testContents;

testFreq Macro

%macro testFreq
    (data         = _last_,  /* data set to report on if debugging turned on  */
     tables       = ,        /* frequency tables to generate */  
     tableoptions = list,    /* options for the tables statement, eg, LIST, MISSING, etc. */
     titleline    = 3        /* title line for test print title */
    ); 
 
/*------------------------------------------------------------------------------------------
  Copyright (c) 2006 Henderson Consulting Services
            May be freely downloaded and distributed as long as the source is acknowledged.
 
  PROGRAMMER   : Don Henderson
  PURPOSE      : Invoke PROC FREQ if debugging option is enabled.
 
                 Debugging can be turned on by setting the global macro variable "debug"
                 to a non-null value.
 
                 No run; statement is included after the PROC FREQ so the programmer can
                 follow the testFreq macro call with their own title and footnote
                 statements. If debugging is not turned on, the title/footnote statements
                 will only be used for later output if they are not over-written.
 
|------------------------------------------------------------------------------------------|
|  MAINTENANCE HISTORY                                                                     |
|------------------------------------------------------------------------------------------|
|  DATE    |     BY    | DESCRIPTION                                                       |
|----------|-----------|-------------------------------------------------------------------|  
| Dec 2006 |  Don H    | Original Creation
|-----------------------------------------------------------------------------------------*/
 
 %global Debug;  /* ensure it exists */
 
 %if %length(&tables) = 0 %then
 %do;  /* required parameter not specified */
 
    %put ERROR: Parameter Tables not specified. It is a required parameter for macro testFreq.;
 
 %end; /* required parameter not specified */
 %else %if %length(&Debug) gt 0 %then
 %do;  /* flag set - produce debugging output */
 
    run;
    proc freq data=&data;
     tables &tables/&tableOptions;
     title&titleLine "Test PROC FREQ for &data";
 
   /* no run; statement provided so the macro call call be followed by
      programmer specfied title and footnote statements which are then
      followed by a run; statement
   */
 
 %end; /* flag set - produce debugging output */
 
%mend testFreq;

testPrint Macro

%macro testPrint
    (data      = _last_,  /* data set to print if debugging turned on  */
     var       = _all_,   /* variables to print */  
     obs       = ,        /* number of observations to print */
     titleline = 3,       /* title line for test print title */
     options   = label    /* used to pass in any other desired options */
    ); 
 
/*------------------------------------------------------------------------------------------
  Copyright (c) 2006 Henderson Consulting Services
            May be freely downloaded and distributed as long as the source is acknowledged.
 
  PROGRAMMER   : Don Henderson
  PURPOSE      : Invoke PROC PRINT if debugging option is enabled.
 
                 Debugging can be turned on by setting the global macro variable "debug"
                 to a non-null value.
 
                 No run; statement is included after the PROC PRINT so the programmer can
                 follow the testPrint macro call with their own title and footnote
                 statements. If debugging is not turned on, the title/footnote statements
                 will only be used for later output if they are not over-written.
 
|------------------------------------------------------------------------------------------|
|  MAINTENANCE HISTORY                                                                     |
|------------------------------------------------------------------------------------------|
|  DATE    |     BY    | DESCRIPTION                                                       |
|----------|-----------|-------------------------------------------------------------------|  
| Dec 2006 |  Don H    | Original Creation
|-----------------------------------------------------------------------------------------*/
 
 %global Debug;  /* ensure it exists */
 
 %if %length(&obs) ne 0 %then
 %do;  /* subset of observations being printed */
 
    %let titleLine = title&titleLine "Test Print of &obs Observations from &data";
    %let obs = (obs=&obs);
 
 %end; /* subset of observations being printed */
 %else %let titleLine = title&titleLine "Test Print of &data";
 
 %if %length(&Debug) gt 0 %then
 %do;  /* flag set - produce debugging output */
 
    run;
    proc print data=&data&obs &options;
    &titleLine;
 
   /* no run; statement provided so the macro call call be followed by
      programmer specfied title and footnote statements which are then
      followed by a run; statement
   */
 
 %end; /* flag set - produce debugging output */
 
%mend testPrint;