SAS Programming
SAS Log Parser Code for SAS Clients Enterprise Guide and SAS Add-in Microsoft Office
Develop automated log parsing solutions for SAS Enterprise Guide and SAS Add-in for Microsoft Office. This article provides reusable code for extracting, analyzing, and reporting on SAS log information.
Purpose of Log Parsing
SAS logs contain valuable information about:
- Execution errors and warnings
- Performance metrics
- Data quality issues
- Processing statistics
Automated parsing helps identify issues quickly and maintain quality assurance.
Basic Log Parser Structure
sas
/* Read SAS log file */
data log_contents;
infile "program.log" truncover;
input line $200.;
line_num = _n_;
run;
/* Parse log entries */
data parsed_log;
set log_contents;
/* Identify message types */
if index(upcase(line), 'ERROR:') then msg_type = 'ERROR';
else if index(upcase(line), 'WARNING:') then msg_type = 'WARNING';
else if index(upcase(line), 'NOTE:') then msg_type = 'NOTE';
else msg_type = 'INFO';
/* Extract message */
message = scan(line, 2, ':');
run;Advanced Pattern Recognition
sas
data detailed_parse;
set log_contents;
/* Execution time */
if index(line, 'real time') then do;
pattern = prxparse('/real time\s+([\d.:]+)/');
if prxmatch(pattern, line) then do;
exec_time = prxposn(pattern, 1, line);
output;
end;
end;
/* Observations processed */
if index(line, 'observations read') or
index(line, 'observations written') then do;
pattern = prxparse('/(\d+)\s+observations?\s+(read|written)/i');
if prxmatch(pattern, line) then do;
obs_count = input(prxposn(pattern, 1, line), best12.);
operation = prxposn(pattern, 2, line);
output;
end;
end;
run;Enterprise Guide Log Parser
sas
/* Parse EG project logs */
%macro parse_eg_log(project_path=);
/* Get all log files from EG project */
filename logs "&project_path.\Logs";
data eg_logs;
length filename $256 line $500;
infile logs (*.log) filename=fname truncover;
input line $char500.;
filename = scan(fname, -1, '\/');
line_num = _n_;
run;
/* Analyze by program */
proc sql;
create table log_summary as
select filename,
count(*) as total_lines,
sum(index(upcase(line), 'ERROR:') > 0) as errors,
sum(index(upcase(line), 'WARNING:') > 0) as warnings
from eg_logs
group by filename;
quit;
/* Report issues */
proc print data=log_summary;
where errors > 0 or warnings > 0;
title "Programs with Issues";
run;
%mend;Add-in for Microsoft Office Parser
sas
/* Parse logs from SAS Add-in tasks */
%macro parse_addin_log(excel_file=);
/* Read log from Excel workbook */
proc import datafile="&excel_file"
out=addin_log
dbms=xlsx replace;
sheet="Log";
run;
/* Parse log entries */
data parsed_addin;
set addin_log;
/* Identify issues */
has_error = (index(upcase(log_entry), 'ERROR:') > 0);
has_warning = (index(upcase(log_entry), 'WARNING:') > 0);
/* Extract timestamp */
if prxmatch('/\d{2}:\d{2}:\d{2}/', log_entry) then do;
pattern = prxparse('/\d{2}:\d{2}:\d{2}/');
timestamp = prxposn(pattern, 0, log_entry);
end;
run;
/* Summary report */
proc freq data=parsed_addin;
tables has_error has_warning / nocum nopercent;
run;
%mend;Performance Metrics Extraction
sas
/* Extract performance statistics */
data perf_metrics;
infile "program.log" truncover;
input line $500.;
/* CPU time */
if index(line, 'CPU time') then do;
cpu_seconds = input(scan(line, -2), ?? best12.);
metric = 'CPU_TIME';
value = cpu_seconds;
output;
end;
/* Memory usage */
if index(line, 'memory') then do;
if index(line, 'MB') then do;
memory_mb = input(scan(line, -2), ?? best12.);
metric = 'MEMORY_MB';
value = memory_mb;
output;
end;
end;
/* I/O operations */
if index(line, 'I/O') then do;
metric = 'IO_OPS';
/* Parse I/O statistics */
output;
end;
keep metric value line;
run;Error Categorization
sas
/* Categorize errors by type */
data error_categories;
set parsed_log;
where msg_type = 'ERROR';
/* Categorize errors */
if index(upcase(message), 'NOT FOUND') then category = 'Missing Object';
else if index(upcase(message), 'SYNTAX') then category = 'Syntax Error';
else if index(upcase(message), 'INVALID') then category = 'Invalid Value';
else if index(upcase(message), 'PERMISSION') then category = 'Access Denied';
else if index(upcase(message), 'MEMORY') then category = 'Resource Error';
else category = 'Other';
/* Extract affected object */
if index(message, 'file') or index(message, 'dataset') then do;
/* Parse object name */
object = scan(message, -1, ' ');
end;
run;
/* Summary by category */
proc freq data=error_categories order=freq;
tables category / nocum;
run;Automated Reporting
sas
/* Generate log analysis report */
%macro log_report(log_file=, output_file=);
/* Parse log */
/* ... parsing code ... */
/* Create report */
ods pdf file="&output_file";
title "SAS Log Analysis Report";
title2 "Log File: &log_file";
/* Error summary */
proc freq data=parsed_log;
where msg_type in ('ERROR', 'WARNING');
tables msg_type / nocum;
run;
/* Detailed error list */
proc print data=parsed_log(obs=100);
where msg_type = 'ERROR';
var line_num msg_type message;
run;
/* Performance metrics */
proc report data=perf_metrics;
column metric value;
define metric / group;
define value / analysis sum;
run;
ods pdf close;
%mend;
%log_report(
log_file=program.log,
output_file=analysis.pdf
);Best Practices
- Regular Parsing: Automate log analysis
- Error Tracking: Maintain error history
- Performance Monitoring: Track metrics over time
- Alerting: Notify on critical errors
- Documentation: Document common issues and solutions
Conclusion
Automated log parsing improves code quality, reduces debugging time, and provides valuable insights into SAS program execution. Implement these parsers to enhance your development and production monitoring processes.