我輩はブロガーではない。ネタもまだない

SASとかDelphiあたりの人様の役に立たないネタを提供します

BaseSASユーザのためのGit(その6:実行ログの管理)

今回はログの話。めっちゃ長いyo。
構成ファイルだけ見たい方は最後へどうぞ。


カスタム操作でclass.sasをバッチ実行すると、ログが更新されてSourceTreeでは差分が検出されると思います。

f:id:japelin:20211215093049p:plain
タイトルの日時行と、CPU時間、処理時間で差分を検出している

1. CPU時間、処理時間を削除

プログラムに変更はないのに、実行毎に異なる処理時間が差分として検出されてしまうのは、あまり意味がないと思います。(ボトルネック調査には必要ですけど)
ですので、まずはこれらのCPU時間、処理時間が出力されないように変更します。

Mysasv9.cfgを開き、以下のように編集します

-CONFIG "C:\Program Files\SASHome2\SASFoundation\9.4\nls\ja\sasv9.cfg"
-NOSTIMER

デフォルトのconfigファイルを読み込みつつ、NOSTIMERによって、処理時間、CPU時間を非表示にします。

f:id:japelin:20211214231317p:plain
処理時間とCPU時間が消えた


これでMysasv9.cfgは一旦コミットしておきましょう。

2. カレントディレクトリへの復帰


試しにclass.sasの最後に以下のステートメントを追加してバッチ実行をしてみてください。

options noxwait xsync;
x "cd C:\Temp";


termstmt.sasが見つからない、というエラーが出ていますね

f:id:japelin:20211215181057p:plain
実行環境とは異なるディレクトリを参照しているため、見つからない

プログラム中でカレントディレクトリが変更された場合、termstmt.sasが参照できなくなってしまいます。

これを避けるために、Mysasv9.cfgのTERMSTMTのtermstmt.sasを実行する前の行に以下を追加します。

%LET execpath=%SYSFUNC(GETOPTION(SYSIN));
%LET PrgDir=%ksubstr(&execpath.\\,1,%kindex(&execpath.\\,%kscan(&execpath,-1,"\")\\)-1);
options noxwait xsync;
x "cd ""&PrgDir""";

ここでは、カレントディレクトリのtermstmt.sasを参照するために、実行プログラムのパスを取得してカレントディレクトリを戻すという処理をしています。

本体のプログラムを編集することなくプログラム処理が書けるのがTERMSTMTのいいところです。


class.sasの変更は破棄し、Mysasv9.cfgはコミットしておきます。

3. プログラムの編集による行数変更

プログラムの2行目に以下のオプションを追加してバッチ実行してみます。

options nofmterr;


SourceTreeでclass.logを見てください。
どうでしょうか。

2行目にoptionsステートメントが挿入されたため、以降の行数が変わり、ログにはソース行が全て出力されてしまっています。

f:id:japelin:20211220154321p:plain
行数が変わっただけなのに…

これではプログラムを修正するたびに、修正箇所以降のソース行が全て編集として検出されてしまいます。
どうにかログから行数を取り除きたいのですが、そのようなオプションは存在しないため、自力で加工する必要があります。

termstmt.sasのdataステップを以下のように変更します。(_infile_ 一時変数も編集できるんですね。)

data _null_;
  length fchar $1 ichar $10;
  infile y lrecl=&ls;
  input;
  file z;
  fchar=subpad(_infile_,1,1);
  ichar=trim(scan(_infile_,1,' '));
  if input(fchar,??best.) and 
     input(ichar,??best.) then do;
    firstblank=length(ichar)+1;
    substr(_infile_,1,firstblank-1)='';
  end;
  put _infile_;
run;

1文字目を数値かどうかチェックしつつ、scan関数でスペース区切りで取得した文字列の1つ目が数値であるかどうかをチェックし、いずれも数値なら行番号と判断して、スペースに置き換えています。
他の書き方もあるようですが、偶然proc optionsを実行したときのログに、正しく動かないパターンがあったので、上記のように作り直しました。
なお、172万行のログでも1秒位で書き換えが終わるので、処理速度はあまり問題にならないと思います。

f:id:japelin:20211220154446p:plain
ソース行の行数だけが消えている

4. タイトル行と日付

残るは、SAS システムというタイトル行と日付です。
タイトルだけならまだいいのですが、日付はアウトプットとは異なり、NODATEオプションでは制御できません。
そのため、こちらもログの加工が必要になります。

先程のtermstmt.sasに以下を追加します。

  if index(_infile_,'     SAS システム     ')then delete;

ログはページ区切りのたびにタイトル行が出力されますので、1行目だけは出力し、2ページ目以降のタイトル行だけを削除したい場合は、以下のように書きます。

  if _n_>1 and index(_infile_,'     SAS システム     ')then delete;

ついでに改ページコードも削除してくれるのもgoodポイント。

f:id:japelin:20211220154428p:plain
タイトル行が消えている

5. ログの確認

サブミットしたログをすぐに確認したいときにはtermstmt.sasの最終行を以下のように変更します。

x "timeout /T 1 >nul & copy ""&zfile"" ""&xfile"" & del ""&zfile"" & ""&xfile""";

SourceTreeからサブミットしたログがすぐに.logに関連付けられたアプリケーションで開きます。
SASのままだと毎回SASが起動して面倒かもしれないので、シンタックスハイライトできるエディタがおすすめです。
EmEditorとか。

おさらい

今回編集したソース

options noxwait xsync;
%let ls=%eval(%sysfunc(getoption(LINESIZE))+1);
%let xfile=%sysfunc(getoption(LOG));
%let yfile=%sysfunc(pathname(work))\_tmp_.log;
%let zfile=%sysget(temp)\_mod_.log;
filename y "&yfile";
filename z "&zfile" encoding='utf-8';
x "copy /Y ""&xfile"" ""&yfile"" >nul";
data _null_;
  length fchar $1 ichar $10;
  infile y lrecl=&ls;
  input;
  file z;
  if _n_ >1 and index(_infile_,'     SAS システム     ')then delete;
  fchar=subpad(_infile_,1,1);
  ichar=trim(scan(_infile_,1,' '));
  if input(fchar,??best.) and 
     input(ichar,??best.) then do;
    firstblank=length(ichar)+1;
    substr(_infile_,1,firstblank-1)='';
  end;
  put _infile_;
run;

options noxsync;
x "timeout /T 1 >nul & copy /Y ""&zfile"" ""&xfile"" >nul & del ""&zfile"" & ""&xfile"" " ;

(copyコマンドに上書きパラメータ指定&結果を非表示にする>nulを追加しています)

  • Mysasv9.cfg
-CONFIG "C:\Program Files\SASHome2\SASFoundation\9.4\nls\ja\sasv9.cfg"
-NOSTIMER
-TERMSTMT='
%LET execpath=%SYSFUNC(GETOPTION(SYSIN));
%LET PrgDir=%ksubstr(&execpath.\\,1,%kindex(&execpath.\\,%kscan(&execpath,-1,"\")\\)-1);
options noxwait xsync;
x "cd ""&PrgDir""";
%inc "termstmt.sas";
'

最後に

前回から続いてコミットが溜まっているので、(不要なものは変更を破棄して)SubmitTestブランチをMasterにマージしておきましょう。