Macros for SAS Application Developers
https://github.com/sasjs/core
Loading...
Searching...
No Matches
mv_getjoblog.sas
Go to the documentation of this file.
1/**
2 @file
3 @brief Extract the log from a completed SAS Viya Job
4 @details Extracts log from a Viya job and writes it out to a fileref.
5
6 To query the job, you need the URI. Sample code for achieving this
7 is provided below.
8
9 ## Example
10
11 %* First, compile the macros;
12 filename mc url
13 "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
14 %inc mc;
15
16 %* Next, create a job (in this case, a web service);
17 filename ft15f001 temp;
18 parmcards4;
19 data ;
20 rand=ranuni(0)*1000;
21 do x=1 to rand;
22 y=rand*4;
23 output;
24 end;
25 run;
26 proc sort data=&syslast
27 by descending y;
28 run;
29 ;;;;
30 %mv_createwebservice(path=/Public/temp,name=demo)
31
32 %* Execute it;
33 %mv_jobexecute(path=/Public/temp
34 ,name=demo
35 ,outds=work.info
36 )
37
38 %* Wait for it to finish;
39 data work.info;
40 set work.info;
41 where method='GET' and rel='state';
42 run;
43 %mv_jobwaitfor(ALL,inds=work.info,outds=work.jobstates)
44
45 %* and grab the uri;
46 data _null_;
47 set work.jobstates;
48 call symputx('uri',uri);
49 run;
50
51 %* Finally, fetch the log;
52 %mv_getjoblog(uri=&uri,outref=mylog)
53
54 This macro is used by the mv_jobwaitfor.sas macro, which is generally a more
55 convenient way to wait for the job to finish before fetching the log.
56
57 If the remote session calls `endsas` then it is not possible to get the log
58 from the provided uri, and so the log from the parent session is fetched
59 instead. This happens for a 400 response, eg below:
60
61 ErrorResponse[version=2,status=400,err=5113,id=,message=The session
62 requested is currently in a failed or stopped state.,detail=[path:
63 /compute/sessions/LONGURI-ses0006/jobs/LONGURI/log/content, traceId: 63
64 51aa617d01fd2b],remediation=Correct the errors in the session request,
65 and create a new session.,targetUri=<null>,errors=[],links=[]]
66
67 @param [in] access_token_var= The global macro variable to contain the access
68 token
69 @param [in] mdebug= (0) Set to 1 to enable DEBUG messages
70 @param [in] grant_type= valid values:
71 @li password
72 @li authorization_code
73 @li detect - will check if access_token exists, if not will use sas_services
74 if a SASStudioV session else authorization_code. Default option.
75 @li sas_services - will use oauth_bearer=sas_services.
76 @param [in] uri= The uri of the running job for which to fetch the status,
77 in the format `/jobExecution/jobs/$UUID` (unquoted).
78 @param [out] outref= The output fileref to which to APPEND the log (is always
79 appended).
80
81
82 @version VIYA V.03.04
83 @author Allan Bowe, source: https://github.com/sasjs/core
84
85 <h4> SAS Macros </h4>
86 @li mp_abort.sas
87 @li mf_getplatform.sas
88 @li mf_existfileref.sas
89 @li mf_getuniquefileref.sas
90 @li mf_getuniquelibref.sas
91
92**/
93
94%macro mv_getjoblog(uri=0,outref=0
95 ,access_token_var=ACCESS_TOKEN
96 ,grant_type=sas_services
97 ,mdebug=0
98 );
99%local dbg libref1 libref2 loglocation fname1 fname2;
100%if &mdebug=1 %then %do;
101 %put &sysmacroname entry vars:;
102 %put _local_;
103%end;
104%else %let dbg=*;
105
106%local oauth_bearer;
107%if &grant_type=detect %then %do;
108 %if %symexist(&access_token_var) %then %let grant_type=authorization_code;
109 %else %let grant_type=sas_services;
110%end;
111%if &grant_type=sas_services %then %do;
112 %let oauth_bearer=oauth_bearer=sas_services;
113 %let &access_token_var=;
114%end;
115
116%mp_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password
117 and &grant_type ne sas_services
118 )
119 ,mac=&sysmacroname
120 ,msg=%str(Invalid value for grant_type: &grant_type)
121)
122
123/* validation in datastep for better character safety */
124%local errmsg errflg;
125data _null_;
126 uri=symget('uri');
127 if length(uri)<12 then do;
128 call symputx('errflg',1);
129 call symputx('errmsg',"URI is invalid (too short) - '&uri'",'l');
130 end;
131 if scan(uri,-1)='state' or scan(uri,1) ne 'jobExecution' then do;
132 call symputx('errflg',1);
133 call symputx('errmsg',
134 "URI should be in format /jobExecution/jobs/$$$$UUID$$$$"
135 !!" but is actually like:"!!uri,'l');
136 end;
137run;
138
139%mp_abort(iftrue=(&errflg=1)
140 ,mac=&sysmacroname
141 ,msg=%str(&errmsg)
142)
143
144%mp_abort(iftrue=(&outref=0)
145 ,mac=&sysmacroname
146 ,msg=%str(Output fileref should be provided)
147)
148
149%if %mf_existfileref(&outref) ne 1 %then %do;
150 filename &outref temp;
151%end;
152
153options noquotelenmax;
154%local base_uri; /* location of rest apis */
155%let base_uri=%mf_getplatform(VIYARESTAPI);
156
157/* prepare request*/
158%let fname1=%mf_getuniquefileref();
159%let fname2=%mf_getuniquefileref();
160proc http method='GET' out=&fname1 &oauth_bearer
161 url="&base_uri&uri";
162 headers
163 %if &grant_type=authorization_code %then %do;
164 "Authorization"="Bearer &&&access_token_var"
165 %end;
166 ;
167run;
168%if &mdebug=1 %then %do;
169 %put &sysmacroname: fetching log loc from &uri;
170 data _null_;infile &fname1;input;putlog _infile_;run;
171%end;
172%if &SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201 %then
173%do;
174 data _null_;infile &fname1;input;putlog _infile_;run;
175 %mp_abort(mac=&sysmacroname
176 ,msg=%str(&SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
177 )
178%end;
179
180%let libref1=%mf_getuniquelibref();
181libname &libref1 JSON fileref=&fname1;
182data _null_;
183 set &libref1..root;
184 call symputx('loglocation',loglocation,'l');
185run;
186
187/* validate log path*/
188%let errflg=1;
189%let errmsg=No loglocation entry in &fname1 fileref;
190data _null_;
191 uri=symget('loglocation');
192 if length(uri)<12 then do;
193 call symputx('errflg',1);
194 call symputx('errmsg',"URI is invalid (too short) - '&uri'",'l');
195 end;
196 else if (scan(uri,1,'/') ne 'compute' or scan(uri,2,'/') ne 'sessions')
197 and (scan(uri,1,'/') ne 'files' or scan(uri,2,'/') ne 'files')
198 then do;
199 call symputx('errflg',1);
200 call symputx('errmsg',
201 "URI should be in format /compute/sessions/$$$$UUID$$$$/jobs/$$$$UUID$$$$"
202 !!" or /files/files/$$$$UUID$$$$"
203 !!" but is actually like:"!!uri,'l');
204 end;
205 else do;
206 call symputx('errflg',0,'l');
207 call symputx('logloc',uri,'l');
208 end;
209run;
210
211%mp_abort(iftrue=(%str(&errflg)=1)
212 ,mac=&sysmacroname
213 ,msg=%str(&errmsg)
214)
215
216/* we have a log uri - now fetch the log */
217%&dbg.put &sysmacroname: querying &base_uri&logloc/content;
218proc http method='GET' out=&fname2 &oauth_bearer
219 url="&base_uri&logloc/content?limit=10000";
220 headers
221 %if &grant_type=authorization_code %then %do;
222 "Authorization"="Bearer &&&access_token_var"
223 %end;
224 ;
225run;
226
227%if &mdebug=1 %then %do;
228 %put &sysmacroname: fetching log content from &base_uri&logloc/content;
229 data _null_;infile &fname2;input;putlog _infile_;run;
230%end;
231
232%if &SYS_PROCHTTP_STATUS_CODE=400 %then %do;
233 /* fetch log from parent session */
234 %let logloc=%substr(&logloc,1,%index(&logloc,%str(/jobs/))-1);
235 %&dbg.put &sysmacroname: Now querying &base_uri&logloc/log/content;
236 proc http method='GET' out=&fname2 &oauth_bearer
237 url="&base_uri&logloc/log/content?limit=10000";
238 headers
239 %if &grant_type=authorization_code %then %do;
240 "Authorization"="Bearer &&&access_token_var"
241 %end;
242 ;
243 run;
244 %if &mdebug=1 %then %do;
245 %put &sysmacroname: fetching log content from &base_uri&logloc/log/content;
246 data _null_;infile &fname2;input;putlog _infile_;run;
247 %end;
248%end;
249
250%if &SYS_PROCHTTP_STATUS_CODE ne 200 and &SYS_PROCHTTP_STATUS_CODE ne 201
251%then %do;
252 %if &mdebug ne 1 %then %do; /* have already output above */
253 data _null_;infile &fname2;input;putlog _infile_;run;
254 %end;
255 %mp_abort(mac=&sysmacroname
256 ,msg=%str(logfetch: &SYS_PROCHTTP_STATUS_CODE &SYS_PROCHTTP_STATUS_PHRASE)
257 )
258%end;
259
260%let libref2=%mf_getuniquelibref();
261libname &libref2 JSON fileref=&fname2;
262data _null_;
263 file &outref mod;
264 if _n_=1 then do;
265 put "/** SASJS Viya Job Log Extract start: &uri **/";
266 end;
267 set &libref2..items end=last;
268 %if &mdebug=1 %then %do;
269 putlog line;
270 %end;
271 put line;
272 if last then do;
273 put "/** SASJS Viya Job Log Extract end: &uri **/";
274 end;
275run;
276
277%if &mdebug=0 %then %do;
278 filename &fname1 clear;
279 filename &fname2 clear;
280 libname &libref1 clear;
281 libname &libref2 clear;
282%end;
283%else %do;
284 %put &sysmacroname exit vars:;
285 %put _local_;
286%end;
287%mend mv_getjoblog;
288
289
290