Advertisement
Guest User

Untitled

a guest
Jul 3rd, 2017
78
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
SAS 33.32 KB | None | 0 0
  1. /*=============================================================================
  2. Program Name:         LOGCHECK.SAS
  3. Purpose:              To automatically scan SAS log files in a specified directory
  4.                       for ERRORs, WARNINGs and NOTEs which are against good
  5.                       programming practice. The user can specify the directory
  6.                       that the files are stored in and how many files the
  7.                       macro will search through.
  8. Macro variables:      DIR [Required]:       Windows NT directory path where the
  9.                                             LOG files are stored
  10.                                             [usually surounded by a %STR()].
  11.                                             This pathname can be gained from NT explorer
  12.                                             using the right-click and using "Properties".
  13.                       SCOPE [Default=A]:    How many LOG files are to be scanned.
  14.                                             Values: A = All files, S = Single file,
  15.                                                     I = Include files of this type,
  16.                                                     E = Exclude files of this type
  17.                       FILENAME [Optional]:  File or start of filename to be scanned.
  18.                                             If SCOPE=A then this option is ignored.
  19.                                             If SCOPE=I then all file names beginning
  20.                                             with this are scanned.
  21.                                             If SCOPE=E then all file names except
  22.                                             those beginning with this are scanned.
  23.                                             If SCOPE=S then this file name is scanned.
  24.                       UMESSAGE [Optional]:  Comma-delimted list of non-standard
  25.                                             user-defined LOG messages surrounded
  26.                                             by a %STR.
  27.                       YNZEROOBS [Default=Y]:    Switch to check whether data sets have zero observations.
  28.                                                 Values: Y = Check for Zero observations.
  29.                                                         N = Do not check for Zero observations
  30.                       DTFROM [Optional]:    Date of LOG file creation (on or after).
  31.                                             LOG files created before this date will not be scanned.
  32.                                             Date must be of the form: DDMMMYYYY.
  33. Programmer:           Lawrence Heaton-Wright
  34. OS/SAS Vnum:          Windows NT / 8.2
  35. Date:                 28-Aug-2003
  36. Notes:                This program can be run from interactive or batch SAS.
  37.                       This macro references several sub-macros:
  38.                         SCANLOG, MAXTITLE, FINDINGS
  39.                         SCANLOG:    Scans LOG file. Creates data set which is
  40.                                     appended to a FINDINGS data set.
  41.                         MAXTITLE:   Checks for pre-existing titles -
  42.                                     finds maximum number of existing title
  43.                         FINDINGS:   Reports LOG scan findings
  44.                       Report options of NOBYLINE, LS=132, PS=50, NONUMBER, DATE
  45.                         always set in this macro. The values of the original options
  46.                         are reset after running the macro,
  47.  
  48. Example:              %LogCheck (Dir=%STR(Q:\ABC Pharma\prot 001\BioStatistics\Programs\Tables));
  49.                         This will check ALL LOG files in this directory.
  50.                       %LogCheck (Dir=%STR(Q:\ABC Pharma\prot 001\BioStatistics\Programs\Tables), Scope=S, FileName=t01);
  51.                         This will check the T01.LOG file in this directory.
  52.                       %LogCheck (Dir=%STR(Q:\ABC Pharma\prot 001\BioStatistics\Programs\Tables), Scope=I, FileName=demog);
  53.                         This will check all LOG files beginning with DEMOG
  54.                         (ie. DEMOG_TABLE.LOG, DEMOG_BASELINE.LOG) in this directory.
  55.                       %LogCheck (Dir=%STR(Q:\ABC Pharma\prot 001\BioStatistics\Programs\Tables), Scope=E, FileName=compare);
  56.                         This will check all LOG files other than those beginning with COMPARE
  57.                       %LogCheck (Dir=%STR(Q:\ABC Pharma\prot 001\BioStatistics\Programs\Tables), UMessage=%STR(PGM NOTE:, PROBLEM:));
  58.                         This will check ALL LOG files in this directory searching
  59.                         the LOG files for the additional messages "PGM NOTE:" and "PROBLEM:".
  60.                       %LogCheck (Dir=%STR(Q:\ABC Pharma\prot 001\BioStatistics\Programs\Tables), dtFrom=25APR2008);
  61.                         This will check ALL LOG files in this directory created on or after 25APR2008.
  62. --------------------------------------------------------------------------------
  63.  Modifications:
  64.  Programmer/Date:     Reason:
  65.  ----------------     -------
  66.  LHW / 18-JAN-2005    Improved summary section of report. Produce a list of files
  67.                       with and without issues and user ID and date submitted.
  68.  LHW / 07-NOV-2005    Add code to check for existing WORK data sets. At completion
  69.                       of macro delete any WORK data sets created by the macro but
  70.                       not-pre-existing WORK data sets.
  71.  LHW / 09-NOV-2005    Added HEADING3 to report. Prints directory scanned on a separate
  72.                       row in the header information.
  73.                       Create PRNFILE1/PRNFILE2 = Heading information for FILENAME
  74.                       broken into 2 parts {amount of characters 1->132, 133->end}.
  75.  LHW / 05-JAN-2006    Added YNZEROOBS macro variable. This is a Y/N variable which
  76.                       activates the search for zero observations in a data set.
  77.  LHW / 16-APR-2007    Version 1.0:
  78.                       Updated SCOPE=E option to use a similar functionality to
  79.                       the Inclusion of files option.
  80.                       Added _VERSION & _VERDATE to show version number and date.
  81.  LHW / 06-JUL-2007    Version 1.1:
  82.                       Added BQUOTE around SYSPBUFF macro variable to mask commas
  83.                       inside the UMESSAGE input variable. Otherwise an error is
  84.                       generated stated that there are the wrong amount of elements
  85.                       for the INDEX macro function.
  86.  LHW / 29-APR-2008    Version 2.0:
  87.                       Added DTFROM macro variable. This variable is an additional
  88.                       switch to enable users to only scan LOG files created on
  89.                       or after a specified date.
  90.  LHW / 30-APR-2008    Version 2.1:
  91.                       When creating SCANLOG=1 restrict data set to those files
  92.                       which are SCANLOG=1 as this will ensure that the data set
  93.                       _LOGFILES will contain only those LOG files to be scanned.
  94.                       This will also allow interrogation based on the number
  95.                       of observations.
  96.                       Added Date LOG files craeted to REPORT headings.
  97.                       Added VALIDVARNAME to list of options checked.
  98.                       Set OPTIONS VALIDVARNAME=UPCASE as default for duration of macro.
  99. ==============================================================================*/
  100.  
  101. %MACRO LogCheck (Dir=, Scope=A, FileName=, UMessage=, ynZeroObs=Y, dtFrom=, _Version=%STR(2.1), _VerDate=29APR2008) / PARMBUFF;
  102.     OPTIONS NOSOURCE;
  103. *-------------------------------------------------------------------------------*;
  104. * Upper-case zero observations switch flag variable.                            *;
  105. *-------------------------------------------------------------------------------*;
  106.     %LET ynZeroObs=%UPCASE(&ynZeroObs.);
  107.     PROC SQL;
  108. *-------------------------------------------------------------------------------*;
  109. * Find WORK data sets already existing prior to invocation of LOGCHECK macro.   *;
  110. *-------------------------------------------------------------------------------*;
  111.     CREATE TABLE _pre_exist AS
  112.         SELECT DISTINCT memname FROM SASHELP.vstable WHERE UPCASE(libname) EQ "WORK";
  113. *-------------------------------------------------------------------------------*;
  114. * Retrieve OPTIONS settings for PS, LS, DATE, NUMBER & BYLINE. These options    *;
  115. * are set by the LOGCHECK macro. At the end of the macro these will be reset to *;
  116. * the intial values.                                                            *;
  117. *-------------------------------------------------------------------------------*;
  118.         CREATE TABLE _initial_options AS
  119.             SELECT DISTINCT optname, setting FROM SASHELP.voption
  120.             WHERE optname IN ('LINESIZE' 'PAGESIZE' 'BYLINE' 'DATE' 'NUMBER' 'VALIDVARNAME');
  121.     QUIT;
  122.  
  123.     DATA _NULL_;
  124.         SET _initial_options;
  125.         CALL SYMPUT(optname,COMPRESS(setting));
  126.     RUN;
  127.     OPTIONS VALIDVARNAME=UPCASE;
  128. *-------------------------------------------------------------------------------*;
  129. * Check UMESSGAE macro variable. If non-missing then there are non-standard     *;
  130. * user-defined LOG messages to check for. Create macro variables with a prefix  *;
  131. * of MESSAGE for the number of non-standard user-dfiened LOG messages.          *;
  132. *-------------------------------------------------------------------------------*;
  133.     %IF &UMessage NE %THEN %DO;
  134.         DATA _NULL_;
  135.             UMessage=SYMGET("UMessage");
  136.             len_with_comma=LENGTH(UMessage);
  137.             len_without_comma=LENGTH(COMPRESS(UMessage,','));
  138.             UserM=len_with_comma-len_without_comma+1;
  139.             CALL SYMPUT('UserM',COMPRESS(PUT(UserM,BEST.)));
  140.         RUN;
  141.         %LET MaxUMLen=1;
  142.         %DO um_i=1 %TO &UserM.;
  143.             %LET Message&um_i=%SCAN(&UMessage.,&um_i.,',');
  144.             %IF %LENGTH(&&Message&um_i.) GT &MaxUMLen. %THEN %LET MaxUMLen=%LENGTH(&&Message&um_i.);
  145.             %PUT User message &um_i. = &&Message&um_i. Maximum length of comment=&MaxUMLen.;
  146.         %END;
  147.     %END;
  148. %*** Macro variable used to indicate that the macro should continue when =N         ***;
  149.     %LET CloseDown=N; %LET Scope=%UPCASE(&Scope); %LET FileName=%UPCASE(&FileName);
  150. %*------------------------------------------------------------------------------*;
  151. %* Check that user have not change version number or version date.              *;
  152. %* Added BQUOTE to mask commas inside UMESSAGE (if UMESSAGE specified).         *;
  153. %*------------------------------------------------------------------------------*;
  154.     %PUT SysPBuff=&SysPBuff.;
  155.     %IF %INDEX(%BQUOTE(%UPCASE(&SysPBuff.)),_VERSION) GT 0
  156.         OR %INDEX(%BQUOTE(%UPCASE(&SysPBuff.)),_VERDATE) GT 0 %THEN %DO;
  157.         %PUT ERROR: Version or Version Date Changed by User;
  158.         %PUT        Terminating &SysMacroName.;
  159.         %PUT;
  160.         %LET CloseDown=Y;
  161.     %END;
  162.     LIBNAME _test_ "&Dir";
  163. %*** Use the SYSLIBRC macro variable to determine if the LIBREF has been assigned   ***;
  164. %*** If SYSLIBRC=0 then this indicates that the LIBNAME statement was successful    ***;
  165. %*** For any other value shut down the macro. Also check for null values of DIR     ***;
  166.     %IF &CloseDown=N %THEN %DO;
  167. %*------------------------------------------------------------------------------*;
  168. %* Macro information.                                                           *;
  169. %*------------------------------------------------------------------------------*;
  170.         %PUT &SysMacroName. Version &_Version., Version Date &_VerDate.;
  171.         %PUT;
  172.         %PUT NOTE: STARTING &SysMacroName. PARAMETER CHECKS;
  173.         %PUT;
  174.         %IF &SysLibRC. NE 0 %THEN %DO;
  175.             %LET CloseDown=Y;
  176.             %PUT ;
  177.             %PUT ERROR: Specified directory does not exist. Check spelling.;
  178.             %PUT ERROR: Macro terminating due to &Dir not existing;
  179.             %PUT ;
  180.         %END;
  181.     %END;
  182. %*** Continue with the macro ***;
  183.     %IF &CloseDown=N %THEN %DO;
  184.         %PUT ;
  185.         %PUT NOTE: Specified directory exists. Macro continuing.;
  186.         %PUT NOTE: Checking &Dir LOG files.;
  187.         %PUT ;
  188. %*** Check that SCOPE requested is a valid values [A/I/E/S].                          ***;
  189.         %IF NOT (&Scope=A OR &Scope=I OR &Scope=E OR &Scope=S) %THEN %DO;
  190.             %PUT ;
  191.             %PUT ERROR: SCOPE has not been specified as All/Include/Exclude/Single LOG file check.;
  192.             %PUT ERROR: Macro terminating. SCOPE=&Scope.. Choices are A/I/E/S. ;
  193.             %PUT ;
  194.             %LET CloseDown=Y;
  195.         %END;
  196.     %END;
  197. %*** Continue with the macro ***;
  198.     %IF &CloseDown=N %THEN %DO;
  199.         %PUT ;
  200.         %PUT NOTE: Macro continuing.;
  201.         %PUT NOTE: Checking &Dir SCOPE=&Scope LOG files.;
  202.         %PUT ;
  203. %*** Check that if SCOPE is Include/Exclude/Single then a filename has been specified.   ***;
  204.         %IF (&Scope=I OR &Scope=I OR &Scope=S) AND &FileName= %THEN %DO;
  205.             %PUT ;
  206.             %PUT ERROR: No filename specified even though an Include/Exclude or Single LOG file check has been requested.;
  207.             %PUT ERROR: Macro terminating. SCOPE=&Scope FILENAME=&FileName.. FileName MUST be entered.;
  208.             %PUT ;
  209.             %LET CloseDown=Y;
  210.         %END;
  211.     %END;
  212. %*** Continue with the macro ***;
  213.     %IF &CloseDown=N %THEN %DO;
  214.         %PUT ;
  215.         %PUT NOTE: Macro continuing.;
  216.         %PUT NOTE: Checking Zero Observations switch flag has correct input value;
  217.         %PUT ;
  218. %*** Check that if YNZEROOBS has a value of Y or N.   ***;
  219.         %IF NOT (&ynZeroObs. EQ Y OR &ynZeroObs. EQ N) %THEN %DO;
  220.             %PUT ;
  221.             %PUT ERROR: Zero observations switch flag has incorrect values.;
  222.             %PUT ERROR: Macro terminating. YNZEROOBS=&ynZeroObs.. ynZeroObs MUST have values of Y or N.;
  223.             %PUT ;
  224.             %LET CloseDown=Y;
  225.         %END;
  226.     %END;
  227. %*** Continue with the macro ***;
  228. %*** Checking that DTFROM is a valid date ***;
  229.     %IF &dtFrom NE %THEN %DO;
  230.         %PUT ;
  231.         %PUT NOTE: Macro continuing.;
  232.         %PUT NOTE: Checking Date of LOG files is a valid date value;
  233.         %PUT ;
  234. %*** Check that DTFROM is of the form DDMMYYYY.   ***;
  235.         %LET dtWrong=N;
  236.         DATA _NULL_;
  237.             _dt=INPUT(SYMGET('dtFrom'),??DATE9.);
  238.             IF _dt EQ . THEN CALL SYMPUT('dtWrong','Y');
  239.         RUN;
  240.         %IF &dtWrong. EQ Y %THEN %DO;
  241.             %PUT ;
  242.             %PUT ERROR: Cutoff Date not of DDMMYYYY format.;
  243.             %PUT ERROR: Macro terminating. DTFROM=&dtFrom.. dtFrom MUST be the form DDMMMYYYY.;
  244.             %PUT ;
  245.             %LET CloseDown=Y;
  246.         %END;
  247.     %END;
  248. %*** Continue with the macro ***;
  249.     %IF &CloseDown=N %THEN %DO;
  250.         %PUT ;
  251.         %PUT NOTE: Macro continuing.;
  252.         %PUT NOTE: Checking &Dir SCOPE=&Scope FILENAME=&FileName LOG files.;
  253.         %PUT ;
  254.         DATA _NULL_;
  255.             folder=SYMGET("dir");
  256. %*** Use DIR to create a DOS command to return all of the LOG files in a directory. ***;
  257.             %IF &dtFrom. NE %THEN %DO;
  258.                 dir_cmd="'dir " || '"' || TRIM(LEFT(folder)) || '\*.LOG"' || "/od'";
  259.             %END;
  260.             %ELSE %DO;
  261.                 dir_cmd="'dir " || '"' || TRIM(LEFT(folder)) || '\*.LOG"' || "/b'";
  262.             %END;
  263.             CALL SYMPUT ('dir_cmd',dir_cmd);
  264.         RUN;
  265.         FILENAME dir PIPE &Dir_Cmd.;
  266.         %IF &dtFrom. NE %THEN %DO;
  267.         DATA _LogFiles (DROP=_LogFile _crDate _dtFrom);
  268.             ATTRIB
  269.                 _crDate     LABEL="File Creation Date" FORMAT=DATE9.
  270.                 _dtFrom     LABEL="Cutoff Date for LOG file scan" FORMAT=DATE9.
  271.                 LogFile     LABEL="SAS LOG file" LENGTH=$100.
  272.             ;
  273.             INFILE dir TRUNCOVER;
  274.             INPUT _LogFile $CHAR256. @;
  275.             IF INDEXC(SUBSTR(_LogFile,1,1),'1234567890') EQ 0 THEN DELETE;
  276.             _crDate=INPUT(SCAN(_LogFile,1,' '),DDMMYY10.);
  277.             LogFile=SCAN(_LogFile,4,' ');
  278.             _dtFrom=INPUT(SYMGET('dtFrom'),DATE9.);
  279.             IF _crDate LT _dtFrom THEN DELETE;
  280.         %END;
  281.         %ELSE %DO;
  282.         DATA _LogFiles;
  283.             LENGTH ReadFile $200.;
  284.             INFILE dir TRUNCOVER;
  285.             INPUT LogFile $CHAR256. @;
  286.         %END;
  287. %*** Use SYMGET functionality to retrieve all input macro variables                 ***;
  288.             folder=SYMGET("dir"); scope=SYMGET("scope"); FileName=SYMGET("FileName");
  289.             ReadFile=TRIM(folder) || "\" || LogFile;
  290.            LogFile=UPCASE(LogFile);
  291. %*** Check SCOPE and FILENAME. Set a flag [SCANLOG=1] for the following records:    ***;
  292. %***    If SCOPE=A then SCANLOG=1 for all records.                                  ***;
  293. %***    If SCOPE=I then SCANLOG=1 for records where LOGFILE begins with FILENAME.   ***;
  294. %***    If SCOPE=E then SCANLOG=1 for records where LOGFILE does not begin with     ***;
  295. %***        FILENAME.                                                               ***;
  296. %***    If SCOPE=S then SCANLOG=1 for the record where LOGFILE=FILENAME.            ***;
  297.            ScanLog=0;
  298.            IF scope='A' OR
  299.                (scope='I' AND SUBSTR(LogFile,1,LENGTH(FileName)) EQ FileName) OR
  300.                (scope='E' AND SUBSTR(LogFile,1,LENGTH(FileName)) NE FileName) OR
  301.                (scope='S' AND LogFile EQ COMPRESS(FileName || '.LOG')) THEN ScanLog=1;
  302.            IF ScanLog EQ 1;
  303.        RUN;
  304. %*** Check LOG files data set for occurrences of SCANLOG.                           ***;
  305.        %LET dsid=%SYSFUNC(OPEN(WORK._LogFiles));
  306.        %LET N_Files=%SYSFUNC(ATTRN(&dsid.,NOBS));
  307.        %LET rc=%SYSFUNC(CLOSE(&dsid.));
  308. %*** If SCOPE=I or E then SCANLOG should equal 1 for at least one record.           ***;
  309.        %IF (&Scope=I OR &Scope=E) AND %EVAL(&N_Files)=0 %THEN %DO;
  310.            %PUT ;
  311.            %PUT ERROR: Multiple log files requested but no files match FILENAME=&FileName..;
  312.            %PUT ERROR: Macro terminating.;
  313.            %PUT ;
  314.            %LET CloseDown=Y;
  315.        %END;
  316. %*** If SCOPE=S then SCANLOG should equal 1 for only one record.                    ***;
  317.        %IF &Scope=S AND %EVAL(&N_Files) NE 1 %THEN %DO;
  318.            %PUT ;
  319.            %PUT ERROR: Single log file requested but no file matches FILENAME=&FileName..;
  320.            %PUT ERROR: Macro terminating.;
  321.            %PUT ;
  322.            %LET CloseDown=Y;
  323.        %END;
  324. %*** Check that there are files to be scanned if no LOG files created after DTFROM  ***;
  325.        %IF &dtFrom. NE AND %EVAL(&N_Files) EQ 0 %THEN %DO;
  326.            %PUT ;
  327.            %PUT ERROR: No LOG files created after DTFROM = &dtFrom..;
  328.            %PUT ERROR: Macro terminating.;
  329.            %PUT ;
  330.            %LET CloseDown=Y;
  331.        %END;
  332.    %END;
  333. %*** Continue with the macro ***;
  334.    %IF &CloseDown=N %THEN %DO;
  335. %*-------------------------------------------------------------------------------*;
  336. %* Check WORK area for existing _FINDINGS data set. If this exists then delete   *;
  337. %* this data set as we do not require LOG file findings from previous log checks *;
  338. %* to be reported again.                                                         *;
  339. %* Use EXIST function to check if _FINDINGS exists. Returns non-zero value if    *;
  340. %* operation was successful (i.e. _FINDINGS exists).                             *;
  341. %*-------------------------------------------------------------------------------*;
  342.    %IF %SYSFUNC(EXIST(WORK._FINDINGS)) %THEN %DO;
  343.        %PUT NOTE: WORK._FINDINGS already exists. Deleting for new report.;
  344.        %PUT;
  345.        PROC DATASETS LIBRARY=WORK;
  346.            DELETE _findings;
  347.        RUN; QUIT;
  348.    %END;
  349. %*** For each occurrence of SCANLOG=1, call the SCANLOG macro to search that file   ***;
  350. %*** for ERRORs, WARNINGs, NOTEs.                                                   ***;
  351. %*** Create INVOKEORDER variable = unique record number of LOG file to be scanned   ***;
  352. %*** Use INVOKEORDER from a macro DO loop to create _READFILE - a macro variable    ***;
  353. %*** which is used in the invocation of the SCANLOG macro.                          ***;
  354.        DATA _LogFiles;
  355.            SET _LogFiles (WHERE=(ScanLog=1));
  356.            InvokeOrder=_N_;
  357.        RUN;
  358.        %DO _i=1 %TO &N_Files.;
  359.            DATA _NULL_;
  360.                SET _LogFiles (WHERE=(InvokeOrder=&_i.));
  361.                CALL SYMPUT ('_ReadFile',TRIM(LEFT(ReadFile)));
  362.            RUN;
  363.            %ScanLog(InFile=%STR(&_ReadFile.));
  364.        %END;
  365. %*-------------------------------------------------------------------------------*;
  366. %* Check SASHELP.VTITLE for maximum number of titles. Create TITLE+1 for         *;
  367. %* LOG findings report.                                                          *;
  368. %*-------------------------------------------------------------------------------*;
  369.        %MaxTitle;
  370.        %LET Title=%EVAL(&MaxTitle+1);
  371.        TITLE&Title "LOG FILE CHECK";
  372. %*-------------------------------------------------------------------------------*;
  373. %* Print out relevant LOG file problems.                                         *;
  374. %*-------------------------------------------------------------------------------*;
  375.        PROC FORMAT;
  376.            PICTURE RepLine
  377.                    -1="        FILE NAME: " (NOEDIT)
  378.                0-HIGH="0000099" (PREFIX="LOG LINE:")
  379.                       .=" " (NOEDIT);
  380.        RUN;
  381. %*-------------------------------------------------------------------------------*;
  382. %* Check _FINDINGS is not missing. If missing then create a dummy data set       *;
  383. %* containing 1 observation which will be used to print out a                    *;
  384. %* "No Log File Problems" report.                                                *;
  385. %* If no observations in _FINDINGS data set set NERROR=0 [Number of LOG files    *;
  386. %* with errors/problems found]. Otherwise set NERROR to the number of LOG files  *;
  387. %* in _FINDINGS.                                                                 *;
  388. %*-------------------------------------------------------------------------------*;
  389.        PROC SQL NOPRINT;
  390.            SELECT DISTINCT NObs INTO: NObs FROM SASHELP.vtable
  391.                WHERE libname="WORK" AND memname="_FINDINGS";
  392.        QUIT;
  393.        %IF %EVAL(&NObs.) EQ 0 %THEN %DO;
  394.            %PUT NO RECORDS IN _FINDINGS - CREATE DUMMY DATA SET;
  395.            DATA _findings;
  396.                step=1; LineNo=1; Repline=.; Line=" ";
  397.                FileName="No Problems detected in LOG file(s)";
  398.            RUN;
  399.            %LET NError=0;
  400.        %END;
  401.        %ELSE %DO;
  402.            PROC SQL NOPRINT;
  403.                SELECT DISTINCT N(DISTINCT FileName) INTO: NError FROM _findings;
  404.            QUIT;
  405.        %END;
  406.        %LET MaxLines=%EVAL(36-&Title.);
  407.        PROC SORT DATA=_findings;
  408.            BY FileName Step LineNo;
  409.        RUN;
  410. %*-------------------------------------------------------------------------------*;
  411. %* Define SUMMARY page data set.                                                 *;
  412. %* Produce list of LOG files scanned and those with potential issues and those   *;
  413. %* without. Find final page number. Use this to start the detailed report        *;
  414. %* pagination calculations.                                                      *;
  415. %*-------------------------------------------------------------------------------*;
  416.        DATA _summary ;
  417.            SET _FileInfo;
  418.            ATTRIB
  419.                directory   LABEL="Directory Scanned" LENGTH=$132.
  420.                ScopeFiles  LABEL="Scope of Files Scanned" LENGTH=$132.
  421.                Summary     LABEL="Number LOG Files Scanned and Number of Issues" LENGTH=$132.
  422.                Program     LABEL="Program LOG File Scanned" LENGTH=$132.
  423.            ;
  424.            directory=SYMGET("dir");
  425.            scope=SYMGET("scope");
  426.            IF scope="A" THEN ScopeFiles="All LOG Files scanned";
  427.            ELSE IF scope="S" THEN ScopeFiles="Scanned File = &Filename..LOG";
  428.            ELSE IF scope="I" THEN ScopeFiles="Files beginning with &Filename. scanned";
  429.            ELSE IF scope="E" THEN ScopeFiles="Files beginning with &Filename. excluded from scanning";
  430.            Summary="Number of LOG files scanned = " || COMPRESS(PUT(&N_Files.,BEST.)) ||
  431.                    "; Number of LOG files with potential issues = " ||
  432.                    COMPRESS(PUT(&NError.,BEST.)) ||".";
  433.            Program=SCAN(FileName,-1,'\');
  434.        RUN;
  435. %*-------------------------------------------------------------------------------*;
  436. %* Calculate pagination for SUMMARY data set. Use MAXLINES macro variable which  *;
  437. %* indicates how many lines are available to the report.                         *;
  438. %*-------------------------------------------------------------------------------*;
  439.        PROC SORT DATA=_Summary;
  440.            BY issue FileName;
  441.        RUN;
  442.  
  443.        DATA _Summary;
  444.            SET _Summary END=eod;
  445.            BY issue FileName;
  446.            RETAIN page 0 LinesLeft &MaxLines.;
  447.            IF _N_ EQ 1 THEN page=1;
  448.            IF FIRST.issue THEN LinesLeft=LinesLeft-6;
  449.            LinesLeft=LinesLeft-1;
  450.            IF LinesLeft LT 1 THEN DO;
  451.                Page+1; LinesLeft=&MaxLines.-6;
  452.            END;
  453.            _Page=page;
  454.            IF eod THEN CALL SYMPUT('SummPage',PUT(page,BEST.));
  455.        RUN;
  456. %*-------------------------------------------------------------------------------*;
  457. %* Calculate page numbers.                                                       *;
  458. %*-------------------------------------------------------------------------------*;
  459.        DATA _findings;  
  460.            SET _findings END=eof;
  461.            ATTRIB
  462.                Page        LABEL="Page number"
  463.                LinesLft    LABEL="Lines left per report page"
  464.                ExtraLine   LABEL="Extra line needed for LINE - FLOW variable"
  465.                UID_Date    LABEL="User ID and Date/Time submitted" LENGTH=$132.
  466.                PrnFile1    LABEL="REPORT Heading: 1st 132 characters of FILENAME" LENGTH=$132.
  467.                PrnFile2    LABEL="REPORT Heading: 2nd 132 characters of FILENAME" LENGTH=$132.
  468.            ;
  469.            RETAIN Page %EVAL(&SummPage.+1) LinesLft &MaxLines.;
  470.            BY FileName Step LineNo;
  471.  
  472.            DDLogs=INDEX(UPCASE(FileName),"DERIVED DATASETS");
  473.            UID_Date=TRIM(LEFT(UserID)) || " / " || TRIM(LEFT(PUT(SubmitDT,DATETIME20.)));
  474.  
  475.            ExtraLine=CEIL(LENGTH(Line)/112);
  476.            LinesLft=LinesLft-ExtraLine;
  477.            IF FIRST.Step THEN LinesLft=LinesLft-2;
  478.            IF FIRST.FileName THEN DO;
  479.                LinesLft=LinesLft-2;
  480.                FileNameID+1;
  481.            END;
  482.            IF (DDLogs>0 AND FIRST.FileName AND _N_ NE 1) OR
  483.                (FIRST.FileName AND LinesLft<3) OR LinesLft<1 THEN DO;
  484.                Page+1;
  485.                LinesLft=&MaxLines.;
  486.            END;
  487.            %IF &NError. NE 0 %THEN %DO;
  488.                IF eof THEN CALL SYMPUT ("TotPages",COMPRESS(PUT(page,BEST.)));
  489.            %END;
  490.            %ELSE %DO;
  491.                %LET TotPages=&SummPage.;
  492.                *CALL SYMPUT ("TotPages",'1');
  493.            %END;
  494. %*-------------------------------------------------------------------------------*;
  495. %* If length of FILENAME (plus "Filename =") >132 then create PRNFILE2 as        *;
  496. %* remainder of FILENAME from characters 133 to the end. PRNFILE1 is the first   *;
  497. %* 132 characters of FILENAME.                                                   *;
  498. %*-------------------------------------------------------------------------------*;
  499.            PrnFile1=SUBSTR(FileName,1,132-11);
  500.            IF (LENGTH(FileName)+11)>132 THEN PrnFile2=SUBSTR(FileName,132-11+1);
  501.        RUN;
  502. %*-------------------------------------------------------------------------------*;
  503. %* Reporting step.                                                               *;
  504. %*-------------------------------------------------------------------------------*;
  505.        OPTIONS NOBYLINE LS=132 PS=48 DATE NONUMBER;
  506.        PROC REPORT DATA=_summary NOWD MISSING SPACING=0 SPLIT="~";
  507.            COLUMN Page directory ScopeFiles Summary issue _Page ("__" Program UserID SubmitDT);
  508.  
  509.            DEFINE _Page        / ORDER NOPRINT ORDER=INTERNAL;
  510.            DEFINE issue        / ORDER NOPRINT ORDER=INTERNAL;
  511.            DEFINE directory    / ORDER NOPRINT ORDER=INTERNAL;
  512.            DEFINE ScopeFiles   / ORDER NOPRINT ORDER=INTERNAL;
  513.            DEFINE Summary      / ORDER NOPRINT ORDER=INTERNAL;
  514.            DEFINE Page         / ORDER NOPRINT ORDER=INTERNAL;
  515.            DEFINE Program      / ORDER ORDER=INTERNAL "File Name" WIDTH=50 FLOW LEFT;
  516.            DEFINE UserID       / DISPLAY "User ID" WIDTH=50 FLOW LEFT;
  517.            DEFINE SubmitDT     / DISPLAY "Date/time Submitted" WIDTH=32 FLOW LEFT;
  518.  
  519.            BREAK AFTER Page / PAGE;
  520.            BREAK AFTER issue / SKIP;
  521.  
  522.            COMPUTE BEFORE Page;
  523.                LINE @1 132*'_';
  524.                LINE @1 ' ';
  525.            ENDCOMP;
  526.  
  527.            COMPUTE BEFORE _Page;
  528.                LENGTH Heading1-Heading3 $132.;
  529.                Heading2=TRIM(ScopeFiles)
  530.                        %IF &dtFrom. NE %THEN %DO;
  531.                            || " [ for LOG files created after %UPCASE(&dtFrom.) ]"
  532.                        %END;
  533.                        || " in Directory:";
  534.                Heading3=TRIM(Directory);
  535.                IF issue EQ . THEN DO;
  536.                    Heading1='LOG DIRECTORY SCANNING INFORMATION SUMMARY - NO ISSUES IN LOG FILES';
  537.                END;
  538.                ELSE DO;
  539.                    Heading1='LOG DIRECTORY SCANNING INFORMATION SUMMARY - POSSIBLE ISSUES IN LOG FILES';
  540.                END;
  541.                LINE @1 132*'=';
  542.                LINE @1 Heading1 $132.;
  543.                LINE @1 Heading2 $132.;
  544.                LINE @1 Heading3 $132.;
  545.                LINE @1 Summary $132.;
  546.                LINE @1 132*'=';
  547.                LINE @1 ' ';
  548.            ENDCOMP;
  549.  
  550.            COMPUTE AFTER Page;
  551.                LENGTH PageXofY $132.;
  552.                PageXofY="Page " || COMPRESS(PUT(page,BEST.)) || " of &TotPages.";
  553.                LINE @1 132*'_';
  554.                LINE @1 ' ';
  555.                LINE @1 PageXofY $132.;
  556.            ENDCOMP;
  557.        RUN;
  558.        QUIT;
  559.        
  560.        %IF &NError. NE 0 %THEN %DO;
  561.            PROC REPORT DATA=_findings LS=132 NOWD MISSING SPACING=0 SPLIT="~";
  562.  
  563.                COLUMN Page PrnFile1 PrnFile2 UID_Date FileNameID Step LineNo
  564.                           ("__" RepLine Line);
  565.  
  566.                DEFINE Page     / ORDER NOPRINT ORDER=INTERNAL;
  567.                DEFINE PrnFile1 / ORDER NOPRINT ORDER=INTERNAL;
  568.                DEFINE PrnFile2 / ORDER NOPRINT ORDER=INTERNAL;
  569.                DEFINE UID_Date / ORDER NOPRINT ORDER=INTERNAL;
  570.                DEFINE FileNameID / ORDER NOPRINT ORDER=INTERNAL;
  571.                DEFINE Step     / ORDER NOPRINT ORDER=INTERNAL;
  572.                DEFINE LineNo   / ORDER NOPRINT ORDER=INTERNAL;
  573.                DEFINE RepLine  / DISPLAY " " FORMAT=RepLine. WIDTH=20 LEFT;
  574.                DEFINE Line     / DISPLAY " " WIDTH=112 FLOW;
  575.  
  576.                BREAK AFTER Page / PAGE;
  577.  
  578.                COMPUTE BEFORE FileNameID;
  579.                    LINE @1 "FileName = " PrnFile1 $132.;
  580.                    LINE @1 "           " PrnFile2 $132.;
  581.                    LINE @1 "User ID/Date Submitted = " UID_Date $132.;
  582.                    LINE @1 132*'_';
  583.                    LINE @1 ' ';
  584.                ENDCOMP;
  585.  
  586.                COMPUTE AFTER Step;
  587.                    LINE @1 132*'_';
  588.                    LINE @1 ' ';
  589.                ENDCOMP;
  590.  
  591.                COMPUTE AFTER Page;
  592.                    LENGTH PageXofY $132.;
  593.                    PageXofY="Page " || COMPRESS(PUT(page,BEST.)) || " of &TotPages.";
  594.                    LINE @1 PageXofY $132.;
  595.                ENDCOMP;
  596.            RUN;
  597.            QUIT;
  598.        %END;
  599.    %END;
  600. *-------------------------------------------------------------------------------*;
  601. * Resetting options and statements from ones modified by LOGCHECK to original   *;
  602. * settings.                                                                     *;
  603. *-------------------------------------------------------------------------------*;
  604.    TITLE&Title.; LIBNAME _test_;
  605. *-------------------------------------------------------------------------------*;
  606. * Find WORK data sets existing after invocation of LOGCHECK macro.              *;
  607. * Create macro variable _LIST_DELETE as a list of data sets created by          *;
  608. * LOGCHECK/SCANLOG/MAXTITLE invocation which did not exist prior to invocation. *;
  609. * Use this macro variable in a PROC DATASETS call to delete these data sets.    *;
  610. *-------------------------------------------------------------------------------*;
  611.    DATA _NULL_;
  612.        MERGE
  613.            _pre_exist (IN=in_pre_exist)
  614.            SASHELP.vstable (WHERE=(UPCASE(libname) EQ "WORK") IN=in_post_exist) END=eof
  615.        ;
  616.        LENGTH list_delete $1024.;
  617.        RETAIN list_delete ' ';
  618.        BY memname;
  619.        IF in_post_exist AND NOT in_pre_exist THEN list_delete=TRIM(list_delete) || " " || memname;
  620.        
  621.        IF eof THEN DO;
  622.            PUT "DELETE THESE DATA SETS: " list_delete;
  623.            CALL SYMPUT ('_list_delete',list_delete);
  624.        END;
  625.    RUN;
  626.  
  627.    PROC DATASETS LIBRARY=WORK MTYPE=DATA;
  628.        DELETE &_list_delete.;
  629.    RUN; QUIT;
  630.    OPTIONS SOURCE;
  631.    %PUT RESETTING TO INTIAL OPTION SETTINGS;
  632.    %PUT;
  633.    %PUT LS=&LineSize. PS=&PageSize. DATE=&Date. BYLINE=&ByLine. VALIDVARNAME=&ValidVarName.;
  634.    OPTIONS LS=&LineSize. PS=&PageSize. &Date. &ByLine. &Number VALIDVARNAME=&ValidVarName.;
  635. %MEND LogCheck;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement