5
votes

I want to call a SAS program from another program on Windows. I have some experience invoking SAS from the command line in batch mode, but no real experience receiving messages from it and handling those messages. I have googled around and found quite a bit of information about reading from stdin from within a SAS program, but I cannot seem to figure out how to make my SAS program write out to stdout or stderr. Can I even do this in Windows?

From the SAS program, I would like to do the following:

  • Redirect Warning Messages and Error Messages to stderr instead of printing them to the log file
  • Within the SAS program, manually detect errors and/or other issues and output them to either stderr or stdout.

Here is what I have tried:

SAS

data test;
    attrib i length=8;

    do i = 1 to 10;
        put 'putting';  *how can i make this go to stdout?;
        putlog 'putting to log'; *this can go to the log - that is okay;
        if i = 5 then do;
            *pretend this is an error I am manually detecting - how can i make this go to stderr?;
            put 'we found 5';
        end;
        output;
    end;
run;

data _null_;

    1 = y; *this is an error detected by SAS.  How can I make this go to stderr?;

run;

Python that calls the SAS:

import subprocess
import os


if __name__ == '__main__':

    filename = os.path.normpath(r'C:\Users\oob\Desktop\sas_python_test.sas')
    sas_executable = os.path.normpath(r'C:\Program Files\SAS\SASFoundation\9.2\sas.exe')

    cmd = r'"' + sas_executable + r'"' + " " + r'"' + filename + r'"'

    p = subprocess.Popen(cmd,shell=False,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    print p.communicate()

My results on the console from this are:

('', '')
3
I've never used SAS, but is it a console app? It may not have handles for stdout/stderr. In that case try PyWin32's win32com module to automate SAS using OLE.Eryk Sun
Here's a link to SAS documentation about using unnamed pipes that might be helpful: support.sas.com/documentation/cdl/en/hostwin/63285/HTML/default/…RWill

3 Answers

2
votes

As far as I know this is not possible to achieve directly. You can emulate this by passing in a unique filename into sas using the -sysparm command line parameter and saving your STDOUT output to that. You can then use the -log command line parameter to send the sas log to a different file. Once the SAS program has finished you will be able to use your program of choice to parse each of the files that were produced. Unfortunately the log file is locked until the sas program finishes with it so if you want to use SAS to process the logfile you will need to launch a secondary follow up program to do so. (ie. you can't read the log file from within the SAS program that is creating it).

Once you read the log in you can look for lines that begin with ERROR: or WARNING: and take the appropriate actions (in my case it sends an email to me). You may want to add some logic that suits your style of coding. For example, some things that SAS treats as NOTES I consider ERRORS. Also, some things SAS treats as ERRORS I don't care about. Here's the logic I use:

data problems log;
  length line $1000;

  infile "&logfile";
  input;

  logfile = "&logfile";
  line_no = _n_;
  line    = _infile_;
  problem = 0;

  if 
  (
     line =: "ERROR:"
  or line =: "WARNING:"
  or line =: "NOTE: Numeric values have been converted to character values"
  or line =: "NOTE: Character values have been converted to numeric values"
  or line =: "NOTE: Missing values were generated as a result of performing an operation on missing values"
  or line =: "NOTE: MERGE statement has more than one data set with repeats of BY values"
  or line =: "NOTE: Invalid (or missing) arguments to the INTNX function have caused the function to return"
  or line =: "INFO: Character variables have defaulted to a length of 200"
  or line =: "NOTE: Invalid"
  )
  and not
  (
     line =: "WARNING: Your system is scheduled to expire"
  or line =: "WARNING: The Base Product product with which Session Manager is associated"
  or line =: "WARNING: will be expiring soon, and is currently in warning mode to indicate"
  or line =: "WARNING: this upcoming expiration. Please run PROC SETINIT to obtain more"
  or line =: "WARNING: information on your warning period."
  or line =: "WARNING: This CREATE TABLE statement recursively references the target table. A consequence"
  or line =: "WARNING: Unable to copy SASUSER registry to WORK registry. Because of this, you will not see registry customizations during this"
  or line =: "WARNING: Estimates did not improve after a ridge was encountered in the objective function."
  or line =: "WARNING: Estimates may not have converged."
  or line =: "ERROR: A lock is not available for"
  or line =: "ERROR: Errors printed on pages"
  )
  then do;
    problem = 1;
    output problems;
  end;
  output log;
run;

Hope this helps.

2
votes

I don't have a windows version of SAS handy, but on UNIX I redirect to STDOUT like this:

data _null_;
    file STDOUT;
    do i=1 to 10;
    put i=;
    end;
run;

Not sure how to redirect the error log to STDERR, but printing to STDERR would look like this:

ods listing file=STDERR;

proc print data=sashelp.class;
run;
-1
votes

Googled redirecting the log to STDERR for you:

   proc printto log=STDERR;
   run;

   data _null_;
      1=x;
   run;