1
votes

I have a very large SAS program featuring about 50 sub-programs, each of which features many steps. At the moment, it will run until completion regardless of whether there is an error. I require it to halt and exit when an error occurs however.

Note that (I believe) the SYSERR macro is unsuitable for this task, as I would need to check SYSERR at the end of each individual step (e.g. after each DATA or PROC step), as SYSERR is reset after each step boundary; this would be a very time-consuming and error-prone task, as there are thousands of different step boundaries in each of my 50 sub-programs.

The kind of solution I envisage would involve checking the log file produced by each (of the 50) sub-programs immediately after they have been run, and then halting if an error appears in the log file (or proceeding to the next sub-program if there is no error). I cannot envisage how to do that however. Many thanks in advance.

1
Do you have SAS/Connect license? Perhaps you could spawn each of the subprograms as tasks or rsubmit blocks?Tom
I do have a SAS license, so yes I could try that (I'm relatively new to SAS so will need to look into this method however).Alex Michael

1 Answers

0
votes

Your solution to check the log, I believe, is the good one. Because you can filter the log on words like "WARNING" and "ERROR" or "ERROR:". You can copy past a log into excel and filter if lines are containing those error key words.

However, I have a solution in SAS here,

1) creation of the log with proc printto 2) close the proc printto redirection 3) analysis of the log automaticly with SAS

Here is the code for the macro function :

/**
*
* @dev Function to create a log for a program
* @param job The name of the job to be logged
*
*/

%macro runjob(job /*Enter the name of the job to log Ex: myjob*/);
    option fullstimer;

    %let runjob=%sysfunc(compress(&job._%sysfunc(datetime(),b8601dt)));
    data _null_;
        call symputx("runjob","&runjob.",'G');
    run;

    filename logfile "C:\LOG\&runjob..log";

    proc printto log=logfile new;
    run;

%mend runjob; /* %runjob(myjob); */


/**
*
* @dev Funtion to check if a table is empty
* @param inset The name of dataset to be checked
*
*/

%macro checkTableIfEmpty(inset /* Write the name of your dataset (ex: checklog) */);
    %let dsid = %sysfunc (open(&inset));


    %if &dsid ge 0 %then
        %let dsid = 1;
    %let anyobs = %sysfunc (attrn(&dsid,ANY));
    %let dsid = %sysfunc (close(&dsid));

    %put anyobs=&anyobs;

    %if &anyobs = 1 %then
        %do;

            data _null_;
                call symputx('checkTableIfEmpty',0,'G');
            run;

        %end;
    %else
        %do;

            data _null_;
                call symputx('checkTableIfEmpty',1,'G');
            run;

        %end;
%mend checkTableIfEmpty; /* %checkTableIfEmpty(checklog); */


/**
*
* @dev Function to filter a log file from SAS with words like "warning" and "error"
* @param inp The pathname of the log to be checked
*
*/

%macro checkLog(inp /* Write the pathname of the log to be checked (ex: myjob_20170818T161545.log) */);

    data empty_marker;
        length MSG $200;
        MSG='No error(s)/warning(s).';
    run;

    DATA CHECKLOG;
        LENGTH ROWS $200;
        LABEL ROWS = 'Messages from LOG';
        INFILE "&inp" TRUNCOVER;
        INPUT ROWS &;
        LINE = _N_;

        IF SUBSTR(ROWS,1,5)='ERROR' OR SUBSTR(ROWS,1,7)='WARNING' THEN
            OUTPUT;
    RUN;

    %checkTableIfEmpty(checklog);

    ODS HTML BODY="C:\LOG\log.html" STYLE=sasweb;
    TITLE1 "Messages from LOG";

    %if &checkTableIfEmpty = 0 %then
        %do;
            proc sql;
                select distinct(rows) from checklog;
            run;

        %end;
    %else
        %do;

            proc print data=empty_marker;
            run;

        %end;

    ODS HTML CLOSE;
%mend checkLog; /*  %checkLog(c:\LOG\myjob_20170818T161545.log);  */

You can then use those functions in a program like that

%let jobname=myjob;
/* START */
%runjob(&jobname);

...

/*END*/
proc printto;
run;

%checkLog(C:\LOG\&runjob..log);

You will get a html file in C:\LOG\LOG.html

Messages from LOG
ERROR: Ambiguous reference, column DateSent is in more than one table. 
ERROR: Ambiguous reference, column Operation_date is in more than one table. 
ERROR: Expression using equals (=) has components that are of different data types. 
ERROR: Expression using less than or equal (<=) has components that are of different data types. 

The duplicates lines are deleted, because of a "distinct" selection. It will be really easier to debug with each log of each sub programs.

Regards,