I am trying to figure out how I can adapt a macro outlined in this paper: http://support.sas.com/resources/papers/proceedings14/1762-2014.pdf
It analyzes the SAS log during batch mode processing. I am looking for a way to parse my log for key messages, but I don't want to send to email like in the paper, rather I want to create a JSON payload. I am not advanced enough with macro programs to decipher how to adapt this code for my needs. I've read up on ways to parse the SAS log and I really like that this one executes during batch mode. Anyone willing to give it a shot? Can you show me how to strip this macro down to just the "chase the log" part? I figure if I can get it down to just that component, I can spend more time figuring out the JSON piece. Or have another suggestion for how to parse the log in batch mode? I'm using 9.4 on Windows.
Here's the code from the paper (sorry for the lack of indentation):
*This first part is placed at the beginning of your program;
%macro chasethelog(emailid=, EndProcess=);
data _null_;
file 'chasethelog.sas';
put '%let StartTime = ' "%sysfunc(putn(%sysfunc(datetime()), datetime16.));";
put '%let User= '"%upcase(&SYSUSERID);";
put '%let PgmName='"%scan(%scan(&SYSPROCESSNAME,2,' '),1,'.');";
put '%let emailid=' "&emailid;";
put '%let procid='"&SYSJOBID;";
put '%let EndProcess=' "&EndProcess;";
put '%include "'chasethelog_main.sas";';
run;
systask command "chasethelog.sas";
%mend chasethelog;
%macro chasethelog_main;
%let JobStatus=1;
%let Toread=1;
%let EndJob=0;
%let TraceWarn=0;
%let TraceError=0;
%let Iteration=0;
%do %until(&JobStatus=0);
%let SendMail=0;
%let Track=0;
%let WarnFlag=0;
%let ErrorFlag=0;
filenamerunlog pipe "cat &PgmName..log";
data a;
infilerunloglrecl=32000 length=linelength end=eof %if &Iteration>0
%then firstobs=&toread;;
input logline $varying700. linelength ;
if index(logline,'ERROR:') or
upcase(substr(left(logline),1,8))='WARNING:' or index(logline,'uninitialized') > 0
or
index(logline,'repeats of BY values') > 0 or
index(logline,'W.D format') > 0 or
index(logline,'Invalid') > 0 or index(logline,'Mathematical
operations could not') > 0 or upcase(substr(left(logline),1,10))='USER ERROR' or
upcase(substr(left(logline),1,12))='USER WARNING' or
index(logline,'outside the axis range') > 0 or
index(logline,'values have been converted') or
index(logline,'Missing') >0
then do;
callsymputx('SendMail', '1');
if index(logline,'ERROR:')=0 then call
symputx('WarnFlag',1);
output;
end;
if index(logline,'ERROR:') then do;
callsymputx('ErrorFlag',1);
if "&EndProcess"="Y" and &EndJob=0 then call
symputx('EndJob',1);
end;
callsymputx ('nrecord',_n_);
run;
%let toread=%eval(&nrecord+&toread);
%let TraceWarn=%eval(&TraceWarn+&WarnFlag);
%let TraceError=%eval(&TraceError+&ErrorFlag);
%if &SendMail=1 and &emailid^= %then %do;
filenamesendm email to="&emailid" Subject=%if &ErrorFlag=1 %then
"Error Occured in the &PgmName..sas Program"
%else "Suspicious lines Occured in the &PgmName..sas
Program";;
data a;
set a;
output;
logline='';
output;
run;
data _null_;
set a;
filesendm;
put logline;
run;
%end;
%if &EndJob %then %do;
x "kill &procid";
%if &emailid^= %then filename Stats email to="&emailid"
Subject="%upcase(&PgmName.).sas Program is done with ERROR"; ;
data _null_;
file Stats;
run;
%let JobStatus=0;
%gotoEndLogCheck;
%end;
filenameprc pipe "ps u";
data b;
infileprc length=len;
input process $varying900. len;
if index(process,"&PgmName") and index(process,"&procid");
callsymputx('track',scan(process,2,' '));
run;
%if &track^=&procid %then %do;
%let JobStatus=0;
%if &emailid^= %then %do;
filename Status email to="&emailid" %if &TraceError>0 %then
Subject="%upcase(&PgmName.).sas Program is done with ERROR";
%else %if &TraceWarn>0 %then
Subject="%upcase(&PgmName.).sas Program is done with Warning";
%else Subject="%upcase(&PgmName.).sas Program is with
Success";;
data _null_;
file Status;
run;
%end;
%end;
%EndLogCheck:
%let Iteration=%eval(&Iteration+1);
filename _all_ clear;
%end;
%mend chasethelog_main;
This isn't the place for contract work. There are other boards out there if you want someone to build you a tool.
Log scanning is pretty simple, open the file (infile) to read in a datastep, then read one by one and search for string using functions like index.
For creating json file, in later releases there is things like:
https://support.sas.com/rnd/base/Tipsheet_PROC_JSON.pdf
Or you could just write out to a plain file using file and put statements.
Both those tasks are pretty basic, and there is plenty of tutorials on reading/writing files out there.
Do bear in mind that code you find on the internet may be old, not work the way you want etc.
Wow, I suppose by the way my question was written, you have misinterpreted what I am asking. It occurs to me now I could have written it differently. I am not asking someone to write an entire macro for me. I'm also not asking about how to parse text or create JSON - those are the goals of my future macro, but those are pieces I am comfortable doing on my own. What I'm having trouble with is trying to tease out the piece of the code that chases the log in batch mode, so that I can replace the piece of this macro that sends the email message with something else that suits my needs. I was hoping someone could help me decipher the pieces of what the macro is doing, or maybe even point me in the direction of a different way of processing a SAS log during batch mode.
I would forget the macro. When a program is run in batch (and its been a while since I did this as its all network or virtual based now), a log file, and list file is placed in the location of the main programs run location, so if you have:
c:/test/myprogram.sas
And batch submit this, SAS will by default create:
c:/test/myprogram.log
c:/test/myprogram.lst
Therefore you can read the plain text file with the .log extension to get the log. This is all the macro is doing, by taking the program name from the system macro variables:
put '%let PgmName='"%scan(%scan(&SYSPROCESSNAME,2,' '),1,'.');";
And then using this in a filename for the datastep to read from:
filenamerunlog pipe "cat &PgmName..log";
You could do this simply by:
data want; fname=catx('.',scan(scan("&sysprocessname.,2,' '),1,'.'),'.log'); infile fname; length buff $2000; input buff $; run;
Then you will have the complete log read into want dataset, and can process it as you wish.
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.