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; * Next save 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); |