高效地停止大型 SAS 程序
Halting Large SAS Program Efficiently
我有一个非常大的 SAS 程序,包含大约 50 个子程序,每个子程序都有很多步骤。此时无论是否有错误都会运行直到完成。但是,我要求它在发生错误时停止并退出。
请注意(我相信)SYSERR 宏不适合此任务,因为我需要在每个单独步骤的末尾检查 SYSERR(例如,在每个 DATA 或 PROC 步骤之后),因为 SYSERR 在每个步骤后重置台阶边界;这将是一项非常耗时且容易出错的任务,因为在我的 50 个子程序中,每个子程序都有数千个不同的步骤边界。
我设想的解决方案包括检查每个(50 个)子程序生成的日志文件 运行,然后如果日志文件中出现错误则停止(如果没有错误则继续下一个子程序)。但是,我无法想象如何做到这一点。
非常感谢。
我相信你检查日志的解决方案是好的。
因为您可以过滤 "WARNING" 和 "ERROR" 或 "ERROR:" 等词的日志。
您可以将过去的日志复制到 excel 并过滤是否包含这些错误关键字的行。
不过,我这里有 SAS 的解决方案,
1) 使用 proc printto 创建日志
2) 关闭 proc printto 重定向
3)用SAS自动分析日志
宏函数的代码如下:
/**
*
* @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 0;
MSG='No error(s)/warning(s).';
run;
DATA CHECKLOG;
LENGTH ROWS 0;
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); */
然后您可以在这样的程序中使用这些函数
%let jobname=myjob;
/* START */
%runjob(&jobname);
...
/*END*/
proc printto;
run;
%checkLog(C:\LOG\&runjob..log);
你会在 C:\LOG\LOG.html
中得到一个 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.
由于 "distinct" 选择,重复的行被删除。
有了每个子程序的每个日志,调试起来真的会更容易。
此致,
我有一个非常大的 SAS 程序,包含大约 50 个子程序,每个子程序都有很多步骤。此时无论是否有错误都会运行直到完成。但是,我要求它在发生错误时停止并退出。
请注意(我相信)SYSERR 宏不适合此任务,因为我需要在每个单独步骤的末尾检查 SYSERR(例如,在每个 DATA 或 PROC 步骤之后),因为 SYSERR 在每个步骤后重置台阶边界;这将是一项非常耗时且容易出错的任务,因为在我的 50 个子程序中,每个子程序都有数千个不同的步骤边界。
我设想的解决方案包括检查每个(50 个)子程序生成的日志文件 运行,然后如果日志文件中出现错误则停止(如果没有错误则继续下一个子程序)。但是,我无法想象如何做到这一点。 非常感谢。
我相信你检查日志的解决方案是好的。 因为您可以过滤 "WARNING" 和 "ERROR" 或 "ERROR:" 等词的日志。 您可以将过去的日志复制到 excel 并过滤是否包含这些错误关键字的行。
不过,我这里有 SAS 的解决方案,
1) 使用 proc printto 创建日志 2) 关闭 proc printto 重定向 3)用SAS自动分析日志
宏函数的代码如下:
/**
*
* @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 0;
MSG='No error(s)/warning(s).';
run;
DATA CHECKLOG;
LENGTH ROWS 0;
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); */
然后您可以在这样的程序中使用这些函数
%let jobname=myjob;
/* START */
%runjob(&jobname);
...
/*END*/
proc printto;
run;
%checkLog(C:\LOG\&runjob..log);
你会在 C:\LOG\LOG.html
中得到一个 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.
由于 "distinct" 选择,重复的行被删除。 有了每个子程序的每个日志,调试起来真的会更容易。
此致,