はじめに
Caché は、特定のイベントが発生したときに、ユーザが記述したルーチンを呼び出すメカニズムを提供します。各イベントの処理は、通常システム自体のサブルーチンとして扱われます。Caché には、^%ZSTART および ^%ZSTOP という 2 つのルーチンがあります。それぞれが、システムが事前に定義した 4 組の中の 1 つ以上のラベルを定義します。これらのラベルは、イベントのクラスが起きた際に呼び出される各ルーチンへのエントリ・ポイントになります。
適切なラベルは、その動作が開始ならば ^%ZSTART 内で、終了ならば ^%ZSTOP 内で呼び出されます。
これらのエントリ・ポイントは、Caché のサブルーチンとして機能しますが、複雑な計算をしたり、長時間実行するためのものではありません。ネットワーク・アクセスなどのように長期的に計算したり、潜在的に長時間わたって実行すると、呼び出されたルーチンが返されるまで動作の完了が遅れます。この場合、ユーザのログインに長い時間がかかったり、時間がかかりすぎるために JOB の処理能力が削減される場合があります。
設計に関する考慮事項
^%ZSTART および ^%ZSTOP の実行環境にはある程度制約があります。設計者は以下のような点に注意してください。
%ZSTART および %ZSTOP を有効にする
^%ZSTART^%ZSTOP は、%SYS ネームスペースに属さなければ (したがってコンパイルされなければ) なりません。しかし、Caché がこれらを使用して自動的に開始するには、ただそこにあるだけでは不十分です。代わりに、構成マネージャから個々のエントリ・ポイントを有効または無効にします。
一旦ルーチンを設計、開発、コンパイルし、テストができる段階になると、構成マネージャから個々のエントリ・ポイントを有効にすることができます。構成マネージャを開始し、[詳細] タブを選択します。表示されたパネルで [開始] から、[ユーザ・コード有効] を開くと、8 項目のリストが表示されます。このリストは、4 つのイベント・クラスの動作開始または停止の、すべての組み合わせに対応しています。
これらの各項目を、有効にする (=  はい) または無効にする (=  いいえ) に指定します。設定を変更するには、項目を強調表示にして [変更] オプションを選択します。項目の有効 (チェックあり)/ 無効 (チェックなし) を示すチェック・ボックスを持つダイアログ・ボックスが表示されるので、必要に応じて変更し、設定を変更した場合は [OK] をクリックして適用します。
構成マネージャの終了時に、ユーザはこの設定を適用するか、適用しないかを選択することができます。場合によっては、この設定を有効にするために Caché を再起動する必要があります。
例えば、バックグラウンド・プロセスが開始するたびに何かを得たいとします。以下のすべてに該当する場合、適切なエントリ・ポイント JOB%^ZSTART が呼び出されます。
^%ZSTART および ^%ZSTOP のデバッグ
最終的な環境において ^%ZSTART^%ZSTOP をデバッグする機会はほとんどありません。エラーが発生した際にインタラクティブ・セッションでターミナルに記述されるエラー・メッセージは、オペレータのコンソール・ログに転送されます。これは Caché 管理者ディレクトリにある “cconsole.log” ファイルです。
メッセージは、失敗の原因とエラーが検出された位置を示します。この位置は、プログラム・ロジックまたはフローで実際にエラーが発生した場所とは異なる場合があります。開発者は、提供された情報からエラーの特性と場所を推定し、ルーチンを修正してください。これにより、今後のテストでは、発生するエラーの特性についてより多くの情報を得ることができるようになります。
極端な失敗が発生した場合でない限り、他の Caché の機能が使用できなくなっていても、構成マネージャは開始したり、実行することができます。つまり、原因の関数の使用を無効にし Caché を再起動することにより、そのエラー状態から回復し分析することができます。
1 つ以上のエントリ・ポイント呼び出しを無効にするには、以下を実行します。
  1. [構成マネージャ] を起動します。
  2. [詳細] タブをクリックします。
  3. [開始] の [ユーザ・コード有効] を開きます。
  4. それぞれの項目を選択し、[変更] をクリックして、各オプションの設定を変更します。
  5. 変更を加えた後、[OK] をクリックします。
場合によっては、この設定を有効にするために Caché を再起動する必要があります。
^%ZSTART および ^%ZSTOP (および、サポートする任意のルーチン) が正確に格納されるように注意してください。これらのトレースをすべて削除するには、以下を実行します。
  1. Caché [エクスプローラ] を起動します。
  2. [%SYS] ネームスペースを開きます。
  3. [ルーチン] を選択します。
  4. 右側のパネル (ルーチンのコンテンツ) で、削除するルーチンを探します。
  5. 削除したいルーチンを選択します。
  6. [ファイル] メニューから [削除] を選択します。次に表示されるダイアログ・ボックスで、[はい] を選択すると、削除を確認します。
Note:
必ず、ルーチンを削除する に、Caché 構成マネージャ経由でエントリ・ポイントを無効にしてください。この変更を有効にするために、構成マネージャが Caché を再起動するように警告した場合は、次に進む前に再起動も実行してください。これにより、エントリ・ポイントが削除される間に、実行されることはありません。
実装例
以下は、システムの動作状況を追跡する単純なログの実例です。これは、^%ZSSUtil と呼ばれるログ・エントリを記述する共通のユーティリティと、^%ZSTART^%ZSTOP に対する別々のルーチンで構成されます。^%ZSTOP ルーチンは、^%ZSTART の多くの動作に似ているため、ここでは ^%ZSTART^%ZSSUtil について主に説明しますが、上記の 3 つのルーチンについて、すべて実例を示しています。
Note:
以下の 3 つのコードは、ユーザの理解を深めるために記述されたものです。ObjectScript の便利な利用法や簡潔な記述方法を示したものではありません。
ルーチン:^%ZSSUtil
このルーチンには、2 つのエントリ・ポイントがあります。一方は、オペレータのコンソール・ログに 1 行記述し、他方は、ローカルのログ・ファイルに名前と値の組み合わせのリストを記述します。オペレータのコンソール・ログもローカルのログ・ファイルも Caché の管理者のディレクトリにあります。このディレクトリの名前は、ManagerDirectory メソッドまたは %Library.File クラスにより返されます。
%ZSSUtil ;
    ; this routine packages a set of subroutines 
    ; used by the %ZSTART and %ZSTOP entrypoints
    ; 
    ; does not do anything if invoked directly
    quit
    
#Define Empty ""
#Define OprLog 1
    
WriteConsole(LineText) PUBLIC ;
    ; write the line to the console log
    ; by default the file cconsole.log in the MGR directory
    new SaveIO
    
    ; save the current device and open the operator console
    ; set up error handling to cope with errors
    ; there is little to do if an error happens
    set SaveIO = $IO
    set $ZTRAP = "WriteConsoleExit"
    open $$$OprLog
    use $$$OprLog
    ; we do not need an "!" for line termination
    ; because each WRITE statement becomes its 
    ; own console record (implicit end of line)
    write LineText
    ; restore the previous io device
    close $$$OprLog
    ; pick up here in case of an error
WriteConsoleExit ;
    set $ZTRAP = ""
    use SaveIO
    quit
    
WriteLog(rtnname, entryname, items) PUBLIC ;
    ; write entries into the log file
    ; the log is presumed to be open as 
    ; the default output device
    ; 
    ; rtnname: distinguishes between ZSTART & ZSTOP
    ; entryname: the name of the entrypoint we came from
    ; items: a $LIST of name-value pairs
    new ThisIO, ThisLog
    new i, DataString
    
    ; preserve the existing $IO device reference
    ; set up error handling to cope with errors
    ; there is little to do if an error happens
    set ThisIO = $IO
    set $ZTRAP = "WriteLogExit"

    ; construct the name of the file
    ; use the month and day as part of the name so that 
    ; it will create a separate log file each day
    set ThisLog = "ZSS"
                _ "-"
                _ $EXTRACT($ZDATE($HOROLOG, 3), 6, 10)
                _".log"
    
    ; and change $IO to point to our file
    open ThisLog:"AWS":0
    use ThisLog
    
    ; now loop over the items writing one line per item pair
    for i = 1 : 2 : $LISTLENGTH(items)
    {
        set DataString = $LISTGET(items, i, "*MISSING*")
        if ($LISTGET(items, (i + 1), $$$Empty) '= $$$Empty)
        {
            set DataString = DataString
                           _ ": "
                           _ $LISTGET(items, (i + 1))
        }
        write $ZDATETIME($HOROLOG, 3, 1),
              ?21, rtnname,
              ?28, entryname,
              ?35, DataString, !
    }
    
    ; stop using the log file and switch $IO back
    ; to the value saved on entry
    close $IO
    ; pick up here in case of an error
WriteLogExit ;
    set $ZTRAP = ""
    use ThisIO
    quit
説明
ラベル:^%ZSSUtil
このルーチンは、他のルーチンと同様に、まず QUIT コマンドを実行して、以下のコマンドから呼び出されると良好な結果が得られます。
    do ^%ZSSUtil
#DEFINE 配列は、外観をそろえるために、プログラムの本文に指定された制約を提供します。このインスタンスでは、空文字列とオペレータのコンソール・ログのデバイス番号を指定します。
ラベル:WriteConsole^%ZSSUtil
このエントリ・ポイントは非常に単純です。容量の少ない出力用に、またデバッグの出力に使用するための最小限のルーチンとして、設計されたものです。
引数として 1 つの文字列を持ち、これをオペレータのコンソール・ログに記述します。しかし、現在の呼び出しの $IO 装置の保存とリストアは、注意して実行しなければなりません。
コンソール・デバイスでは、デバイス各項目が送信された結果、コンソール・ログには別々のレコードが記述されます。以下にコードの例があります。
    WRITE 1, 2, 3, !
上記は、4 つのレコードを記述します。最初の 3 つは 1 桁の数字からなり、4 つめは空白行からなります。1 行に複数の項目を記述したい場合は、呼び出し元がこれらを文字列に連結させなければなりません。
ラベル:WriteLog^%ZSSUtil
これは、上記のルーチンよりも複雑です。^%ZSTART または ^%ZSTOP 内の任意のエントリ・ポイントから呼び出すことができます。最初の 2 つの引数は、このラベルが何に対して実行しているかについてのリポートに必要な情報を提供します。3 番目の引数は、ログに記述される名前と値の組み合わせの $LIST です。
このエントリ・ポイントは、まず使用するファイルの名前を作成します。ログ管理を簡素化するため、この名前にはルーチンが入力された月日が含まれます。したがって、WriteLog への呼び出しは、現地時間が深夜 12 時をすぎる度に、新規のファイルを作成します。その名前は呼び出し時にのみ決定されるため、引数として渡される名前と値の組み合わせはすべて同じファイルに表示されます。
一旦名前が作成されると、$IO の現在値を後で使用できるように保存し、出力デバイスを指定されたログ・ファイルに切り替えます。OPEN コマンドに使用するパラメータによって、そのファイルがなければ作成するように指定されています。timeout がゼロの場合、Caché がファイルを 1 回だけ開こうとします。 もし開くことができなければ失敗します。
そのファイルが一旦開かれると、コードは名前と値の組み合わせをループします。各組み合わせに対し、その行に呼び出しルーチン名とエントリ・ポイント名、続けて名前と値の組み合わせが記述されます (値の部分が空文字列の場合は、名前のみ記述)。組み合わせは 1 行に 1 個ずつ記述されます。読みやすいように、各行の最初の 3 つの値は一列に並ぶようになっています。
すべての組み合わせの記入後、ログ・ファイルを終了し、先ほど保存した $IO の値がリストアされ、コントロールは呼び出し元に返されます。
ルーチン:^%ZSTART
このルーチンには、実際に Caché に呼び出されるエントリ・ポイントを含みます。上記の ^%ZSSUtil の機能も使用します。すべてのエントリ・ポイントは、事実上同じように動作し情報をログに配置します。SYSTEM エントリ・ポイントは、他に比べるとやや複雑ですが、同様にオペレータのコンソール・ログに情報を配置します。
%ZSTART ; User startup routine. 
 
#Define ME "ZSTART"
#Define BgnSet "Start"
#Define Empty ""

    ; cannot be invoked directly
    quit
 
SYSTEM ;
    ; Cache starting
    new EntryPoint, Items
     
     set EntryPoint = "SYSTEM"
    
     ; record the fact we got started in the console log
     do WriteConsole^%ZSSUtil((EntryPoint
                               _ "^%"
                               _ $$$ME
                               _ " called @ "
                               _ $ZDATETIME($HOROLOG, 3)))
    
    ; log the data accumulate results
     set Items = $LISTBUILD($$$BgnSet, $ZDATETIME($HOROLOG, 3),
                           "Job", $JOB,
                           "Computer", $ZUTIL(110),
                           "Version", $ZVERSION,
                           "StdIO", $PRINCIPAL,
                           "Namespace", $ZUTIL(5),
                           "CurDirPath", $ZUTIL(12),
                           "CurNSPath", $ZUTIL(12, ""),
                           "CurDevName", $ZUTIL(67, 7, $JOB),
                           "JobType", $ZUTIL(67, 10, $JOB),
                           "JobStatus", $ZHEX($ZJOB),
                           "StackFrames", $STACK,
                           "AvailStorage", $STORAGE,
                           "UserName", $ZUTIL(67, 11, $JOB))
    do WriteLog^%ZSSUtil($$$ME, EntryPoint, Items)
    
    quit
    
LOGIN ;
    ; a user logs into Cache (user account or telnet)
    new EntryPoint, Items
    
    set EntryPoint = "LOGIN"
     set Items = $LISTBUILD($$$BgnSet, $ZDATETIME($HOROLOG, 3))
    do WriteLog^%ZSSUtil($$$ME, EntryPoint, Items)
    quit
    
JOB ;
    ; JOB'd process begins
    new EntryPoint, Items
    
     set EntryPoint = "JOB"
     set Items = $LISTBUILD($$$BgnSet, $ZDATETIME($HOROLOG, 3))
    do WriteLog^%ZSSUtil($$$ME, EntryPoint, Items)
    quit
     
CALLIN ;
    ; a process enters via CALLIN interface
    new EntryPoint, Items
    
     set EntryPoint = "CALLIN"
     set Items = $LISTBUILD($$$BgnSet, $ZDATETIME($HOROLOG, 3))
    do WriteLog^%ZSSUtil($$$ME, EntryPoint, Items)
    quit
説明
ラベル:^%ZSTART
^%ZSSUtil の説明でも述べたように、このルーチンはまず QUIT コマンドを実行します。 エントリ・ポイントの 1 つから実行を開始するのではなく、ルーチンとして呼び出す方が良好な結果を得ることができるためです。
このルーチンは、そのルーチン自体の名前、開始文字列および空文字列に対し、指定された定数 (マクロとして) を定義します。
ラベル:SYSTEM^%ZSTART
^%ZSSUtil がログ・ファイルの記述に関する詳細な機能の大部分を担うため、このルーチンは主に情報を収集し、その後 ^%ZSSUtil で適切なエントリ・ポイントを呼び出します。これは、そのルーチン名、エントリ・ポイント、呼び出された日付時刻を使用した文字列を作成します。その後、WriteConsole^%ZSSUtil を呼び出してオペレータのコンソール・ログに配置します。
後で、表示したい名前と値の組み合わせのリストを作成し、これを WriteLog^%ZSSUtil に渡してローカルのログ・ファイルに配置します。その後、呼び出し元に戻ります。
ラベル:LOGIN^%ZSTARTJOB^%ZSTARTCALLIN^%ZSTART
SYSTEM エントリ・ポイントとは異なり、これらはオペレータのコンソール・ログに情報を置きません。呼び出す際に識別するための簡単な項目のリストを作成し、WriteLog^%ZSSUtil を使用して記録します。
ルーチン:^%ZSTOP
このルーチンは、実際に Caché に呼び出されるエントリ・ポイントを含みます。^%ZSTART と同様に、^%ZSSUtil の機能を使用します。^%ZSTOP のエントリ・ポイントは、%ZSTART のエントリ・ポイントと同じ名前と同様の機能を持ち、SYSTEM エントリ・ポイントのみがオペレータのコンソール・ログに記述します。すべてのルーチンは、ローカルのログに動作状況を記録します。
%ZSTOP ; User shutdown routine. 
 
#Define ME "ZSTOP"
#Define EndSet "End"
#Define Empty ""

    ; cannot be invoked directly
    quit
 
SYSTEM ; Cache stopping
    new EntryPoint
    
    set EntryPoint = "SYSTEM"
     ; record termination in the console log
     do WriteConsole^%ZSSUtil((EntryPoint
                               _ "^%"
                               _ $$$ME
                               _ " called @ "
                               _ $ZDATETIME($HOROLOG, 3)))
     ; write the standard log information
    do Logit(EntryPoint, $$$ME)
    quit
    
LOGIN ; a user logs out of Cache (user account or telnet)
    new EntryPoint
    
    set EntryPoint = "LOGIN"
    do Logit(EntryPoint, $$$ME)
    quit
    
JOB ; JOB'd process exits. 
    new EntryPoint
    
    set EntryPoint = "JOB"
    do Logit(EntryPoint, $$$ME)
    quit
     
CALLIN ; process exits via CALLIN interface. 
    new EntryPoint
    
    set EntryPoint = "CALLIN"
    do Logit(EntryPoint, $$$ME)
    quit
    
Logit(entrypoint, caller) PRIVATE ;
    ; common logging for exits
    
    new items
    
     set items = $LISTBUILD($$$EndSet, $ZDATETIME($HOROLOG, 3))
    do WriteLog^%ZSSUtil(caller, entrypoint, items)
    quit
説明
このルーチンの機能は、^%ZSTART に類似しています。詳細は、^%ZSTART の概要、例、説明を参照してください。