Hi All,
We are able to extract user, flowname, trigger,etc from below code.
We are looking to extract email notification (when flow exit or start, etc) with email address and options . see below screenshot . Found below info in .dat files but not sure how to extract them and also options.
17
FlowStateMailWhen
4
Exit
10
FlowStderr
0
15
MailDestination
24
email.com
10
OEMAppName
3
SAS
11
OutputFiles
options linesize=180;
ods graphics off;
ods html close;
ods listing;
%macro flowdef;
%let JSHOME=/sas/common/pm;
%PUT JSHOME = "%trim(&JSHOME)";
%if %length(%trim(&JSHOME)) = 0 %then
%do;
%put %str();
%put ERROR: JS_HOME environment variable not available, exiting;
data _null_; abort return 16; run;
%end;
%if &sysscp = WIN %then
%do;
filename events "%trim(&JSHOME)\work\system\triggerevents.dat";
filename flowdefs "%trim(&JSHOME)\work\storage\flow_storage\*.dat";
%end;
%else
%do;
filename events "/sas/common/pm/work/system/triggerevents.dat";
filename flowdefs "/sas/common/pm/work/storage/flow_storage/*.dat";
%end;
%mend;
%flowdef;
data triggers;
infile events;
length owner $ 16 flowname $ 32;
input; * version info;
input; * number of events;
nevents = input(_infile_||" ",5.); drop nevents;
do i=1 to nevents;
input; * length of flow name;
input; * flow name;
owner = scan(_infile_,1,":");
flowname = scan(_infile_,2,":");
output;
do until(_infile_ = "</List>");
input;
end;
end;
run;
filename events;
data scheduled adhoc;
length owner $ 16 flowname $ 32 event $ 14 jobname details $ 64 specifics $ 32 runas $ 32 eventtype $ 4 flowpart instance $ 8 removed $ 1 calendar calowner $ 32 timepart $ 65 nextrun $ 17 flowID $ 6;
retain owner flowname eventtype flowpart instance removed flowID;
drop calowner ;
infile flowdefs;
input;
if _infile_ = '<JFFlow>' then
do;
jobname = " "; runas = " "; nextrun = " "; EventType = " "; FlowPart = " "; flowID = " ";
/* Job File Flow definition found. Get FlowName, Owner, and Instance */
input; /* eat next line -- length */
input; /* should be username:flowname */
owner = scan(_infile_,1,':');
flowname = scan(_infile_,2,':');
input; /* eat next line -- length */
input; /* should be same as above with %%%%%## instance */
instance = scan(_infile_,2,'%');
input; /* eat next line -- length */
input; /* eat next line -- <List> token */
input; /* this is the number of Flow IDs that have run already */
nflows = input(_infile_||" ",3.);
do i=1 to nflows;
input;
end;
/* we are at the last run flow ID or the same 0 if none */
if nflows then
flowID = _infile_;
else
flowID = " ";
input; /* eat next line -- length */
input; /* eat next line -- </List> token */
input;
/* This line is questionable. Empirical observation had found that if the character is "F" then the flow has NOT */
/* been "removed," so is still scheduled. Otherwise, if it is "T" it HAS been "removed" and is an AdHoc flow. */
/* However, more recent complex flow instances have cast a shadow of doubt onto this notion. Stay tuned.... */
removed = _infile_;
/* Between the previous flow list and the next <List> are some things we can ignore (flow security, flow version) */
/* so just scan for the next List header -- this should be the list of flow triggers, file and/or time. */
do until (_infile_ = '<List>');
input; /* eat everything until list of flow triggers */
end;
input;
FlowPart = "Events";
ntriggers = input(_infile_||' ',5.);
* if ntriggers = 0 then output;
do i = 1 to ntriggers;
do until (_infile_ = "<JFCalendarEventDef>" or _infile_ = "<JFFileEventDef>");
input;
end;
if _infile_ = "<JFFileEventDef>" then EventType = "File"; else EventType = "Time";
do until (_infile_ = "</JFEventDef>");
input;
end;
input; input; /* eat the length of the next token and then get the next token */
if EventType = "File" then
do;
event = "File Trigger: ";
details = _infile_;
specifics = " ";
end;
else
if _infile_ = '<JFTimeInstance>' then
do;
/* Job File Trigger instance found. Get Calendar name and time */
input; /* eat next line -- length */
input; /* should be calendar:hh:mm%dur */
calendar = scan(_infile_,1,':');
timepart = scan(_infile_,2,':')||':'||scan(_infile_,3,':%');
input; /* eat next line -- length */
input; /* eat calendar name repeat */
input; /* eat next line -- length */
input; /* calendar owner */
calowner = tranwrd(_infile_,'DT_BS_','.\');
calendar = trim(calendar)||'@'||trim(calowner);
event = "Time Trigger: ";
details = trim(calendar) || " at " || trim(timepart);
end;
else
do;
put "ERROR: Invalid Flow Event Trigger type: " _infile_;
put _all_; abort return 5;
end;
do until (_infile_ = "</RuntimeClass>");
input;
end;
link out; /* output information on each flow's trigger */
end;
end;
else if _infile_ = '<SubFlowEvents>' then
do;
do until (_infile_ = '<JFFlow>');
input;
end;
/* Job File SUB Flow definition found. Get SubFlow Name */
input; /* eat next line -- length */
input; /* should be username:flowname:subflow */
details = scan(_infile_,3,':');
specifics = " ";
flowpart = "SubFlows";
event = "SubFlow : ";
link out;
/* Just eat everything until end of sub flow */
do until (_infile_ = '</SubFlowEvents>');
input;
end;
end;
else if _infile_ = '</JFFlow>' then
do;
jobname = " "; runas = " "; nextrun = " "; EventType = " ";
/* We are either at the end of a flow or at the end of all */
end;
else if _infile_ = '<JFJob>' then
do;
input; /* eat next line -- length */
input; /* eat next line -- "lsf" or "link" */
if _infile_ = "link" then
do until (_infile_ = '</JFJob>');
input;
end;
else
do;
FlowPart = "Jobs";
/* "lsf" Job Flow Job definition found */
input; /* eat next line -- length */
input; /* should be username:flowname:jobname{metaid} */
jobname = scan(_infile_,3,':{');
runas = owner;
do until (_infile_ = '</JFJob>');
input;
if _infile_ = 'SubmissionCmd' then
do;
input; /* eat next line -- length */
input; /* eat next line -- "bsub" */
input; /* eat next line -- length */
input; /* eat next line -- "UserName" */
input; /* eat next line -- length */
input; /* should be RunAs username */
runas = _infile_;
end;
end;
/* Write out every job within a flow */
event = "Job: ";
details = jobname;
specifics = " ";
if "&sysscp" = "WIN" or index(owner,"\") then
iffy = lowcase(runas) ^= lowcase(owner);
else
iffy = runas ^= owner;
if iffy then
specifics = "Run As: " || trim(runas);
link out;
end;
end;
return;
out:
if removed = "T" or ntriggers = 0 then output adhoc; else output scheduled;
return;
run;
filename flowdefs;
proc sort data=scheduled; by owner flowname descending instance flowpart; run;
data schedules;
set scheduled;
length firstinst $ 8;
retain firstinst;
by owner flowname descending instance flowpart;
if first.flowname then firstinst = instance;
if instance = firstinst;
drop firstinst;
run;
/* Now remove flows that are not REALLY "scheduled" -- not found in triggers file */
proc sort data=triggers; by owner flowname; run;
data schedules nonsched;
merge triggers(in=scheduled) schedules;
by owner flowname;
if scheduled then output schedules;
else output nonsched;
run;
proc sort data=schedules; by owner flowname flowID; run;
proc sql;
create table schedule as
select * from work.schedules
where event in ('Time Trigger:', 'File Trigger:')
;
quit;
proc sql;
create table active_schedule as
select owner, flowname, details as trigger_event, eventtype as trigger_type, flowid
from schedule
;
quit;
April 27 – 30 | Gaylord Texan | Grapevine, Texas
Walk in ready to learn. Walk out ready to deliver. This is the data and AI conference you can't afford to miss.
Register now and lock in 2025 pricing—just $495!
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.