pos = index(intext, '2E0D'X) ;
what is '2E0D'X? (is error hexadecimal coded?)
txt = substr(intext, 8, pos - 😎 ;
from this paper.
I think that is searching for a "right raised omission bracket", probably in an HTML file.
It is described at: Unicode char 2e0d
'2E'x is a period and '0D'x is a carriage return. Perhaps it is looking for a period at the end of line? Although that would assume that log was written on Windows and then re-read on Unix or with settings to prevent SAS from stripping the CR.
I looked briefly at the code in the paper and it is probably not going to find all of the error messages.
Normally I search for lines that start with ERROR. This will eliminate many false positives caused by MPRINT, SOURCE or SOURCE2 settings echoing the source code to the log. Also SAS can sometimes insert text between the ERROR at the beginning of the line and colon (':') before the error message.
Realised this is almost a year-old thread, but think it's worth replying.
Tom, I think you are right, it does indeed search for combination of the full stop and carriage return. Unfortunately, in some cases error goes onto a new line, which would break this macro a little. Also good spot on the environment differences, was sure to baffle me for a while.
I'm trying to augment/change code a bit, so that it could read multiple log lines, if any of the text triggers have been encountered.
Not really sure how, without reading heaps of sugi docs -- so if you have any pointers on this front, or have any more elegant solutions that would be greatly appreciated!
Not sure if that helps anyone, but I, inspired by the paper wrote something which i think is slightly more robust at picking up errors:
/*
USAGE: %de_log(full-file-path);
EXAMPLE: %de_log(c:\temp\saved_log.log);
*/
%macro de_log(logfile);
option nomprint;
filename log "&logfile";
data de_log_output (drop=line_txt);
retain nline 0;
length line_txt FULL_TEXT $ 1000 TYPE $ 10 SUB_TYPE $ 100;
infile infl lrecl=200 pad;
input @;
nline+1;
if substr(_infile_, 1, 5) = "ERROR"
or substr(_infile_, 1, 7) = "WARNING"
or substr(_infile_, 1, 4) = "NOTE"
then do;
line_txt = _infile_;
if substr(_infile_, length(_infile_), 1) ne '2E'x then do;
line_txt = _infile_;
do while (substr(_infile_, length(_infile_), 1) ne '2E'x);
input /@;
line_txt=catx(" ", line_txt, _infile_);
end;
end;
else do;
line_txt =_infile_;
end;
/*exclude non-error notes*/
if substr(line_txt, 1, 4) = "NOTE"
and (index(line_txt, 'The data set')=0
or index(line_txt, 'has 0 observations')=0)
then delete;
/*define type and subtype*/
TYPE = compress(scan(line_txt, 1, " "), ":");
if index(line_txt, ",") and not(index(line_txt, "DROP,")) then do;
SUB_TYPE = substr(scan(line_txt, 1, ","), index(line_txt, ":") +2);
end;
else if index(line_txt, "0 observations") then do;
SUB_TYPE = "Incomplete dataset (obs=0)";
end;
else if index(line_txt, "Multiple lengths were specified for the BY variable")
then do;
SUB_TYPE = "BY variables have inconsistent LENGTHS";
end;
else if index(line_txt, "The quoted string currently being processed") then do;
SUB_TYPE = "Unbalanced quote marks?";
end;
else if index(line_txt, "Invalid data set name") then do;
SUB_TYPE = "No / invalid dataset name";
end;
else if index(line_txt, "has never been referenced") then do;
SUB_TYPE = "Keeping, dropping or renaming non-existent variable";
end;
else SUB_TYPE = "Other";
FULL_TEXT = line_txt;
output;
end;
run;
proc sort
data=de_log_output;
by TYPE SUB_TYPE;
run;
proc summary
data=de_log_output
noprint nway n;
class TYPE SUB_TYPE;
output
out=de_log_summary (drop=_TYPE_);
run;
option mprint;
%mend de_log;
Join us for SAS Innovate 2025, our biggest and most exciting global event of the year, in Orlando, FL, from May 6-9.
Early bird rate extended! Save $200 when you sign up by March 31.
Learn the difference between classical and Bayesian statistical approaches and see a few PROC examples to perform Bayesian analysis in this video.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.