How many a times at work have you gone thru the logs looking for ERROR, WARNINGS, NOTES etc for more information about the generated problem?…I’ve been doing a lot like that lately for developing / debugging / lines of code for more information…I just wished I had a piece of code that would search and report me the location / line number and few more information about….luckily I found this macro in a SAS SUGI paper…here’s the link….
www2.sas.com/proceedings/sugi25/25/po/25p219.pdf
Then I had to customize it a little more to make the macro browse thru a folder of log files with a common runtime so that I can get all the errors into one report file…
Here’s an example and the full code below….
I intentionally induced couple of errors highlighted in RED font locations in these datasteps below….
| %let cyle_runtime=10OCT2010102001; | 
 
| proc printto log="&LogLoc.\example1_&cyle_runtime..log"; run; | 
 
| INPUT ID $ 1 SBP 2-4 DBP 5-7 GENDER $ 8 AGE 9-10 WT 11-13; | 
 
| proc printto log="&LogLoc.\example2_&cyle_runtime..log"; run; | 
 
|      INPUT @1 CATEGORY $9. @10 NUMBER 3.; | 
 
| PROC FREQ DATA=CDS ORDER=FREQ; WEIGHT NUMBER; | 
 
 
 
This code produces 2 log files at C:\SASDATA\ with timestamp on them..
Now running my SAS Macro %ReportErrorWarnings with the right parameters would result in a Error file at the same location…
%ReportErrorsWarnings(searchstr,searchloc,searchfiles,outfile,lines2display);
The macro from the SUGI paper was good…it created an arrow against the error / filename and linenumber…I customized the macro to browse thru a folder / location of logs etc… I agree it isn’t pretty but it works for me….This error file gives me the exact location (for eg line 20 in example 1 file and 2 lines above and below….). The number of lines to display above and below is again customizable though as the last parameter…
Similarly one can search for “ERROR:”,”WARNING:”, “NOTE:”,”not resolved”, “uninitialized”, “invalid data”, “_ERROR_=1″, “missing values”, “lock held by” etc…any other usual errors that you might want to track.
%ReportErrorsWarnings(searchstr,searchloc,searchfiles,outfile,lines2display);
Here’s the full code…with the repeatition of the above code again…for context…
| %macro recsinds(table,macvar);                                       | 
 
| /*---------------------------------------------------------------------- | 
 
|   this macro can be used to get the count of observations in a dataset | 
 
|   into a macrovariable that you give.                                  | 
 
|   usage: %recsinds(sashelp.class,macvar);                              | 
 
|   &macvar is the observation count of your dataset                     | 
 
|  ----------------------------------------------------------------------*/                                                                      | 
 
|      %let handle = %sysfunc(open(&table)); /* open the table */        | 
 
|         /* get the observation count into the macvar macro variable */ | 
 
|             %let &macvar = %sysfunc(attrn(&handle, nlobs));            | 
 
|              %let rc = %sysfunc(close(&handle)); /* close the dataset */ | 
 
|      /* write the record count to the log */                           | 
 
|       %put recsinds &table: &&&macvar.    &macvar=&&&macvar.;          | 
 
| %macro SearchErrorsWarnings(strg,loc,dsx,mm=1); | 
 
| * mm=# of lines to display before and after target lines. mm=0,1,2 ...etc.; | 
 
| filename dd "&loc.\&dsx."; | 
 
| %global nnn;  *nnn=# of records in dsx; | 
 
| data aa (keep= filen arrow linum xx); | 
 
|       infile dd length=ln end=last; | 
 
|       length llprted pthru 8 arrow $3 xx $120 filen $400; | 
 
|       *LLPRTed:line # of Last Line Printed; * PThru: to be line # of the last of: * the 2mm+1 lines to be displayed; | 
 
|       length %do jj=1 %to &mm; x&jj %end; XT $ 120; | 
 
|       * These store the mm lines that are; * to be printed prior to a Find; * Nextsave these mm lines; | 
 
|       %do jj=%eval(&mm-1) %to 1 %by -1; | 
 
|       input XT $varying120. ln; | 
 
|       if index (XT,"THE SAS SYSTEM")>0 then delete; | 
 
|       if index (XT,upcase("&strg"))>0 then | 
 
|             filen="========================================";linum=.; arrow= | 
 
|             * Found one!;     * Insert a blank line between finds;      * provided the scopes of two finds ;    * do not overlap; | 
 
|             if (_n_ > pthru + &mm + 1) & pthru > 0 | 
 
|                   filen="========================================";linum=.; arrow= | 
 
|             *Output mm lines preceding the find; | 
 
|                   if &jj<_n_ -="" code="" pthru="" then=""> | 
 
|             if &mm > 0 then arrow="-->"; | 
 
|             output; * Output the Found line;         | 
 
|             * Compute pthru, the line # of the ;            * last line of the scope so that the;        * next mm lines can be printed; | 
 
|                   * Outputting the next mm lines; | 
 
| if last then call symput( | 
 
| proc append base=allout data=aa; run; | 
 
| %mend SearchErrorsWarnings; | 
 
| %macro ReportErrorsWarnings(searchstr,searchloc,searchfiles,outfile,lines2display); | 
 
| %let dircmd0=%nrbquote(%str(dir /b /s %")%str(&searchloc.\&searchfiles.)%str(%")); | 
 
| FILENAME rootloc pipe "&dircmd0";  | 
 
| %if &nobs gt 0 %then %do; | 
 
|       %SearchErrorsWarnings(&searchstr.,&searchloc.,&&filen&k.,mm=&lines2display.); | 
 
|       retain filen linum arrow xx; | 
 
|       file "&outfile."lrecl=32767; | 
 
|             put "*****************************************************************************************************"; | 
 
| %mend ReportErrorsWarnings; | 
 
| %let cyle_runtime=10OCT2010102001; | 
 
| proc printto log="&LogLoc.\example1_&cyle_runtime..log"; run; | 
 
| INPUT ID $ 1 SBP 2-4 DBP 5-7 GENDER $ 8 AGE 9-10 WT 11-13; | 
 
| proc printto log="&LogLoc.\example2_&cyle_runtime..log"; run; | 
 
|      INPUT @1 CATEGORY $9. @10 NUMBER 3.; | 
 
| PROC FREQ DATA=CDS ORDER=FREQ; WEIGHT NUMBER; | 
 
| %ReportErrorsWarnings(ERROR:,&LogLoc.,*_&cyle_runtime..log,&LogLoc.\error_&cyle_runtime..txt,2); |