BookmarkSubscribeRSS Feed
sathya66
Barite | Level 11

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

 

sathya66_0-1764847384761.png

 

 


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;

 

 

sas-innovate-2026-white.png



April 27 – 30 | Gaylord Texan | Grapevine, Texas

Registration is open

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!

Register now

How to Concatenate Values

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 0 replies
  • 45 views
  • 0 likes
  • 1 in conversation