この章では,Tru64 UNIX Event Manager (EVM) のユーザ・レベル・プログラミング・インタフェースについて説明します。 この章に記載した主な問題は次のとおりです。
イベントとして扱う状態の変化の決定方法
イベントの内容の設計
EVM の API 関数とユーティリティを使用した,イベントの発信,登録,およびアクセス
この章では,イベントとは,次のいずれかが関心を持つ可能性のある現象が起きたことを示します。
システム管理者,アプリケーション管理者,またはその他のユーザ
システム監視ソフトウェア
オペレーティング・システム
アプリケーション・プログラム
これらは,ローカル・システムまたはリモート・システムに存在します。
この章では,ユーザ・レベルのイベント処理についてのみ説明します。
カーネル内部でのイベントの発信と登録については,
kevm
(7)
この章では,以下の項目について説明します。
イベントとイベント管理 (14.1 節)
EVM インベント処理の概要 (14.2 節)
EVM の起動と停止 (14.3 節)
イベントの発信とアクセスの権限 (14.4 節)
EVM イベントの内容 (14.5 節)
イベント・セットの設計 (14.6 節)
EVM プログラミング・インタフェース (14.7 節)
EVM へのイベント・チャネルの追加 (14.8 節)
EVM プログラミング・インタフェースがサポートする関数の詳細については,オンライン・リファレンス・ページに記載しています。 使用頻度の高い EVM 関数の概要と例については 14.7 節 を参照してください。
イベント・ビューアとコマンド行インタフェースについては,この章では説明していません。
ビューアについては,オンライン・ヘルプを参照してください。
コマンド行での操作については,『システム管理ガイド』 マニュアルを参照してください。
14.1 イベントとイベント管理
EVM では,イベント情報の発信,配信,保存,および表示を集中管理することができます。 このとき,各イベント発信者が使用するイベント・チャネルには依存せず,発信者と現在のチャネルの関係を変更する必要もありません。 EVM を使用すると,従来のバージョンの Tru64 UNIX システムと比較して,システム管理者は簡単にイベント情報にアクセスできます。 また,柔軟なインフラストラクチャが提供されているので,次の配信元でイベント配信チャネルとして使用することができます。
Tru64 UNIX の開発グループ
独立ソフトウェア・ベンダ
ユーザ・アプリケーションの開発者
その他のイベント・チャネル
イベント情報を渡すためのメカニズムは,イベント (またはイベント通知) と呼ばれ,イベントを生成するコンポーネントはイベント発信者 (event poster) と呼ばれます。 EVM のイベント発信メカニズムは,単方向の通信チャネルです。 これは,発信者が,イベントのアクセスを希望する任意エンティティに対して情報を通信できるようにしたものです。 発信者は,どのエンティティが発信イベントのアクセスを希望しているかを把握している必要はありません。
イベント情報を受信するエンティティは,イベント受信者 (event subscriber) と呼ばれます。 イベントによって,受信者の種類は異なり,システム管理者や,他のソフトウェア・コンポーネント,または一般ユーザなどが含まれることがあります。 また,イベントによっては受信者が存在しないこともあります。
イベントは,任意のプロセスで発信および受信を行うことができます。 また,同一のプロセスで発信と受信の両方を行うこともできます。 ただし,特定のイベントの発信および受信は,セキュリティ権限によって管理されます (14.4 節)。
Tru64 UNIX システムの以前のバージョンでは,イベント処理のためにさまざまな種類のチャネルがサポートされており,標準のものもあれば専用のものもありました。
最も単純なイベント・チャネルは,静的な ASCII ログ・ファイルです。
このログ・ファイルには,単一のソースからのイベント情報が格納され,ユーザは標準の UNIX ツール (more
など) を使用して表示できます。
動的なチャネルとしては,システム・ロガー (syslog
) やバイナリ・イベント・ロガー (binlog) などがあります。
どちらのチャネルでも,デーモン・プロセスを使用して,複数のソースに関するイベント情報の受信,記録,および転送を行います。
syslog と binlog
についての詳細は,
syslogd
(8)binlogd
(8)
EVM では,複数のイベント・チャネルを集中管理するために,すべてのソースのイベントが 1 つのイベント・ストリームに結合されます。 イベントに関心のあるユーザは,結合されたストリームをリアル・タイムで監視したり,イベントの履歴をストレージから取得して表示したりできます。 EVM の表示機能には,グラフィカルなイベント・ビューアと,完全なセットのコマンド行ユーティリティがあります。 イベント・ビューアは,SysMan アプリケーションに統合されています。 コマンド行ユーティリティでは,イベントのフィルタ,ソート,およびフォーマットをさまざまな方法で行うことができます。 選択した状態が自動的に通知されるように EVM を構成することもできます。
注意
EVM は,メッセージをブロードキャストするための機能です。 2 つのプロセス間に二地点間専用通信チャネルをインプリメントする場合には使用しないでください。 このような目的で EVM を使用すると,システムの性能が低下する可能性があります。 別のプロセスと通信を確立する必要があるときに,送信する情報がシステム管理者やその他のプロセスに関係がない場合は,ソケットまたはパイプなどの通信チャネルを使用して直接接続してください。
図 14-1
は,発信,受信,および取得操作の概要です。
イベント取得操作については,
evmget
(1)図 14-1: EVM の概要
EVM イベントはデータのパッケージであり,さまざまなソフトウェア・コンポーネント間で受渡したり,後で表示するためにデータを保存できます。
イベントを発信するためには,EVM データベースに保存されているイベント・テンプレートと一致している必要があります。 イベントのデータ項目は,発信するイベントまたは一致するテンプレートに設定できます。 発信したイベントのデータ項目とイベント・テンプレートのデータ項目をマージした結果が,イベント受信者が受信するイベントの内容になります。 イベントの一致およびマージについての詳細は,14.6.3.2 項 および 14.6.3.3 項を参照してください。
標準的なイベントのライフ・サイクルには,次の操作が含まれます。
プロセスから発信される可能性のあるすべてのイベントに対して,テンプレートが作成されます。 テンプレートは,製品またはサブシステムのインストール時に EVM データベースに格納されます。
イベントの受信に関係するプロセスでは,EVM デーモンに対する接続が確立されて,受信要求が発行されます。 受信要求には,関心のあるイベントの識別に使用するフィルタが指定されています。
プロセスまたはカーネル構成要素でイベントに値する状態変更が検出されると,EVM への接続が行われて,状態変更に対応するイベントが発信されます。
また,EVM 以外のイベント・チャネルでイベントが発信された場合,そのイベントはチャネルによって独自の方法で処理されます (ログの記録など)。 次に,EVM フォーマットに変換されて,EVM に渡されます。
EVM では,イベントの発信要求の有効性が検査されます。 特に,EVM テンプレート・データベースに対応するテンプレートが存在するかどうかと,発信者にイベントを発信する権限があるかどうかが検査されます。 有効である場合は,発信されたイベントとテンプレートのデータ項目がマージされたイベントが作成されます。
マージされたイベントが,EVM からイベントを受信するすべてのプロセスに渡されます。
受信者によって,イベントが適切に処理されます。 たとえば,保存や,システム管理者へのメール送信,アプリケーションのフェールオーバーの開始などが行われます。
EVM は,システムのスタートアップ時に自動的に起動し,システムのシャットダウン時に自動的に停止します。
EVM デーモンの起動と停止については,『システム管理ガイド』を参照してください。
起動時に EVM がイベント・テンプレート・データベースを設定する手順,および起動後にイベント・テンプレート・データベースを修正する方法については,14.6.3.4 項を参照してください。
14.4 イベントの発信とアクセスの権限
イベントの発信とアクセスを行う場合は,セキュリティに関して考慮することが重要です。
特定のイベント情報に対するアクセスを管理しなかった場合,システム操作に関する重要な情報が,その権限のないユーザに与えられることがあります。
特定のイベントの発信を管理しなかった場合,システムのシャットダウンのような重要なシステム操作が,その権限のないユーザによって実行されるおそれがあります。
システム管理者は,EVM 権限ファイル
/etc/evm.auth
を変更することによって,どのユーザがイベントのアクセスや発信を行えるかということを制御できます。
アクセス制御についての詳細は,『システム管理ガイド』 マニュアルを参照してください。
14.5 EVM イベントの内容
イベントによって送信されるデータのフォーマット,タイプ,および目的には,さまざまな種類があります。 単純なイベントの場合は,単純なテキスト・メッセージです。 複雑なイベントの場合は,複雑なバイナリ・データの集合で構成されます。 この場合,データの変換時にフォーマット情報が必要になります。 2 つのアプリケーションが協調して動作する場合は,簡単なバイナリ・フラグまたはカウントの場合もあります。 ただし,イベントにとってデータは必須ではありません。 たとえば,特定のイベント・タイプを送信するだけで,特定の状態変更が発生したことを受信者が認識できることもあります。
イベント・データは,変換方法に応じて複雑になります。 イベントをわかりやすくするために,数値データと説明テキストを組み合わせることもできます。 また,受信プロセスによっては,バイナリ・データとして表示する必要があります。 さらに,複数の言語で表示しなければならないこともあります。
EVM のデータ・メカニズムでは,イベントに適した任意の方法でデータを送信できます。 この機能を使用できる構造体には,EVM フォーマット・データ項目 (EVM の標準データ項目の 1 つ) および EVM 変数データ項目があります。
イベント・データの構造体には,次の 2 種類のデータ項目があります。
標準データ項目 -- 定義済みの名前を持った,一定数の項目
変数データ項目 -- 多くの場合,イベントの設計者が名前と型を定義する
イベントを作成する場合は,任意の数のデータ項目を含めることができます。
イベントを発信すると,ホスト名やタイムスタンプなど,一定の環境標準データ項目が EVM によって自動的に追加されます。
14.5.1 標準データ項目
標準データ項目は,イベントで必須の共通データ項目で,EVM によって認識または処理されます。 標準データ項目の名前は,列挙型定数として指定されています。 したがって,名前自体の領域は,イベントの主な領域ではありません。
一部の標準データ項目は,イベントを発信するアプリケーションまたはイベントのテンプレートによってイベントに挿入されます。 その他のデータ項目は,必要に応じて,EVM コンポーネントにより,自動的に挿入されます。 任意のデータ項目をイベントから抽出することができます。
標準データ項目は,
EvmEvent
(5)表 14-1: 標準データ項目
データ項目 | 説明 |
イベント名 (14.5.1.1 項) | イベントの名前を指定する。 |
フォーマット (14.5.1.2 項) | イベントのメッセージ文字列を指定する。 |
優先度 (14.5.1.3 項) | 受信者にとってのイベントの重要度。 イベント配信の順序には影響しない。 |
I18N カタログ (14.5.1.4 項) | 多国語対応イベント用の I18N カタログ・ファイルの名前。 |
I18N メッセージ・セット ID (14.5.1.4 項) | I18N メッセージ・カタログ内のメッセージ・セットを識別する。 |
I18N メッセージ ID (14.5.1.4 項) | イベント・フォーマットの I18N メッセージ ID。 |
クラスタ・イベント (14.5.1.5 項) | TruCluster 環境では,この項目によりイベントはクラスタ内の全ノードに配信される。 |
参照 (14.5.1.6 項) | イベントの説明テキストに対する参照。 |
以降の各項で,表 14-1
の標準データ項目について詳しく説明します。
14.5.1.1 イベント名データ項目
イベント名データ項目は,イベントを識別する文字列で,通常はイベントの発信元と何が起こったかを知らせます。 イベント名は,イベントの型を一意に識別するので,同じイベントの異なるインスタンスに同じ名前を付けることができます。
EVM は,特定のイベントを発信またはアクセスする権限がユーザにあるかどうかを判断する場合や,イベントに対応するテンプレート情報を検索する場合に,イベント名を使用します。 クライアント・アプリケーションは,イベント名をイベント・フィルタと組み合わせて使用し (14.7.11 項),受信するイベントを選択したり,イベントの受信時に必要な動作を判断したりします。 システム管理者は,イベント名を使用して,特に関心のあるイベントのイベント・ログを検索できます。
イベント名には次のような特徴があります。
名前は,1 つ以上のコンポーネントをドットで区切って続けて記述する。
コンポーネントは英字,数字,下線を順不同で 1 つ以上使用して構成する。
名前に含まれているコンポーネントの数に制限はない。
名前の先頭や末尾にドットを使用することはできない。
コンポーネントを 3 つ以上含んだ名前を持たないイベントは,発信できません。
イベント名のコンポーネントは,最初 (左端) のコンポーネントで始まるイベントの階層構造を表します。
最初のコンポーネントは最も一般的で,イベントの発信を行うエンティティをグローバルなレベルで区別します。
その他のコンポーネントは,レベルの詳細さが増していく順番に並べます。
まずイベントを発信すべきと判断したコンポーネント,何が起こったかという情報,最後に最も詳細な情報を置きます。
たとえば,sys.unix.fs.filesystem_full
というイベント名があるとします。
sys.unix
は,イベントがオペレーティング・システムのコンポーネントから発信されたシステム・イベントであることを示します。
fs
は,イベントがファイル・システム・コンポーネントから発信されたことを示します。
filesystem_full
は,報告している出来事が,ファイル・システムの満杯であることを示す。
何が起こったかを示す基本イベント名は,イベントが発信されるときにコンポーネントを追加して拡張し,より詳しい情報を示すようにすることができます。
前述したイベント名の例では,追加のコンポーネントとしてファイル・システム名を追加して (sys.unix.fs.filesystem_full.usr
など),どのファイル・システムが満杯になったかという情報による拡張が行えます。
名前を拡張しても,短い方の名前の各コンポーネントはすべて拡張した名前に一致するので,このイベントが
sys.unix.fs.filesystem_full
イベントであることに変わりはありません。
sys.unix.fs.filesystem_full
という名前のイベントを検索すると,拡張した名前のイベントも見つかります。
この命名規則では,オープンエンドな方法でイベントを識別できます。
つまり,どのレベルでも詳細な情報を記述できるようになっています。
注意深く命名すると,受信者が,特定のイベントやイベント・クラスを選んで表示したり監視したりするのが容易になります。
イベント名を詳しく指定すると,指定する基準も正確になります。
たとえば,イベント名を
myco.myprod.env.temp.ok
および
myco.myprod.env.temp.high
とすると,システム管理者は
myco.myprod.env.temp
と指定して温度に関するイベントをすべて監視したり,myco.myprod.env.temp.high
と指定して,監視するイベントを高温に関するイベントのみに制限したりすることができます。
システム管理者やモニタリング・ソフトウェアの混乱や誤動作 (誤操作) を避けるため,新しいイベントに一意の名前を付けるようにしてください。 次の規則に従って命名すれば,すでに使用されている名前との重複を避けることができます。
サードパーティの製品またはアプリケーションが発信するイベントでは,名前のコンポーネントのうち最初の 3 つが,イベントを発信する製品のベンダ (vendor),製品 (product),プログラムまたは製品コンポーネント (program or product component) を表すようにします。 vendor コンポーネントがグローバルに一意になるようにするには,このコンポーネントに 2 〜 3 文字の頭文字ではなく,会社のフルネームや他社が使用しないような略称を使用します。
ユーザ・アプリケーションの開発者や管理者は,製品のベンダに関して推奨される規則に従って,最初のコンポーネントを部門を識別する名前にします。
ただし,接頭語
local
を選ぶこともできます。
この接頭語は,ユーザがインストールする外部で開発された製品から発信されるイベントと衝突しないためです。
2 番目のコンポーネントは,そのイベントを発信するアプリケーションまたはグループを識別する名前にします。
たとえば,イベント名の先頭を
myco.payroll
や
myco.admin
にすることができます。
Tru64 UNIX が発信するイベントでは,最初の 2 つのコンポーネントが
sys.unix
であり,3 番目のコンポーネントでイベントを発信するサブシステムを識別します。
最初のコンポーネントの
sys
は,システム・イベント用に予約されています。
次の表に,特殊な意味を持つ名前をリストします。 名前の衝突を防ぐために,これらの名前は指定以外のイベントの最初のコンポーネントには使用しないようにしてください。
名前 | 用途 | 例 |
sys |
オペレーティング・システムのイベント | sys.unix.evm.logger.config_err |
local |
ローカルなユーザ組織用 |
|
test |
ローカルなテスト・イベントの発信用 |
イベント名は,選択して公開した後は変更しないでください。
アプリケーションが発信するイベントは,外部インタフェースの一部であり,他のアプリケーションや製品コンポーネントがそのイベントの受信に依存している可能性があるためです。
14.5.1.1.1 予約コンポーネント名
前項では,イベント名が詳細になれば,管理者は EVM フィルタを用いて特定のタイプのイベントを探す操作がやりやすくなると説明しました。
たとえば,sys.unix.hw.registered.cpu
というイベントは,オペレーティング・システムのハードウェア管理サブシステムが,プロセッサを検出して登録したことを示します。
このイベントでは,変数データ項目 (14.5.2 項) にプロセッサのハードウェア ID が含まれているので,イベント・ビューアまたは
evmshow
でイベントを表示させれば,ハードウェア ID が分かります。
そのプロセッサに関連する問題をトレースしている場合は,イベント・フィルタを使用して,そのハードウェア ID を含むイベントのみを選択することができます。
イベント自体に含まれる変数の値でイベントをフィルタリングすることはできないので,この選択は,選択に使用する情報がイベント名にも含まれている場合にのみ使用できます。
この場合,ハードウェア管理サブシステムは,登録した各デバイスに割り当てたハードウェア ID によって名前を拡張することで,選択を可能にします。
ハードウェア ID が 2 の場合,次のコマンドで関連するイベントを検索できます。
evmget -A -f "[name sys.unix.hw.*.2]"
この例では,アスタリスク (*
) がワイルドカード文字になり,ID 2 を含むハードウェア・サブシステムが発信したイベントがすべて,報告内容にかかわらず見つけられるようになります。
ただし,ハードウェア・サブシステム以外のサブシステムも,プロセッサに関する情報を通知する可能性があるので,このフィルタでは,関心のあるデバイスのイベントをすべて選択できないことがあります。
このようなイベントを検索に含めたい場合もあります。
[name
*.2]
と指定すると検索範囲を広げることはできますが,ハードウェア ID に関係のない 2 という数値を含む他のイベントがログに入っていると,それも結果に含まれてしまいます。
予約コンポーネント名の規約により,発信したサブシステムやアプリケーションにかかわらず,関連イベントを選択できるようになります。
規約では,予約コンポーネント名は下線文字 (_
) で始まり,常に特定タイプのエンティティを識別します。
発信サブシステムやアプリケーションは,イベントを発信する前に予約コンポーネント名を基本イベント名に付加し,識別するエンティティに応じて,それに続くコンポーネントが特定のインスタンスを識別します。
予約コンポーネント名は,一般に特定のサブシステムやアプリケーションの代わりとして定義されますが,名前が定義された後の使用は制限されません。
そのエンティティに関して報告する情報を持つものはすべて,発信するイベント内に,予約名とエンティティ ID を含めることができます。
たとえば,予約コンポーネント名
_hwid
は,ハードウェア管理サブシステムで定義されているとおり,ハードウェア・デバイス ID を指定します。
その後にはデバイス ID が必要です。
したがって,前述の例を続けると,プロセッサの登録を報告するイベントの名前は,sys.unix.hw.registered.cpu._hwid.2
になります。
次のコマンドで,すべてのハードウェア・デバイスに関連するすべてのイベントが検索できます。
evmget -A -f "[name *._hwid]"
次のコマンドを使用すると,最も関心のあるプロセッサまで検索の幅を狭めることができます。
evmget -A -f "[name *._hwid.2]"
発信者が規約に従っているという前提で,ハードウェア ID を除くすべてのコンポーネントに対するフィルタにワイルドカードを使用すると,発信したサブシステムやアプリケーションにかかわらず,関連するイベントがすべて確実に検索されます。
予約コンポーネント名の規約では,予約コンポーネント名を使用する際は,発信されるイベントに同じ名前と値の変数 (先頭の下線を含む) が含まれていなければなりません。
この規約により,受信クライアントは,イベント名を解析して値を検索することなく,EVM の通常の API 関数を通じてイベントから値を取得できます。
それ以外の場合,この規約では同じ情報をイベントに 2 回追加しなければならないので,EvmEventPost()
関数は名前が下線で始まる変数をイベント内で自動的に検索し,呼び出し側のプログラムが対応するコンポーネントをイベント名にまだ含めていない場合,イベントを発信する前にそれを付加します。
名前の自動拡張については,
EvmEventPost
(1)
イベントには,任意の数の予約コンポーネント名を,イベント基本名の後の任意のコンポーネント位置に順不同で付加できます。 各予約コンポーネントのすぐ後には,対応する値コンポーネントが必要です。
EVM の名前照合方式では,発信イベントと一致する部分の最も多い名前が検索されるため,イベントを登録するときに,イベントのテンプレート名に予約コンポーネントを指定する必要はありません。
この節で説明した例では,テンプレート (およびイベントの基本名) は
sys.unix.hw.registered
になります。
予約コンポーネントを名前に追加すると,イベントの発信時に,より詳細なレベルを指定できます。
先頭に下線が 1 つある予約コンポーネント名を定義する規約は,システム用に予約されています。
ローカル・サイトとサードパーティ製品のベンダは,_ _prod_code
のように,予約コンポーネント名の先頭に下線を 2 つ使用して,独自の規約を規定しなければなりません。
Tru64 UNIX
が使用する予約済みのコンポーネント名のリストは,
EvmEvent
(5)14.5.1.1.2 イベント名の比較
イベント名を検索対象の名前と比較するには,EVM の API 関数を使用します。
ただし,strcmp()
は使用しないでください。
着信イベントの名前には,予期しない数のコンポーネントが含まれることがあります。
イベント名の照合についての詳細は,14.7.12.9 項を参照してください。
14.5.1.2 イベントのフォーマット・データ項目
フォーマット・データ項目には,分かりやすい文字列でイベントの概要が説明されています。 フォーマット行は,次のような場合に展開されて表示されます。
イベントが
evmshow
コマンドで表示されている場合
イベントがイベント・ビューアで表示されている場合
プログラムが
EvmEventFormat()
などの表示 API 関数を呼び出した場合
フォーマット・データ項目には,イベント内の他のデータ項目への参照が含まれることもあります。 次の例について説明します。
Application close-down has started Close-down of application $app has started
2 つ目の例では,$app
はアプリケーションの名前に置き換わります。
このとき,イベントにはこの名前の変数の値が含まれているとします。
したがって,この行は次のように表示されます。
Close-down of application payroll has started
変数については,14.5.2 項 で説明しています。
フォーマット行は,発信コンポーネントに関する簡潔な一貫性のある識別情報から開始して,発生した現象が簡単にわかるように記述します。 次のガイドラインを考慮してください。
完全な文章である必要はないが,はっきりとわかりやすく記述する。
複数の文を記述しない。 メッセージの最後にピリオドを付けない。 発生した現象について詳細で文法的に正しい説明を記述する場合は,イベントの説明テキストを使用する。 説明テキストの使用方法については,14.6.2 項を参照。
最も重要な情報 (発生した現象を管理者に伝える部分) を行の先頭に記述して,この情報を表示するときに,管理者がビューア・ウィンドウを水平方向にスクロールする必要がないようにする。 変数データは,多くの場合,行の最後に記述した方がよい。
フォーマット文字列には,すべての変数への参照を含める必要はない。 管理者は,イベントの詳細な説明を要求することによって簡単に変数データを取得できる。 ただし,ファイル・システムやデバイスの名前などの主要なデータは記述する。
代入を行う変数名を指定するには,$app
のように,前に
$
を付けます。
必要に応じて,@host_name
のように,標準データ項目の前に
@
を付けることもできます。
標準データ項目名では大文字および小文字は区別されませんが,変数名では大文字と小文字が区別されます。
フォーマット・テキストで
$
と
@
の特別な意味を無効にするには,前にバックスラッシュ (\
) を付けます。
テキストに定数のバックスラッシュを含めるには,バックスラッシュを 2 つ (\\
) 使用します。
隣接するテキストからデータ項目または変数を区別するには,${app}
のように,名前を中カッコで囲みます。
変数やデータ項目の表示方法は,名前の後にパーセント記号 (%) とフォーマット指定子を続けることで制御できます。
フォーマット指定子では,表示フィールドの最小幅と表示フォーマットを指定します。
たとえば,次のフォーマット文字列は,device_id
という変数が 16 進数形式で表示され,temperature
が浮動小数点,小数点以下 2 桁で表示されることを示します。
The cabinet temperature for device 0x$device_id%x is $temperature%.2 degrees
これに対応するイベントは次のように表示されます。
The cabinet temperature for device 0x7a is 62.4 degrees
有効なフォーマット指定のリストは,
evmshow
(1)
表 14-2
は,フォーマットされたイベントを作成するときに,イベントのフォーマット・テキストに変数とデータ項目が代入される場合の例です。
表 14-2: イベント・テキストへの変数代入
フォーマット・データ項目 | 変数データ項目 | 生成されたテキスト |
Application started |
なし | Application started |
Debug message: $msg |
msg (string) = "Checkpoint reached" |
Debug message: Checkpoint reached |
Temperature too high: $temp |
temp (float) = 87.2 |
Temperature too high: 87.2 |
This event was posted by @user_name |
なし | This event was posted by jem |
イベントの優先度は,イベントのログ記録,ソート,表示,および対応を手動または自動で行うときの,イベント選択基準として使用されます。
この優先度は,受信者の EVM クライアントにイベントを配信する順序の決定には使用されません。
イベントは,EVM デーモンが受信した順に配信されます。
優先度は 0 〜 700 の整数値で,0 が最も低い重要度になります。
優先度レベルについての詳細は,
EvmEvent
(5)
システム管理者は,優先度に応じて次のような対応を行います。
優先度が 200 (通知レベル) 以上のすべてのイベントのログが記録されるように,ロガーを構成する。
優先度が 600 (警報レベル) 以上のイベントが発信されたときに,メールの送信または警報の発行 (ポケベルで呼び出す,など) が行われるように,ロガーを構成する。
ビューアを使用して,優先度が 300 (警告レベル) 以上のイベントをすべて検索する。
ビューアを使用して,ログに記録されたすべての優先度のイベントを調べ,問題を分析したり,システムが正しく動作していることを確認する。
優先度は,発信コード内にハードコードしないでください。 優先度はテンプレート・ファイルに設定します。
イベントの優先度を選択する場合は,同じアプリケーション内,およびその他の類似したアプリケーション内のほかのイベントと一貫性を保つようにします。
アプリケーションに適用できない優先度がある場合は,使用する優先度を制限してください。
EvmEvent
(5)
イベントの優先度は慎重かつ客観的に選択してください。 発生する結果ではなく,通知する内容を考慮します。 たとえば,アプリケーションの障害には重要なものもありますが,多くはそうではありません。 アプリケーションの重要度は,上位のコンポーネントで判断します。 上位のコンポーネントでは,エラー・イベントを受信して,重要度が認識されているアプリケーション・エラーが通知されたときに,クリティカル・レベルのイベントを発行します。
これらの考慮事項を基準にして,エラーは発生しているがクリティカルの基準に達していないイベントの優先度は,500 (クリティカル・レベル) ではなく 400 (エラー・レベル) に指定します。 一方,システムの温度が高すぎることを通知するイベントは,ほとんどの場合クリティカルです。
相互に関連するイベントの優先度は,イベントごとに設定します。
たとえば,優先度が 500 の障害イベントを発信してアプリケーションに障害が発生したことを通知してから,関連するイベントを発信してアプリケーションがリストアされたことを通知する場合,2 つ目のイベントの優先度は,たとえば 200 など,最初のイベントより低く設定します。
リストア・イベントに優先度 500 を設定した場合は,イベントに対して不適切なアクションがとられることがあります。
14.5.1.4 I18N カタログ名,メッセージ・セット ID,およびメッセージ ID データ項目
イベントに含まれているテキストが,さまざまな国の管理者に通知される可能性がある場合は,イベントの多国語対応を検討してください。 イベントの多国語対応を行うには,すべてのイベントに対するフォーマット文字列が格納された I18N カタログ・ファイルが必要です。 ただし,イベント・テキストを表示するときにカタログ・ファイルが使用できない場合は,イベントにテキストを記述してください。
カタログ・ファイルは,通常の I18N の規則に従って配置し,イベントの仕様にそのファイル名を含める必要があります。 言語ロケールごとに,独自のカタログ・ファイルを指定することもできます。 詳細は,『国際化ソフトウェア・プログラミング・ガイド』を参照してください。
カタログ・ファイルを複数のメッセージ・セットに分割し,イベントにメッセージ・セット ID を指定することもできます。 1 つのイベントに関連するメッセージは,すべて同じメッセージ・セットに属していなければなりません。
データ項目
I18N_catalog
および
I18N_msgset_id
はカタログ名を定義します。
また,該当する場合は,フォーマット・テキストのメッセージ・セットと,イベントに含まれる文字列変数のうち関連するメッセージ ID が指定されているものをすべて定義します。
データ項目
I18N_format_msg_id
には,フォーマット・テキストのメッセージ ID を定義します。
カタログまたはメッセージ ID が指定されていない場合は,イベント概要を表示するときに,フォーマット・データ項目に指定されたフォーマット・テキストが使用されます。
イベント・テキストの翻訳の設定方法については,14.6.4 項を参照してください。
14.5.1.5 クラスタ・イベント・データ項目
クラスタ・イベント・データ項目が true に設定され,TruCluster システムのメンバであるシステムにイベントが発信されると,EVM はクラスタのアクティブなノードすべての受信者にイベントを配信します。 項目が設定されていないか,false に設定されている場合,イベントはローカル・ノードの受信者にのみ配信されます。 イベントがスタンドアロンのシステムに発信される場合,この項目に効果はありません。 クラスタ・イベント・フラグを true に設定しているイベントは,クラスタワイド・イベントと呼ばれます。
テンプレートまたは
evmpost
へのイベント指定の中で使用すると,クラスタ・イベント・データ項目の値は true または false になります。
API 関数のデータ項目として使用されると,値は
EvmTRUE
または
EvmFALSE
のいずれかになります。
クラスタワイド・イベントは,イベントがユーザ・レベルとカーネルのどちらから発信されたかによって,異なります。
ユーザ・レベルでは,クラスタワイド・イベントは他のイベントと同じようにローカルの EVM デーモンへ発信され,次にデーモンはそのイベントを自分の受信者と,他のアクティブなノードで実行中の EVM デーモンに配信します。 event_id データ項目はローカル・デーモンによって設定され,受信者に配信される前に他のデーモンによって変更されることはありません。 これは,次のようなことを意味します。
全ノードの受信者はそのイベントの同一のコピーを受信する。
発信ノードではないノード上で受信したコピーの event_id データ項目は,これらのノードでローカルに発信されるイベントとは順番が違っていることが多い。
カーネルから発信されるクラスタワイド・イベントは,最初にローカル・デーモンを通すことなく他のノードへ配信されるので,その結果,ローカルの event_id の値を与えられていません。 この場合,各ノードで実行されるデーモンは,event_id が設定されていないことを認識し,自分で値を設定します。 これは,次のようなことを意味します。
クラスタの異なるノードの受信者は,同じカーネルが発信したクラスタワイド・イベントを異なる event_id の値で受信する。
発信ノードではないノード上で受信したコピーの event_id データ項目は,これらのノードでローカルに発信されるイベントと連続している。
カーネルレベル・イベントの発信と受信についての詳細は,
kevm
(7)
EVM は,クラスタ別名を使用してクラスタに接続されている受信者が,クラスタワイド・イベントのコピーを 1 つだけ受信するようにします。
ただし EVM logger は,どのクラスタ・メンバが発信したかに関係なく,フィルタに一致するイベントをすべて受信して記録するため,各ノードでコピーが別々に記録されます。
その結果,格納されたイベントを,クラスタ別名を使用した接続により
evmget
コマンドを使用して取得する場合,イベントを記録した各ノードからイベントのコピーが 1 つづつ返されることになります。
クラスタベース・アプリケーションを開発する場合,どのイベント (存在する場合) をクラスタワイド・イベントに指定する必要があるかを,注意して判断してください。
目的の受信者が,イベントの各インスタンスをどのノードがポストしたかを認識して適切な動作を行うように設計することが特に重要です。
member _id データ項目を標準ライブラリ関数 (clu_get_info()
など) と組み合わせて使用すると,発信とローカル・ノードについての詳細が得られます。
詳細は,
EvmEvent
(5)clu_get_info
(3)14.5.1.6 参照データ項目
参照データ項目は,イベントの詳細表示のために,イベントの説明テキストを検索するときに使用されます。 このデータ項目の値は,イベント名とともにイベント・チャネルの説明スクリプトに渡されて,イベントに関連付けられている説明テキストが識別できるようにします。 説明スクリプトはチャネルごとに異なるため,フィールドのフォーマットはチャネルごとに異なります。 ただし,EVM ログ (evmlog チャネル) に対して格納/取得されるイベントの場合は,参照データ項目には次のフォーマットの文字列を指定します。
cat:catalog_name[:set_number]
catalog_name は,イベントの説明テキストが格納されている I18N カタログの名前です。 説明スクリプトで適切なメッセージを検索できるようにするには,カタログ内の各説明メッセージの先頭に,中カッコで囲まれたイベントの名前がなければなりません。
オプションの set_number は,説明テキストが格納されたカタログのメッセージ・セットの番号です。 セット番号を指定しない場合は,カタログ全体が検索されます。
サードパーティ製品のベンダおよびローカル・アプリケーションの場合は,説明テキストを Tru64 UNIX の説明テキスト・カタログ
evmexp.cat
には追加しないで,別のカタログを提供します。
この項目の値は,通常,テンプレート・ファイルにグローバル・データ項目として設定します。
イベントの説明テキストの作成方法についての詳細は,14.6.2 項を参照してください。
14.5.2 変数データ項目
イベントの変数データ項目は,イベントのインスタンスごとに異なる情報を指定するときに使用します。 たとえば,高温が検出されたときにイベントを発信する場合は,実際の温度を浮動小数点値として変数データ項目に指定することができます。
変数データ項目には,次のプロパティがあります。
名前
型
値
サイズ (ほとんどの型で暗黙に指定される)
I18N メッセージ ID (オプション -- 文字列変数の場合にのみ適用)
変数名は,大文字または小文字の英数字および下線 (_) を任意に組み合わせて指定できます。 名前はわかりやすく指定する必要があります。 ただし,変数名はイベントに含めて送信されるため,名前が長くなるほどイベントの物理的な長さも大きくなります。
変数データ項目は,受信者が直接抽出および使用したり,表示用のフォーマット済みイベントを作成するために,イベント・フォーマットのテキスト文字列と結合することができます。
表 14-3
に,EVM でサポートされる変数の型を示します。
表 14-3: EVM の変数データの型
型識別子 | サイズと型 |
EvmTYPE_BOOLEAN |
8 ビットの整数 |
EvmTYPE_CHAR |
8 ビットの文字 |
EvmTYPE_INT16 |
16 ビットの符号付き整数 |
EvmTYPE_INT32 |
32 ビットの符号付き整数 |
EvmTYPE_INT64 |
64 ビットの符号付き整数 |
EvmTYPE_UINT8 |
8 ビットの符号なし整数 |
EvmTYPE_UINT16 |
16 ビットの符号なし整数 |
EvmTYPE_UINT32 |
32 ビットの符号なし整数 |
EvmTYPE_UINT64 |
64 ビットの符号なし整数 |
EvmTYPE_FLOAT |
32 ビットの浮動小数点値 |
EvmTYPE_DOUBLE |
64 ビットの浮動小数点値 |
EvmTYPE_STRING |
ヌルで終了する文字列 |
EvmTYPE_OPAQUE |
サイズを明示的に指定しなければならないバイナリ・データ |
変数にはイベントのインスタンス固有の情報が含まれるため,通常は発信者が指定します。
ただし,文書化の目的では,変数の名前と型,およびダミーの値をイベントのテンプレートに指定しておくと便利です。
テンプレートについては,14.6.3 項を参照してください。
14.6 イベント・セットの設計
アプリケーションまたはサブシステムを設計する場合は,関連するイベント・セットも設計する必要があります。
EVM イベントは,慎重に設計する必要があります。 イベントは,ヒューマン・スタイル (読みやすいテキスト) とプログラム・スタイル (バイナリ・データ) の 2 種類のインタフェース要件を満たす必要があります。 イベントが発信された後は,テキスト形式またはバイナリ・データ形式のいずれかで表示および処理することができます。
イベントを設計するときは,次の事項を考慮します。
関連するイベント・セットに対して,ファミリ名を決定します (詳細は,14.5.1.1 項を参照)。
監視しているエンティティが関心のある状態変更の一覧を作成し,各イベントの名前を選択します (詳細は,14.6.1 項を参照)。
各イベントの内容を決定します。 すべてのイベントには固有の名前が必要です。 ほとんどの場合,フォーマット文字列と優先度を指定する必要があります。 また,多くの場合,変数も必要です。 各変数について,型および指定できる値を決定します (詳細は,14.5 節を参照)。
文書化のために,各イベントの詳細な説明を記述します。 イベントの意味,発生するタイミング,ユーザまたは責任のある受信者の対応方法,およびイベントの内容 (特に,すべての変数データ項目) の詳細を記述します。 説明テキストは,通常,カタログ・ファイル内に保存され,アクセスして表示することができます (詳細は,14.6.2 項を参照)。
イベントごとに,テンプレートに指定する項目,および発信者が指定する項目を決定します。 イベント名を除いて,発信コードおよびテンプレートの項目はすべてオプションです。 オプション項目が発信コードおよびテンプレートの両方で宣言されている場合は,発信者の宣言が優先されます (テンプレートについての詳細は 14.6.3 項を,一般に発信されるイベント項目についての詳細は 14.5 節を,テンプレートと発信イベントのデータ項目のマージ方法についての詳細は 14.6.3.3 項をそれぞれ参照)。
イベントを多国語対応にするかどうかを決定します。 多国語対応にする場合は,I18N カタログ・ファイルに対して名前を選択し,必要なメッセージ・セットをカタログに設定します (詳細は,14.6.4 項を参照)。
設計者は,EVM イベントは,ほかのプログラムまたはサブシステムが依存するインタフェースであることを認識する必要があります。
このため,設定後は,通常変更しないようにします。
14.6.1 イベントに値する状態変更の決定
イベントの重要性は,アプリケーションごとに異なります。 場合によっては,コードで認識された状態変更が,ほかのコードに通知が必要な重要性を持つかどうかを決定するのが困難なこともあります。
次の現象が発生した場合は,イベントを発信することをお勧めします。
コンポーネントによってシステムが変更された場合。 たとえば,システム管理プログラムが,システムに新しいユーザを追加した場合や,ネットワーク構成を変更した場合。
潜在的に重大なエラーが発生した場合。 たとえば,システム管理プログラムによって主要なシステム・ファイルが存在しないことが検出された場合や,デバイス・ドライバによってディスク障害が検出された場合。
障害が発生する可能性を示す境界値を超えた場合。 たとえば,ファイル・システム管理ソフトウェアでは,ファイル・システムが境界値を超過し,95% 以上使用されていることが検出されたときに,警告イベントが発信される。 ただし,状態が境界値の前後を上下する場合は,このようなイベントが繰り返し発信されないように注意する。 通常は,あらかじめ設定した時間が経過しても同じ状態が続いている場合にだけ,イベントが再発信されるようにする。 この場合,経過期間中に,何度か境界値を下回り回復したとしても影響しない。
ユーザに特権が与えられた場合,またはシステムの操作に影響するアクションが実行された場合。 たとえば,システム管理プログラムによってディスクのマウント/アンマウントが行われた場合,またはシステムがクローズされている場合。
次の現象が発生した場合は,イベントを発信しないでください。
ユーザが制御しているセッションで,あるユーザによってエラーが発生したときに,そのユーザと直接通信できる場合。 たとえば,ユーザがプロンプトに間違って入力した場合は,構成プログラムからイベントを発信しない。
次の基準を満たす「エラー」を処理している場合。 つまり,予期されている通常の動作で,発生の原因がわかっているため,システム管理者の対応が必要ないエラーの場合。
検出された状態が既に通知されているため,再度通知する必要がない場合。
イベントを発信するときは,特定の状態が繰り返し発生する場合などに,短期間に同じイベントを繰り返し発信しないようにします。 場合によっては,指定の期間内に同じ現象が発生した回数を通知するなど,要約イベントを一定間隔で発信することも有効な方法です。
イベント処理が頻繁に発生すると,アプリケーションがメッセージの負荷に対応できなくなる可能性があり,イベントが失われる原因になります。
失われたイベントの処理方法については,14.7.12.10 項を参照してください。
14.6.2 イベントの説明テキストの作成
説明テキストは,すべての EVM イベントに必要です。
説明テキストは,発信時にはイベントに含まれていませんが,カタログ・ファイルに保存されており,イベントの参照データ項目と名前データ項目の内容によって参照されます (14.5.1.6 項を参照)。
sys.unix
イベントの説明テキストは,evmexp.cat
というカタログ・ファイルに物理的に格納されています。
イベントの説明テキストを表示するには,evmshow
の
-x
または
-d
オプションを使用するか,または SysMan イベント・ビューアを使用してイベントの詳細な表示を要求します。
説明には,イベントの名前および意味を記述します。 コンテキスト (一定時間内の発生回数やほかのイベントの存在など) によって意味が異なってくるイベントの場合は,この内容および例をいくつか記述します。 イベントに対してアクションが必要な場合は,そのアクションを記述します。 コンテキストによってアクションが異なってくる場合は,その内容と例を記述します。 イベントに対するユーザのアクションが必要ない場合は,その点を明示的に記述することをお勧めします。
例 14-1
は,システム・イベントの説明テキストの例です。
例 14-1: イベントの説明テキストの例
Example 1: EVENT sys.unix.evm.daemon.event_activity Explanation: This high-priority event is posted by the EVM daemon when it detects a high number of events occurring over several minutes. Action: Use the EVM event viewer or the evmget(1) command to review the event log for the source of the activity. If the log does not show high activity around the time at which this event was posted, it is likely that the events were low priority, and hence were not logged. You can monitor low-priority events by running the evmwatch(1) command with an appropriate filter, or by temporarily reconfiguring the EVM logger to log low-priority events. Note: You can change the parameters that control the posting of this event by modifying the daemon configuration file, /etc/evmdaemon.conf.
各発信イベントには,テンプレートが必要です。 1 つのテンプレートに複数のイベントを割り当てることもできます。 テンプレートには,イベント名およびイベントの定数のデータ項目を定義します。
イベント・テンプレートは,次の 2 つの目的で使用されます。
EVM へのイベントの登録。 登録されていないイベントは発信できません。
イベントのほとんど,またはすべてのインスタンスに対して共通のデータ項目 (メッセージ・カタログ情報など) をイベント・テンプレートに設定することができます。 テンプレートに定数のデータ項目を設定しておくと,これらの情報の更新が容易になり,イベント発信者が発信要求にこれらの情報を繰り返し指定する必要がなくなります。 イベント・テンプレートに設定する項目の決定方法については,14.6.3.1 項を参照してください。
イベント・テンプレートの内容と発信イベントの内容をマージする方法についての説明は,14.6.3.3 項を参照してください。
テンプレートは,集中管理されたデータベース内のファイルに保存されます (14.6.3.4 項を参照)。
テンプレート・ファイルには,任意の数のイベント・テンプレートを含めることができます。
14.6.3.1 イベント・テンプレートに設定する項目の決定
イベント発信者が設定する項目およびテンプレートで設定する項目は,設計時に決定します。 定数データ項目は,通常,発信プログラムでイベントにハードコードするのではなく,イベント・テンプレートに設定します。
イベント・テンプレート方式の主な利点は,アプリケーションのすべてのイベントの定数属性を集中管理できるため,開発サイクル時に容易に変更ができることと,アプリケーションの開発後に属性情報の検索先が一箇所になることです。
原則として,発信アプリケーション・プログラムにハードコードするイベント情報は最小限にし,できるだけ多くの情報をイベント・テンプレートに設定します。 通常,アプリケーションでは次の情報だけを設定します。
イベント名 (必須 -- 3 つ以上のコンポーネントで構成され,対応するテンプレートのイベント名と同じ長さまたはそれ以上でなくてはならない)
変数の値
通常,テンプレートには次の情報を設定します。
イベント名 (必須 -- 2 つ以上のコンポーネントが必要)
優先度
フォーマット・テキスト
I18N メッセージ・カタログ情報 (多国語対応のイベントの場合)
Cluster event フラグ (該当する場合)
変数 (通常はゼロまたは空の文字列に初期化する)
変数データ項目の値は,通常,イベント発信時に発信アプリケーションで設定しますが,テンプレートにも変数を設定しておくと,文書化の点から,テンプレートの重要性が高まります。 テンプレートの変数には,通常,ゼロ (文字列変数の場合は空文字列) を設定します。 テンプレートに,実際の省略時の値 (発信者が変更できる) を設定しておくと便利なこともあります。 この場合は,テンプレート・ファイルにコメントとして記述します。
次のソース・ファイルは,1 つのイベントを含むイベントのテンプレート・ファイルの例です。
# Example event file priority 200 # Default priority ref cat:myapp_exp.cat # Global reference event { name myco.myapp.env.temperature format "Temperature is $temperature" var { name temperature type FLOAT value 0,0 } }
イベントには,必要に応じて任意の数の変数を指定できます。
ただし,不透明な変数 (バイナリ構造) は,テンプレートではサポートされません。
14.6.3.2 イベント・テンプレート名と発信イベントの名前の照合
EVM は,イベントが発信されると,テンプレート・データベースで,発信イベントの名前とイベント名が一致するテンプレートを検索します。 一致する名前が存在しない場合は,イベントを発信したプログラムにエラー・コードを返します。 一致する名前が見つかった場合は,EVM はテンプレートに設定されているデータ項目を,イベントを発信したプログラムで設定された項目と結合します。 この操作によりマージされたイベントが生成されて,受信者に配信されます。 マージ操作についての詳細は,14.6.3.3 項を参照してください。
テンプレート照合プロセスでは,発信イベント名の左端のコンポーネントと,テンプレートのイベント名のすべてのコンポーネントが一致していることのみが検査されます。 EVM では,次の規則に基づいて,データベース内で最も近い一致を検索します。
最も近い一致とは,テンプレート・イベントの名前と発信イベントのコンポーネントを左端から右方向に比較したときに,発信イベントのほとんどのコンポーネントと正確に一致する名前を持つテンプレート・イベントのことである。
発信イベントのコンポーネント数が,最も近いデータベース・エントリのコンポーネント数以上の場合は,一致していると見なされる。 発信イベントのコンポーネント数が少ない場合は,一致しているとは見なされない。
各コンポーネントは,正確に一致しなければならない。
テンプレート名には,2 つ以上のコンポーネントが必要である。 発信イベント名には,3 つ以上のコンポーネントが必要である。
テンプレートは,アプリケーションが発信するイベントごとに用意してください。 こうしておくと,イベント固有の情報を,テンプレートに格納することによって集中管理することができます。 しかし,最適一致方式の利点は,発信するときにイベント名にさまざまなインスタンス情報を追加して拡張できることです。 たとえば,デバイス名や温度の値を追加コンポーネントとして追加できます。 インスタンス・コンポーネントを追加した場合は,イベントのフィルタおよびソートが簡単になります。 イベント名の拡張方法の例については,14.5.1.1.1 項を参照してください。
表 14-4
は,イベント・テンプレートと発信イベント間のイベント名の照合の例です。
表 14-4: 名前照合の例
発信イベント名 | テンプレートのイベント名 | 一致の状態 |
myco.myprod.env |
myco.myprod.env |
一致 |
myco.myprod.env.temp.high.70 |
myco.myprod.env.temp |
一致 |
myco.myotherprod |
myco.myotherprod.start |
不一致。 発信イベントのコンポーネント数が足りない。 |
14.6.3.3 テンプレートと発信イベントのデータ項目のマージ
EVM デーモンによって発信イベントの有効性が確認されると,発信イベントのデータ項目とテンプレートのデータ項目がマージされ,イベントを受信しているクライアントにマージされたイベントが配信されます。 マージ・プロセスでは,テンプレートで設定するテキストおよびデータ項目と,発信者で設定するテキストとデータ項目の選択は,イベント設計者が大部分を決定することができます。
図 14-2
は,イベントのマージの概念図です。
図 14-2: 発信イベントとテンプレートのマージ
テンプレートおよび発信イベントの両方に同じデータ項目が設定されている場合は,マージされたイベントでは発信イベントの値が使用されます。
マージ・プロセスでは,発信イベントおよびテンプレートのデータ項目が結合された,バイナリ形式のイベント構造が生成されます。
マージされたイベントは,フォーマットされたメッセージとしてではなく,バイナリ形式で受信者に配信されるため,受信者は,EVM API 関数を使用して,イベントを表示できるようにフォーマットしたり,イベントから情報を抽出する必要があります。
API 関数については,14.7 節を参照してください。
14.6.3.4 テンプレート・ファイルのインストール -- 位置,命名,所有権,および許可の要件
通常,イベントのテンプレート・ファイルは,製品またはアプリケーションをインストールするときにインストールされます。
システム・テンプレートは,/usr/share/evm/templates
の下のサブディレクトリに格納されます。
サードパーティ製品およびローカル・アプリケーションのテンプレートは,ローカル・テンプレート・ディレクトリ
/var/evm/adm/templates
に格納されます。
EVM デーモンが別のテンプレートの位置を指定できるように,システム・テンプレート・ディレクトリおよびローカル・ディレクトリ間には,リンクが作成されます。
製品またはローカル・アプリケーションにテンプレートを追加するには,アプリケーションをインストールするときに,ローカル・テンプレート・ディレクトリの下に適切な名前のサブディレクトリを作成し,そのディレクトリにテンプレートをインストールする必要があります。 EVM のテンプレート検索ポリシでは,シンボリック・リンクを介して検索されるため,アプリケーションと密接に関連するディレクトリにもテンプレートをインストールし,そのディレクトリとローカル・ディレクトリの間にリンクを作成して接続することもできます。
テンプレート・ファイルの接尾語は,.evt
でなければなりません。
また,所有者は
root
または
bin
にし,0600,0400,0640,または 0440 のいずれかのアクセス許可が必要です。
新しいディレクトリにも,適切な許可を割り当てます。
ファイルをインストールしたら,root として
evmreload -d
コマンドを実行し,EVM で新しいテンプレートを認識できるようにします。
次に,エラーがないかどうかを確認します。
詳細は,
evmreload
(8)14.6.3.5 イベント・テンプレートの登録の確認
テンプレートが登録されたかどうかを判断するには,-i
オプションを指定して
evmwatch
を使用します。
たとえば,次のコマンドを実行すると,myapp
アプリケーションに登録されているすべてのイベント・テンプレートの名前の一覧が表示されます。
evmwatch -i -f "[name myco.myprod.myapp]" | evmshow -t "@name"
テンプレートの詳細を表示するには,evmshow
の
-d
オプションを使用します。
evmwatch
では,アクセス権限のないイベントのテンプレートは返されません。
このため,テンプレートを表示する場合は,root としてログインしなければならないことがあります。
14.6.4 イベント・テキストの翻訳の設定 (I18N)
イベントのフォーマット・データ項目およびイベントに含まれる文字列変数の値を表示するときに,別の言語に変換できるようにするには,イベントを多国語対応 (I18N) にする必要があります。 さまざまな国で使用される製品を開発している場合は,任意のまたはすべての項目を変換できるようにします。
格納されている同一のイベントを表示する場合,ユーザごとに異なる言語が使用される可能性があります。 このため,言語の翻訳は,イベントの発信時ではなく,イベントが表示用のフォーマットに変換されるときに同時に行う必要があります。 使用されるすべての言語のテキストをイベントに設定することは実際的ではないため,イベントがフォーマットされるときに,関連するメッセージ・カタログが使用できるようにしなければなりません。 製品の開発者は,メッセージ・カタログを提供し,製品と一緒にインストールされるようにメッセージ・カタログを組み込む必要があります。 カタログが使用できない場合のために,多国語対応のイベントに対して省略時の母国語文字列を含めることができます。
次のデータ項目は,イベントの多国語対応化をサポートしています。
I18N メッセージ・カタログ名
I18N メッセージ・セット識別子 (オプション)
フォーマット・データ項目の I18N メッセージ識別子
多国語対応の文字列変数ごとの I18N メッセージ識別子
この一覧にある任意のまたはすべての項目に対する省略時の母国語文字列
イベントのメッセージ識別子は,すべて同じメッセージ・カタログに関連付けられているため,すべて同じメッセージ・セット (省略時は 1) に属していなければなりません。
イベントのフォーマット文字列のカタログ ID,セット ID,およびメッセージ ID は,通常は変更されないため,すべてイベント・テンプレートに設定してください。 イベントに文字列型の変数が含まれる場合,その変数はデバイス名やアプリケーション名などの項目を参照していることが多いため,表示する言語にかかわらず,通常は翻訳する必要はありません。 このため,ほとんどの場合,メッセージ ID を設定する必要はありません。 ただし,文字列変数の値を翻訳しなければならない稀な場合は,発信者はメッセージ ID を設定する必要があります。
表 14-5
は,イベント例に対する多国語対応の値の例です。
表 14-5: 多国語対応のイベントに対するデータ項目値の例
イベントのデータ項目 | 値 | メッセージ ID |
名前 | acme.prod.env.temp |
n/a |
メッセージ・カタログ | acme_prod.cat |
n/a |
フォーマット文字列 | Temperature of sensor $sensor is
$temperature |
541 |
文字列変数 "sensor" | S27 |
n/a |
文字列変数 "temperature" | high |
542 |
temperature.cat
の英語版とフランス語版は,次のようになります。
英語版
541:Temperature of sensor $sensor is $temperature
542:high
543:low
フランス語版
541:La temperature du senseur $sensor est $temperature
542:haute
543:basse
ビューアでイベントを表示する場合は,ビューアによってフォーマット関数が呼び出され,ユーザのロケール設定に応じて,フォーマット関数から次のいずれかの文字列が返されます。 ただし,適切なカタログ・ファイルを見つけることができ,指定されたメッセージがファイルに格納されている必要があります。
"Temperature at sensor S27 is high" "La temperature du senseur S27 est haute"
フォーマット関数でカタログからイベントが解釈できない場合は,イベントに設定されている値が使用され,ユーザのロケールにかかわらず,次のメッセージが返されます。
"Temperature at sensor S27 is high"
イベント・ファイルが別のシステムに渡されて分析される場合は,関連付けられているカタログ・ファイルが使用できないことがあります。 上の例のように,イベントに省略時の値が含まれている場合は,母国語で表示することができます。 イベントに省略時の値が含まれていない場合は,フォーマットされた文字列を使用して,イベント名およびすべての変数のダンプを表示することができます。 たとえば,次のように表示されます。
Event "myco.myprod.env.temp": $sensor = "S27" $temperature = "high"
I18N についての詳細は,『国際化ソフトウェア・プログラミング・ガイド』を参照してください。
14.7 EVM プログラミング・インタフェース
EVM イベントは不透明なデータ構造であり,EVM のアプリケーション・プログラミング・インタフェース (API) 関数によるアクセスと操作が可能です。
Tru64 UNIX システム上で実行する Java プログラムをサポートするために,JNI (Java Native Interface) パッケージがあります。 Java インタフェースの詳細は,Web ブラウザを使用して次のファイルを参照してください。
file:/usr/share/doclib/evm/java_api/help-doc.html
以降の各項では,EVM イベントに対して通常実行されるいくつかの操作に関するプログラミング情報について説明するとともに例を示します。
14.7.1 EVM ヘッダ・ファイル
EVM 関数を使用するプログラムには,次のヘッダ・ファイルをインクルードします。
#include <evm/evm.h>
14.7.2 EVM API ライブラリ
EVM API 関数を使用するプログラムでは,シェアード・ライブラリ
libevm.so
またはスタティック・ライブラリ
libevm.a
に対してリンクを作成する必要があります。
シェアード・ライブラリはルート・パーティション・ディレクトリ
/shlib
に格納されています。
このため,システムがシングルユーザ・モードで稼働しているときに,動作している必要があるプログラムから使用できます。
ただし,EVM デーモンは,実行レベルが 2 になったときに起動されるため,シングルユーザ・モードのときにデーモンに接続しようとすると失敗します。
/usr/shlib
から
/shlib
内のシェアード・ライブラリに対するシンボリック・リンクが作成されているため,省略時のライブラリ検索パスを使用して,リンク先のプログラムがライブラリにアクセスすることができます。
14.7.3 戻り状態コード
EVM 関数から返された状態コードは,ヘッダ・ファイル
evm/evm.h
に列挙されます。
EVM 関数から共通に返される値は,次のとおりです。
EvmERROR_NONE
-- 操作が正常に完了した。
EvmERROR_INVALID_ARGUMENT
-- 関数に渡された引数の 1 つが無効だった。
EvmERROR_INVALID_VALUE
-- 構造内に無効な値があった。
EvmERROR_NO_MEMORY
-- ヒープ・メモリを取得できなかったため,操作が失敗した。
EvmERROR_NOT_PRESENT
-- 要求された項目がイベントに存在しない。
状態コードの詳細なリストは,evm/evm.h
ファイルを参照してください。
14.7.4 シグナルの処理
EVM API は,通常の処理ではシグナルは使用せず,アプリケーション・プログラムでシグナルが使用されるときにも通常は干渉しません。 ただし,Tru64 UNIX システムの省略時のアクションでは,データを読み込むプロセスが存在しないときに,ローカル接続に対して書き込もうとした場合,サイレントに終了します。 このため,EVM デーモンが接続アクティビティの前または途中で終了した場合は,クライアント・プロセスが何も記録しないで終了する恐れがあります。
この状態が発生するのを回避するために,EvmConnCreate()
関数は,SIGPIPE のハンドラが呼び出し側によって設定されているかどうかをチェックし,設定されていない場合は省略時のハンドラをインストールします。
シグナルが発生してもハンドラは何のアクションもとりませんが,ハンドラが存在するためにクライアントは終了しません。
EVM ハンドラは,EvmConnCreate()
呼び出しの前または後にプログラムで独自のハンドラを設定することにより,無効にできます。
プログラムで省略時のアクションが必要な場合は,EvmConnCreate()
を呼び出してから SIG_DFL にアクションを設定します。
詳細は,
signal
(2)14.7.5 マルチスレッド・プログラムでの EVM
EVM API 関数は,すべてスレッド・セーフです。 このため,内部静的記憶域を使用しなければならない場合は,ロックを使用して,記憶域に対して各スレッドから同時にアクセスされないようにします。 それでも,マルチスレッド・プログラムで EVM API 呼び出しを使用する場合は,同期エラーを回避するために一定の予防策が必要です。
可能であれば,API 関数から返されたエンティティの使用を,エンティティが設定されているスレッド内に制限します。 次のエンティティで制限することができます。
エンティティ | 型 | エンティティを返す関数 |
接続コンテキスト | EvmConnection_t |
EvmConnCreate() |
イベント | EvmEvent_t |
|
データ項目 | EvmItemValue_t |
EvmItemGet() |
データ項目リスト | EvmItemList_t |
EvmItemListGet() |
変数 | EvmVarValue_t |
EvmVarGet() |
変数リスト | EvmVarList_t |
EvmVarListGet() |
イベント・フィルタ | EvmFilter_t |
EvmFilterCreate() |
接続 fd | EvmFd_t |
EvmConnFdGet() |
これらのエンティティを複数のスレッドから参照する場合は,ロックを使用して,同時アクセスまたは同時更新が行われないようにする必要があります。
これらの規則に従わない場合は,予期しないエラーが発生する可能性が高くなります。
14.7.6 EVM イベントの再割り当てと複製
EVM イベントの作成,受信,または読み取りが行われた後で,そのイベントを再度割り当てる必要がある場合は,イベントがメモリに保存される方法を理解しておくと便利です。
EvmEvent_t
型には,制御情報を保持する短いハンドル構造体へのポインタと,イベント本体へのポインタが定義されています。
EvmEventCreate()
または関連する関数を使用して新しいイベントを作成すると,その関数によってハンドルおよびイベント本体に対してヒープ・メモリがそれぞれ割り当てられます。
次に,本体のアドレスがハンドルに格納され,ハンドルのアドレスが関数の
EvmEvent_t
出力引数として返されます。
イベントを参照する場合は,返されたポインタを使用しなければなりません。
変数を追加するなど,イベントを変更すると,多くの場合,イベント本体に対して使用されていた領域が解放されて,別の位置に再度割り当てられます。 このとき,ハンドルに格納されたアドレスが自動的に更新され,新しい位置が反映されます。 つまり,再割り当ては,プログラムに対して完全に透過的に行われます。 ハンドルの位置は,イベントの存在期間内は変更されません。
イベントを変数間で転送する場合は,簡単な C 言語の代入文を
EvmEvent_t
型の変数間で使用します。
保持されている値は,一定の位置 (イベントのハンドル) へのポインタだけなので,必要に応じて両方の変数からイベントを参照できます。
ただし,後で
EvmEventDestroy()
を使用してイベントを破壊する場合は,両方の参照を破棄しなければなりません。
イベントの再割り当てでは,イベント本体はコピーされず,イベントのハンドルへの参照だけがコピーされることに注意してください。
完全に独立したイベントのコピーを作成する必要がある場合には,EvmEventDup()
関数呼び出しを使用します。
14.7.7 コールバック関数
EVM の発信および受信クライアントは,EvmConnCreate()
関数呼び出しを使用して EVM デーモンに接続します。
このとき,EvmRESPONSE_IGNORE
,EvmRESPONSE_WAIT
,EvmRESPONSE_CALLBACK
の 3 つの応答モードから 1 つを指定しなければなりません。
これらのモードについては,
EvmConnCreate
(3)
受信クライアントの場合は,応答モードとして
EvmRESPONSE_CALLBACK
を指定する必要があります。
着信イベントは,EvmConnCreate()
の 4 番目の引数に指定したコールバック関数によって受信クライアントに渡されます。
受信クライアントからコールバック関数を使用する場合の例については,14.7.12.6 項を参照してください。
コールバック関数を使用する場合は,シグナル・ハンドラと異なり,非同期的に呼び出されないことに注意してください。
プログラムで
EvmConnWait()
,select()
,または関連する関数を使用して入力アクティビティの接続を確認してから,EvmConnDispatch()
を呼び出してアクティビティを処理する必要があります。
EvmConnDispatch()
によって,接続からの着信メッセージが読み込まれ,必要に応じてコールバック関数が呼び出されます。
コールバック関数が呼び出されるタイミングについては,
EvmCallback
(5)
ほかの関数と同様に,コールバック関数に渡される引数は,プログラム・スタックに渡され,関数の有効範囲内でのみ使用できます。 このため,コールバックから戻った後で使用するために値を保存しておきたい場合は,戻る前に値をグローバル・メモリ空間にコピーする必要があります。
コールバックによって着信イベントの存在が通知されたときに,イベントをコールバック内で処理および破壊するのではなく,保存したい場合は,グローバル・アクセスできる
EvmEvent_t
型の変数を宣言して,着信イベントを割り当てます。
次に例を示します。
/* In global declarations */ EvmEvent_t SavedEvent; ... /* In your callback function */ SavedEvent = cbdata->event;
イベントを割り当てたときは,イベント本体ではなくイベントへの参照だけがコピーされるため,コールバック関数でイベントを破壊してはなりません。 イベントの処理が終了したら,後でイベントを破壊する必要があります。 破壊しない場合,メモリ・リークが発生することがあります。
イベントの割り当てについては,14.7.6 項を参照してください。
14.7.8 接続ポリシの選択
プログラムが発信クライアントの場合,EVM デーモンに接続するポリシを選択する必要があります。 次のいずれかを選択してください。
プログラムの起動時に接続を確立し,プログラムが終了するまで維持する (永続的な接続)。
イベントの発信が必要になったときに毎回接続を確立し,終わるとすぐに切断する (一時的な接続)。
処理中に EVM 接続を確立する場合の CPU 負荷は無視できません。 セットアップと認証のプロトコルで,ファイル入出力の他にメッセージのトランザクションが複数必要になるからです。 原則的には,通常のプログラム動作中に何度もイベントの発信があると予測される場合には,永続的な接続を行ってください。 このオプションを選択した場合,プログラム・コードでは,EVM デーモンが終了した場合の予期しない切断を考慮しなければなりません。 切断の処理については,14.7.9 項 を参照してください。
イベントをあまり発信しない場合 (たとえば,予期しないエラーが起きたときに限られる場合) は,一時的な接続を行ってください。
一時的な接続では,複数のイベントが発信されるとセットアップ時間の負荷が大きくなりますが,永続的な接続に必要なシステム資源の消費と,予期しない切断に対するプログラム・コードでの対処が不要になります。
一時的な接続でローカル・デーモンにイベントを発信するための最も簡単な方法は,EvmEventPost()
または
EvmEventPostVa()
の接続引数として NULL を渡すことです。
永続的な接続は必要としないが,特定の状況で短期間に何度もイベントを発信することが予測される場合は,個別に接続してイベントを連続的に発信するよりも,一時的な接続を作成して,動作が完了した時点でそれを破棄すると良いでしょう。
受信クライアントは,イベントを確実に受け取るために永続的な接続を維持しなければなりません。
14.7.9 切断の処理
プログラムが
受信クライアント
の場合は,EVM デーモンからの切断を適切に処理することが特に重要です。
通常の操作では切断は発生しませんが,システムをテストしている場合や障害が検出された場合は,切断が発生することがあります。
EVM デーモンが中断されると,通常数秒のうちに Essential Services Monitor デーモンがこれを自動的に再開させます。
詳細は,
esmd
(8)
接続を処理する関数からの戻りコードは,必ず検査する必要がありますが,受信クライアントではこれが特に重要です。 受信クライアントは,接続上でのアクティビティを待機していることが多いためです。
切断が発生した場合,プログラムは
select()
または
EvmConnWait()
呼び出しを中断し,後続の
EvmConnCheck()
と
EvmConnDispatch()
への呼び出しで障害状態のコードが返されます。
このとき,select()
または
EvmConnWait()
呼び出しにすぐに戻らないでください。
CPU にバインドされたループが発生します。
代わりに,状態コードが接続エラーを示しているかどうかを判断し,接続エラーの場合は
EvmConnDestroy()
を使用して接続を破壊してから,再接続を試みます。
再接続の最初の試行に失敗した場合は,一定の間隔が経過してから接続が再試行されるように設定して,接続が再度確立されるまで定期的に再試行を繰り返します。
どのような障害でも,通常デーモンはその後自動的に再開されるため,再試行の間隔は,最初の 60 秒は 1 秒に 1 回,その後は接続が回復するまで 5 秒おきにすることをお勧めします。
接続関数から返されるエラー・コードは,切断以外の状態を示していることもあります。
特に,シグナルの結果として,プログラムが
EvmConnWait()
を中断することがあります。
この場合は,EvmConnWait()
呼び出しにすぐに戻ってください。
プログラムが発信クライアントの場合,切断を処理しなければならないのは,通常は永続的な接続を行っている場合だけです (14.7.8 項
を参照)。
EvmEventPost()
や
EvmEventPostVa()
からのリターン状態をチェックし,必要に応じて再度接続を確立し,発信動作をやり直します。
14.7.10 失われたイベント
イベントの動きが活発なシステムでは,発信されたイベントを多く受信するクライアントが,イベントの一部を受信できなくなることがあります。 クライアントが長時間かけてイベントを処理する場合 (たとえば,各イベントをディスクに書き込まなければならないなど) では,起こりやすくなります。 このようなクライアントに EVM logger があります。 これは,イベントを失ったときにそれを認識し,特別な "missed events" を記録することで,その失敗を通知します。 アプリケーションがイベントを失うおそれがある場合は,その危険が最小になるようにシステムを構成し,プログラムが適切に対処するようにしてください。
EVM デーモンから,受信クライアントにイベントを送るときに,固定サイズの通信 (送信および受信) バッファによる接続で行います。
クライアントが適切な時間内に受信イベントを処理することができず,イベントの負荷が高い場合,バッファが満杯になり,デーモンはその後イベントを送信できなくなります。
省略時の受信バッファ・サイズは,sysconfig パラメータ
sb_max
で定義されたシステムワイド・ソケット・バッファの最大値に設定されています。
送信バッファのサイズは,ソケット・バッファに対するシステムの省略時の値,32,767 に設定されています。
EVM デーモンは多くのシステム・コンポーネントとアプリケーションに対して重要なリソースなので,クライアントがバッファのクリアを待っている間にブロックすることはできません。 その結果,バッファが満杯のために接続バッファに書き込めない場合,デーモンはその接続にブロックされたというマークを付け,他の動作を続けます。 その後にクライアントが入力を読み,バッファに空き領域がある場合,EVM デーモンは失敗した書き込みを完了し,クライアントはイベントを受信します。 ただし,その間に他のイベントが到着し,ブロックされた受信者に送信する必要があっても,デーモンはそれを送信しません。 その代わりに,失った回数をカウントし,接続のブロックが解除された時点でその数を受信者に通知します。 受信者は適切な対処が必要ですが,どのイベントを失ったかを知る方法はありません。
省略時の受信バッファ・サイズを大きくした結果,イベントが失われる可能性は旧バージョンよりも低くなりました。 しかし極端な状況では受信イベントを失う危険性はまだあります。 このようなことが起こる可能性は,いくつかの要因によって決まります。
システムの速度と負荷
受信対象イベント
イベントが発信される頻度
接続の入力バッファ・サイズ
発信されるイベントのサイズ
着信イベントを失うリスクを最小限に抑えるには,着信イベントをできるだけ素早く,かつ効率的に処理できるように,また,イベントを失ったことが通知されたときには適切な対処を行うように,アプリケーションを設計します。 失ったイベントを処理するプログラムの例については,14.7.12.10 項 を参照してください。
アプリケーションがイベントを続けて失う場合は,システム・パラメータを変更して受信バッファ・サイズを大きくすることができます。 受信バッファ・サイズは,省略時のシステム・ソケット・バッファの最大サイズに設定されています。 このパラメータの現在のサイズを調べるには,次のコマンドを入力します。
sysconfig -q socket sb_max
このパラメータの実行時の値を変更して,その値が次のリブートまで有効になるようにするには,次のコマンドを入力します。
sysconfig -r socket sb_max=new_value
この変更は,新しい EVM 接続にのみ影響します。
変更を持続的にするには,sysconfigdb
または
dxkerneltuner
を使用して変更します。
詳細については,
sysconfigdb
(8)dxkerneltuner
(8)14.7.11 イベント・フィルタの使用
イベント・フィルタは,ユーザが関心を持つイベント・セットを識別するときに使用します。 イベント・フィルタを設定すると,フィルタ・エバリュエータに対して,対象となるイベントを定義する文字列が渡されます。 次に,一連のイベントが渡されて,フィルタを通過できるかどうかを示す論理値が各イベントに返されます。
EVM の受信クライアント・プログラムでは,フィルタは受信対象のイベントを指定するときに使用されます。
また,受信したイベントに対するアクションを決定するときにも使用されます。
返されるイベントを制限するために,コマンド行ユーティリティで起動オプションとして使用することもできます。
コマンド行ユーティリティでフィルタを使用する方法については,『システム管理ガイド』を参照してください。
フィルタの構文についての詳細は,
EvmFilter
(5)
フィルタの使用方法についての詳細は,14.7.12.8 項を参照してください。
14.7.12 EVM プログラミング操作の例
以降の各項では,次の操作の例を示します。
簡単なイベント操作の実行 (14.7.12.1 項)
可変長の引数リストの使用 (14.7.12.2 項)
変数の追加と取得 (14.7.12.3 項)
イベントの発信 (14.7.12.4 項)
イベントの読み取りと書き込み (14.7.12.5 項)
イベント通知の受信 (14.7.12.6 項)
複数の入出力ソースの処理 (14.7.12.7 項)
フィルタ・エバリュエータの使用 (14.7.12.8 項)
イベント名の照合 (14.7.12.9 項)
失われたイベントの処理 (14.7.12.10 項)
すべての EVM クライアントは,標準のデータ項目および変数で構成される不透明なバイナリ構造である EVM イベントを処理できる必要があります。 例 14-2 は,イベントを作成して,そのイベントに項目を追加し,次にそのイベントから項目を取得する場合の例です。
この例では,次の関数について説明します。
EvmEventCreate
-- 空のイベントを作成する
(詳細は,
EvmEventCreate
(3)
EvmEventDestroy
-- 以前に作成されたイベントを破壊して,メモリを解放する。
この関数は,イベントを解放する必要がある場合に使用する。
イベントの参照は,ヒープに割り当てられている構造体をポイントしているが,その構造体にはほかの構造体への参照が含まれるため,イベント参照に直接
free()
を使用するとメモリの損失が発生する
(詳細は,
EvmEventDestroy
(3)
EvmItemSet
-- イベントのデータ項目に値を設定する。
設定する項目と変数は,EvmEventCreateVa
と同じ (詳細は
EvmItemSet
(3)
EvmItemGet
-- 指定されたイベント・データ項目の値を返す (詳細は
EvmItemGet
(3)
EvmItemRelease
--
EvmItemGet
() を使用して,イベントの指定されたデータ項目を取得したときに割り当てられたメモリを解放する
(詳細は,
EvmItemRelease
(3)
#include <stdio.h> #include <evm/evm.h> main() { EvmEvent_t event; EvmItemValue_t itemval; EvmStatus_t status; EvmEventCreate(&event); [1] EvmItemSet(event,EvmITEM_NAME,"myco.examples.app.started"); [2] EvmItemSet(event,EvmITEM_PRIORITY,200); status = EvmItemGet(event,EvmITEM_NAME,&itemval); [3] if (status == EvmERROR_NONE) { fprintf(stdout,"Event name: %s\n",itemval.NAME); EvmItemRelease(EvmITEM_NAME,itemval); } EvmEventDestroy(event); [4] }
EvmEventCreate()
を使用して空のイベントを作成します。
この関数を使用する場合は,イベント・ハンドルへのポインタを指定して,標準データ項目が設定されていないイベントを受信します。
イベントは空ですが,メモリは使用するので,後で
EvmEventDestroy()
を使用して領域を解放する必要があります。
[例に戻る]
標準データ項目をイベントに追加するには,EvmItemSet()
を使用します。
ただし,ほとんどの場合,プログラムで追加する項目はイベントの名前だけです。
その他の標準データ項目は,イベントが発信されたときに自動的に追加されます。
または,イベント・テンプレートに設定してください。
設定可能な項目の一覧については,
EvmItemSet
(3)
イベントの項目を取得するには,EvmItemGet()
を使用します。
項目の値は,イベントから
EvmItemValue_t
構造体を介して参照される記憶域にコピーされるため,使い終わったら
EvmItemRelease()
を使用してその記憶域を解放する必要があります。
項目を取得しても,その項目はイベントからは削除されません。
また,コピーを受け取るため,必要なコピー数を取得できます。
このコード例では,イベントの名前 (既に追加したもの) を取得し,その値をプリントしてから,記憶域を解放します。 イベント内に存在しない項目を要求していることもあるので,取得操作からの戻り状態は必ず確認します。 [例に戻る]
イベントの処理が終了したら,イベントによって使用されていた記憶域を解放します。 [例に戻る]
varargs (可変長引数リスト) 版の作成関数を使用してイベントの作成および項目の追加を 1 つのステップで行うと,コードのサイズを削減して,効率を向上させることができます。 また,varargs 版の項目設定関数を使用すると,既存のイベントに対して効率的に項目を追加することができます。
例 14-3 では,次の関数について説明します。
EvmEventCreateVa
-- 1 回の呼び出しでイベントを作成し,項目の名前と値を設定する (詳細は
EvmEventCreateVa
(3)
EvmItemSetVa
-- イベントのデータ項目の値を設定する。
設定する項目と変数のリストは,EvmEventCreateVa
と同じ (詳細は
EvmItemSetVa
(3)
#include <stdio.h> #include <evm/evm.h> main() { EvmEvent_t event; EvmEventCreateVa(&event, [1] EvmITEM_NAME,"myco.examples.app.started", EvmITEM_PRIORITY,200, EvmITEM_NONE); EvmItemSetVa(event, EvmITEM_NAME,"myco.examples.app.finished", [2] EvmITEM_PRIORITY,100, EvmITEM_NONE); EvmItemSetVa(event, EvmITEM_VAR_UINT16,"exit_code",17, [3] EvmITEM_VAR_STRING,"progname","my_app", EvmITEM_NONE); EvmEventDump(event,stdout); [4] EvmEventDestroy(event); [5] }
EvmEventCreateVa()
に指定する各項目には,識別子と値が必要です。
引数リストの最後には,EvmITEM_NONE
識別子を付けます。
[例に戻る]
varags 版の
EvmItemSet()
には,EvmEventCreateVa()
と同じ形式の引数リストを使用します。
この例では,イベントに既に設定されている項目を追加しているため,実際には前の値が新しい値に置き換わるだけです。
[例に戻る]
変数データ項目を varargs リストに入れることは,項目識別子
EvmITEM_VAR_X
xx
を用いて簡単に実行できます。
ここで
X
xx
は変数の型です。
このようにして変数を含める場合,変数を記述するために,識別子の後に正しい数の引数を続けて指定することが重要です。
2 つの引数を必ず付加しなければなりません。
これは,変数名を含む文字列と値引数です。
値引数の型は変数の型に応じて変わります。
この例では,最初の変数には文字列が必要で,2 番目の変数には整数が必要です。
変数の型によっては,さらに変数が必要になることがあります。
詳細は
EvmItemSet
(3)
EvmEventDump()
を呼び出すと,イベントがフォーマットされて標準出力に表示されるため,データ項目と変数が期待どおりに追加されたことを確認できます。
[例に戻る]
イベントの処理が終了したら,これが使用していた記憶域を解放します。 [例に戻る]
上記の例では,変数項目は
EvmItemSetVa()
を用いて varargs リストに入れることでイベントに追加されています。
変数の値は,引数として項目識別子を取る varargs 関数のいずれかを用いて追加または変更できます。
例 14-4 では,既存のイベントに変数データ項目を追加するもうひとつの方法を示し,また,変数の値を取得する方法も示します。 EVM ライブラリには,変数について記述するデータ構造体を使用する基本的な get および set 関数と,構造体の処理をカプセル化してプログラミングを簡単にする便利な関数のセットが含まれています。 この例では,両方の型の関数の使い方を示します。
この例では,次の関数について説明します。
EvmVarSet
-- 指定された変数データ項目の値をイベントに設定する。
この関数は,変数の追加および既存の変数の値の変更に使用する (詳細は,EvmVarSet
(3) を参照)。
EvmVarGet
-- 指定された変数構造体内の指定されたイベント変数の詳細情報を返す。
呼び出し側は,EvmVarRelease
() を呼び出して,変数が使用したメモリを解放する必要がある
(詳細は,
EvmVarGet
(3)
EvmVarRelease
--
EvmVarGet
() を使用して,指定された変数をイベントから取得したときに割り当てられたメモリを解放する。
指定された変数構造を解放するのではなく,構造が参照するヒープ記憶域だけを解放する
(詳細は,
EvmVarRelease
(3)
#include <stdio.h> #include <evm/evm.h> void main() { EvmEvent_t event; EvmStatus_t status; EvmVarValue_t varval_1, varval_2; [1] EvmVarStruct_t varinfo; EvmString_t progname; EvmUint16_t exit_code; EvmEventCreateVa(&event, EvmITEM_NAME,"myco.examples.app.finished", EvmITEM_NONE); /* * Set and retrieve some values using basic set/get functions: */ varval_1.STRING = "my_app"; varval_2.UINT16 = 17; EvmVarSet(event,"progname",EvmTYPE_STRING,varval_1,0,0); [2] EvmVarSet(event,"exit_code",EvmTYPE_UINT16,varval_2,0,0); status = EvmVarGet(event,"progname",&varinfo); [3] if (status == EvmERROR_NONE) { fprintf(stdout,"Program name: %s\n",varinfo.value.STRING); EvmVarRelease(&varinfo); } status = EvmVarGet(event,"exit_code",&varinfo); if (status == EvmERROR_NONE) { fprintf(stdout,"Exit code: %d\n",varinfo.value.UINT16); EvmVarRelease(&varinfo); } /* * Set and retrieve the same values using convenience functions: */ EvmVarSetString(event,"progname","my_app"); [4] EvmVarSetUint16(event,"exit_code",17); status = EvmVarGetString(event,"progname",&progname,NULL); [5] if (status == EvmERROR_NONE) fprintf(stdout,"Program name: %s\n",progname); free(progname); [6] status = EvmVarGetUint16(event,"exit_code",&exit_code); if (status == EvmERROR_NONE) fprintf(stdout,"Exit code: %d\n",exit_code); EvmEventDestroy(event); [7] }
プリミティブ関数を使用してイベントに変数を追加するには,まず
EvmVarValue_t
型の共用体に値を設定します。
共用体のメンバの名前は,EVM 変数型の名前と同じです。
[例に戻る]
EvmVarSet()
を使用して,イベントに変数を追加します。
変数にはわかりやすい名前を付けます。
最後の 2 つの引数は,不透明な変数を追加するか,または文字列変数に I18N メッセージを設定したとき以外は,0 に設定されます。
[例に戻る]
変数の値を取得するには,変数の名前を
EvmVarGet()
に渡します。
EvmVarGet()
は,値を
EvmVarStruct_t
構造体にコピーします。
この構造体には,変数の名前,型,およびサイズも格納されているので,汎用コードを作成して,任意の型の変数を処理することができます。
変数を取得しても変数はイベントから削除されないので,何回でも変数を取得できます。
返された情報によってヒープ・メモリの空間が使用されるので,値を使い終わったら,EvmVarRelease()
を使用してクリーンアップする必要があります。
[例に戻る]
EvmVarSetString()
および
EvmVarSetUint16()
関数は,EvmVarSetXxx()
ファミリの他の関数とともに,EvmVarSet()
関数のシンプルな代用品として使用できます。
これらは必要な引数が少なく,値の構造体を設定する必要もありません。
文字列変数に I18N メッセージ ID を指定する場合は,EvmVarSetStringI18N()
関数を使用します。
[例に戻る]
EvmVarGetString()
および
EvmVarGetUint16()
関数は,EvmVarGetXxx()
ファミリの他の関数とともに,EvmVarGet()
関数のシンプルな代用品として使用できます。
これらは必要な引数が少なく,変数情報の構造体をセットアップして
EvmVarRelease()
を呼び出す取得操作に従う必要もありません。
[例に戻る]
簡易関数を用いて文字列または不透明な変数を取得する場合,この関数は値をヒープ領域に割り当て,そのヒープへのポインタを返します。
この値を使い終えたときは,free()
を用いてヒープ領域を解放しなければなりません。
[例に戻る]
イベントの処理が終了したら,イベントによって使用されていた記憶域を解放します。 [例に戻る]
イベントを作成したら,多くの場合,発信します。 イベントを発信すると,EVM デーモンによって受信者に配信されます。 イベントを発信するには,デーモンに対して発信接続を作成しておく必要があります。
例 14-5 は,接続を作成し,イベントを発信して,接続を切断する方法の例です。
この例では,次の関数について説明します。
EvmConnCreate
-- アプリケーション・プログラムと EVM 間の接続を確立し,入出力アクティビティの処理方法を定義する。
発信,リッスン (受信),またはサービスの各接続に対して,別個の接続を確立する
(詳細は,
EvmConnection
(5)EvmConnCreate
(3)
EvmEventPost
-- EVM にイベントを発信する
(詳細は,
EvmEventPost
(3)
EvmConnDestroy
-- 指定の接続を破壊する
(詳細は,
EvmConnDestroy
(3)
EvmConnCreate()
の代わりに,シンプルな
EvmConnCreatePoster()
マクロを用いて発信接続を行うことができます。
このマクロは必要な引数が
EvmConnCreate()
よりも少なく,指定できる接続オプションが少ないものの,ローカル・システムにイベントを発信する必要のあるアプリケーションのほとんどで使用できます。
プログラムで一時的な EVM 接続を使用する場合は,EvmConnCreate()
や
EvmConnDestroy()
の呼び出しを省略して,EvmEventPost()
への接続引数として NULL を渡すこともできます。
接続の確立には処理時間がかかるので,プログラムに適していれば,一時的な接続のみを使用してください。
詳細は,14.7.8 項
および
EvmEventPost
(3)
EvmEventPostVa()
関数を使用すると,イベントの作成,発信,廃棄を 1 回の呼び出しで行えます。
詳細は
EvmEventPost
(3)
#include <stdio.h> #include <evm/evm.h> void main() { EvmEvent_t event; EvmStatus_t status; EvmConnection_t conn; status = EvmConnCreate(EvmCONNECTION_POST, EvmRESPONSE_WAIT, [1] NULL,NULL,NULL,&conn); if (status != EvmERROR_NONE) { fprintf(stderr,"Failed to create EVM posting connection\n"); exit(1); } EvmEventCreateVa(&event, [2] EvmITEM_NAME,"myco.examples.app.error_detected", EvmITEM_NONE); status = EvmEventPost(conn,event); if (status != EvmERROR_NONE) { fprintf(stderr,"Failed to post event\n"); exit(1); } EvmEventDestroy(event); [3] EvmConnDestroy(conn); }
EVM デーモンへの接続を作成するには,EvmConnCreate()
を使用します。
接続は,プログラムを終了するか,または
EvmConnDestroy()
を使用して明示的に破壊するまで切断されません。
EvmConnCreate()
の最初の 2 つの引数では,接続がイベントの発信に使用されること,および EVM デーモンがイベントの受諾を肯定応答してから発信関数が戻ることを指定しています。
このため,発信に失敗した場合は,対応する処置を実行できます
(その他の応答オプションについては,
EvmConnCreate
(3)NULL
値は,ローカル・システム上で動作する EVM デーモンに接続することを示します。
ほとんどの場合,ここには
NULL
を指定します。
リモート接続についての詳細は,
EvmConnCreate
(3)NULL
を指定します。
最後の引数を使用して,接続のハンドルを取得します。
この接続で今後呼び出しを実行するときは,この値を指定しなければなりません。
[例に戻る]
イベントを作成して発信します。 [例に戻る]
イベントおよび接続を破壊して,クリーンアップします。 定期的にイベントを発信する場合は接続を破壊しないで,今後のすべてのイベントに対して再使用することをお勧めします。 こうしておくと,発信するたびに接続を再確立するオーバヘッドを削減できます。 [例に戻る]
次のいずれかの操作を実行するプログラムを作成する場合は,EVM の読み取りおよび書き込み関数を使用する必要があります。
ファイルにイベントを格納する
パイプまたはソケット接続を用いて,イベントを別のプロセスに渡す
ファイルに格納したイベントを分析する
EVM デーモン以外のプロセスからイベントを受信する
標準の UNIX 書き込み関数を使用して,イベントを直接書き込むことはできません。 これは,イベント・ハンドルには,イベント本体へのポインタ以外は設定されていないうえ,イベントが変更されるたびにイベント本体の位置が変更される可能性があるためです。 逆に,イベントを読み込むときは,本体を読み込むだけでは十分ではありません。 ハンドルを作成し,API 関数を介してイベントを参照できるようにする必要があります。
例 14-6 は,ファイルへのイベントの書き込み,ファイルからプログラムへのイベントの読み取り,およびイベントの有効性の確認を行う方法の例です。
この例では,次の関数について説明します。
EvmEventWrite
-- オープン・ファイル記述子にイベントを書き込む
(詳細は,
EvmEventWrite
(3)
EvmEventRead
-- 新しいイベント構造体を作成し,ファイル記述子から読み込まれたイベントを設定する。
新しいイベントは,EvmEventDestroy()
を使用して解放する必要がある (詳細は,EvmEventRead
(3) を参照)。
EvmEventValidate
-- イベントについてデータの一貫性をチェックする。
このチェックは,接続を介して受信したり,記憶域から取得したイベントの有効性を確認するために行う
(詳細は,
EvmEventValidate
(3)
#include <stdio.h> #include <fcntl.h> #include <evm/evm.h> void main() { EvmEvent_t event_in,event_out; EvmStatus_t status; EvmItemValue_t itemval; int fd; EvmEventCreateVa(&event_out, [1] EvmITEM_NAME,"myco.examples.app.saved_event", EvmITEM_NONE); fd = open("eventlog",O_RDWR | O_CREAT | O_TRUNC, [2] S_IRUSR | S_IWUSR); if (fd < 0) { fprintf(stderr,"Failed to open output log file\n"); exit(1); } status = EvmEventWrite(fd,event_out); if (status != EvmERROR_NONE) { fprintf(stderr,"Failed to write event to log file\n"); exit(1); } lseek(fd,0,SEEK_SET); [3] status = EvmEventRead(fd,&event_in); if (status != EvmERROR_NONE) { fprintf(stderr,"Failed to read event from log file\n"); exit(1); } status = EvmEventValidate(event_in); [4] if (status != EvmERROR_NONE) { fprintf(stderr,"Event read from logfile is invalid"); exit(1); } status = EvmItemGet(event_in,EvmITEM_NAME,&*itemval); [5] if(status == EvmERROR_NONE) { fprintf(stdout,"Event name: %s\n",itemval.NAME); EvmItemRelease(EvmITEM_NAME,itemval); } EvmEventDestroy(event_in); [6] EvmEventDestroy(event_out); }
名前が設定されたイベントを作成します。 [例に戻る]
出力ログ・ファイルを作成し,EvmEventWrite()
を使用してイベントを書き込みます。
イベントは,別のプロセスへのパイプを含め,任意のファイル記述子に書き込むことができます。
ただし,イベントはバイナリ・データ・パッケージであるため,端末やプリンタには直接書き込まないでください。
[例に戻る]
EvmEventRead()
を使用してイベントを読み戻します。
このとき,別のイベントが作成され,イベント・ハンドル自体ではなく,イベント・ハンドルへのポインタを設定する必要があることに注意してください。
[例に戻る]
着信イベントは,このプロセスによって制御されていないため,一貫性を確認することが重要です。
ファイルからイベントを読み込むたびに,または EVM デーモン以外のプロセスからイベントを受信するたびに,EvmEventValidate()
関数を使用して確認します。
[例に戻る]
読み込んだイベントが,既に書き込んだイベントと同じものであることを確認するには,名前を取得して表示します。 [例に戻る]
イベントによって使用された領域を解放します。 [例に戻る]
イベント通知を受信するプログラムでは,次の操作を実行する必要があります。
EVM デーモンに対してリッスン接続を作成する。
EVM デーモンにフィルタ文字列を渡して,関心のあるイベントを通知する。
接続上のイベント関連アクティビティを監視して,イベントが着信したらただちに処理できるようにする。
例 14-7
は,イベントの受信を待機し,イベントが着信するたびに
stdout
に表示される例です。
この例では,次の関数について説明します。
EvmConnSubscribe
-- 指定したフィルタと一致する発信イベントの通知を要求する
(詳細は,
EvmConnSubscribe
(3)
EvmConnWait
-- 指定の接続上で,アクティビティが検出されるまでブロックする。
アクティビティが検出されると,呼び出し側のプログラムによって
EvmConnDispatch()
が呼び出され,そのアクティビティが処理される
(詳細は,
EvmConnWait
(3)
EvmConnDispatch
-- 必要に応じてプログラムのコールバック関数を呼び出し,指定の接続上での未処理の入出力を処理する
(詳細は,
EvmConnDispatch
(3)
EvmEventFormat
-- イベントをフォーマットする
(詳細は,
EvmEventFormat
(3)
注意
EvmConnCreate()
の代わりに,シンプルなEvmConnCreateSubscriber()
マクロを用いて受信接続を行うことができます。 このマクロは必要な引数がEvmConnCreate()
よりも少なく,指定できる接続オプションは少ないものの,受信アプリケーションのほとんどで使用できます。 詳細はを参照してください。 EvmConnCreate
(3)
#include <stdio.h> #include <evm/evm.h> void EventCB(EvmConnection_t conn, EvmCallbackArg_t cbarg, EvmCallbackData_t *cbdata); /*==================================================== * Function: main() *====================================================*/ main() { EvmConnection_t conn; EvmStatus_t status; status = EvmConnCreate(EvmCONNECTION_LISTEN, EvmRESPONSE_CALLBACK, NULL,EventCB,NULL,&conn); [1] if (status != EvmERROR_NONE) { fprintf(stderr,"Failed to create EVM listening connection\n"); exit(1); } status = EvmConnSubscribe(conn,NULL,"[name *.evm.msg.user]"); [2] if (status != EvmERROR_NONE) { fprintf(stderr,"Failed to subscribe for event notification\n"); exit(1); } for (;;) [3] { status = EvmConnWait(conn,NULL); if (status == EvmERROR_NONE) { fprintf(stderr,"Connection error\n"); exit(1); } if (EvmConnDispatch(conn) != EvmERROR_NONE) { fprintf(stderr,"Connection dispatch error\n"); exit(1); } } } /*==================================================== * Function: EventCB() *====================================================*/ void EventCB(EvmConnection_t conn, EvmCallbackArg_t cbarg, [4] EvmCallbackData_t *cbdata) { char buff[256]; switch (cbdata->reason) { [5] case EvmREASON_EVENT_DELIVERED: EvmEventFormat(buff, sizeof(buff), cbdata->event); fprintf(stdout,"Event: %s\n",buff); EvmEventDestroy(cbdata->event); [6] break; default: [7] break; } }
EvmConnCreate()
を使用して EVM デーモンへの接続を確立します。
ここではリッスン接続を指定します。
このコード例では,次の引数が指定されています。
EvmConnCreate()
の最初の 2 つの引数には,接続がリッスンに使用されること,およびイベントが着信した場合はコールバック関数を介して通知することが指定されている。
3 番目の引数には
NULL
が指定されているが,ローカル EVM デーモンに接続することを示す。
リモート接続についての詳細は,
EvmConnCreate
(3)
4 番目の引数には,イベントが着信した場合に呼び出すコールバック関数 (EventCB
) が指定されている。
5 番目の引数は,コールバック引数であり,この接続で使用するために呼び出されるたびにコールバック関数に渡される値である。
この引数は任意の目的で使用できるが,この例では
NULL
に設定されている。
最後の引数は,接続へのハンドルを受信する。
次のステップでは,EvmConnSubscribe()
関数を使用して EVM デーモンに受信したいイベントを通知しています。
ここでは,evmpost
で発信できるユーザ・メッセージを待機しています。
これらのイベントには,sys.unix.evm.msg.user
という名前が付いています。
EvmConnSubscribe()
を呼び出すと,EvmConnDispatch()
を呼び出したときに,コールバック関数が
EvmREASON_SUBSCRIBE_COMPLETE
という理由コードで呼び出されます。
[例に戻る]
この例では,イベントの着信を待機する以外に処理が記述されていません。
このため,EvmConnWait()
を使用して接続上のアクティビティを監視しながら,永久にループします。
EvmConnWait()
の 2 番目の引数として渡された
NULL
は,アクティビティが存在しない場合でもタイムアウトにならないことを示します。
EvmConnWait()
は,アクティビティが発生するたびに戻りますが,イベントが着信しているとは限りません。
たとえば,EVM デーモンからほかのメッセージが送信された場合,またはプロセスがシグナルによって割り込まれた場合にも戻ります。
この関数が正常に戻った場合は,EvmConnDispatch()
を呼び出してアクティビティを処理する必要があります。
通常は,コールバック関数
EventCB()
が呼び出されますが,いつもとは限りません。
[例に戻る]
EvmConnDispatch()
では,アプリケーション・コードによる処理を要求するメッセージがデーモンから読み込まれたときに,コールバック関数が呼び出されます。
このメッセージには,着信イベントも含まれます。
ただし,アプリケーションでは,ほかの種類のメッセージも考慮する必要があります。
このコード例では,次の引数が指定されています。
コールバック関数の最初の引数は,接続ハンドルである。 ある状況で接続を識別するときに使用すると便利であるが,用途は限られている。
2 番目の引数は,接続を確立したときに指定したコールバック引数である。 この値を使用して接続を識別することができ,C++ コードの場合は,オブジェクト・インスタンスにポインタを渡すときに使用することもできるが,使用しなくてもよい。
最後の引数は,コールバック・データであり,コールバック情報が含まれている構造体へのポインタである。
コードが呼び出された理由を確認するには,コールバック・データの構造体を検査する必要がある。
構造体には,理由コード,状態値,および イベントへのポインタ (イベントが配信されている場合) が含まれている。
この構造体についての詳細は,
EvmCallback
(5)
この例では,理由コード
EvmREASON_EVENT_DELIVERED
に記述されているように,着信イベント・メッセージを待機しています。
イベントが着信すると,フォーマット後に表示します。
イベントによって使用される領域を解放するため,処理が終了したらイベントを破壊します。
[例に戻る]
実行されるアクションは,コールバックの理由コードに依存しています。
この場合,理由はイベントが配信されたことなので,EvmEventFormat()
関数を使用してイベントを表示用にフォーマットし,stdout
に出力します。
EvmEventFormat()
では,イベントのフォーマット・データ項目 (設定されている場合) を基にしてテキスト行が生成され,その結果が指定したバッファに格納されます。
フォーマットによって,イベント本体が変更されることはありません。
[例に戻る]
配信されたイベントによってヒープ領域が使用されています。 イベントの処理が終了したら,アプリケーションでこの領域を解放する必要があります。 [例に戻る]
既に受信要求を発行しているため,EvmREASON_SUBSCRIBE_COMPLETE
というコールバック理由によってその関数も起動されます。
この例の場合は,この理由コードおよびその他の理由コードは無視して構いません。
[例に戻る]
イベントのリッスン以外に処理を行うプログラムを作成する場合は,イベントの着信を待機するときに
EvmEventWait()
以外の関数を使用することもできます。
たとえば,select
システム・コールを使用して,EVM 接続など,複数のファイル記述子に対する入出力アクティビティを監視する方法があります。
例 14-8
は,EVM 接続を
stdin
からの入力とともに処理する方法の例です。
この例では,次の関数について説明します。
EvmConnFdGet
-- 指定の接続に関連付けられたファイル記述子 (ファイル番号) を返す
(詳細は,
EvmConnFdGet
(3)
EvmConnCheck
-- 指定の接続上で,未処理の入出力アクティビティがないかどうかを確認する
(詳細は,
EvmConnCheck
(3)
#include <stdio.h> #include <sys/time.h> #include <evm/evm.h> void HandleInput(); void EventCB(EvmConnection_t conn, EvmCallbackArg_t cbarg, EvmCallbackData_t *cbdata); /*=============================================== * Function: main() *===============================================*/ main() { EvmConnection_t conn; EvmStatus_t status; fd_set read_fds; int conn_fd; EvmBoolean_t io_waiting; status = EvmConnCreate(EvmCONNECTION_LISTEN, EvmRESPONSE_CALLBACK, NULL,EventCB,NULL,&conn); if (status != EvmERROR_NONE) { fprintf(stderr,"Failed to create EVM listening connection\n"); exit(1); } status = EvmConnSubscribe(conn,NULL,"[name sys.unix.evm.msg.user]"); if (status != EvmERROR_NONE) { fprintf(stderr,"Failed to subscribe for event notification\n"); exit(1); } EvmConnFdGet(conn,&conn_fd); [1] for (;;) [2] { FD_ZERO(&read_fds); FD_SET(fileno(stdin),&read_fds); FD_SET(conn_fd,&read_fds); select(FD_SETSIZE,&read_fds,NULL,NULL,NULL); if (FD_ISSET(fileno(stdin),&read_fds)) HandleInput(); status = EvmConnCheck(conn,&io_waiting); [3] if (status != EvmERROR_NONE) { fprintf(stderr,"Connection error\n"); exit(1); } if (io_waiting) { status = EvmConnDispatch(conn); if (status != EvmERROR_NONE) { fprintf(stderr,"Connection dispatch error\n"); exit(1); } } } } /*=============================================== * Function: HandleInput() *===============================================*/ void HandleInput() [4] { char buff[256]; if (feof(stdin)) exit(0); if (fgets(buff,sizeof(buff),stdin) == NULL) exit(0); if (buff[0] == '\n') exit(0); fprintf(stdout,buff); } /*=============================================== * Function: EventCB() *===============================================*/ void EventCB(EvmConnection_t conn, EvmCallbackArg_t cbarg, [5] EvmCallbackData_t *cbdata) { char buff[256]; switch (cbdata->reason) { case EvmREASON_EVENT_DELIVERED: EvmEventFormat(buff, sizeof(buff), cbdata->event); fprintf(stdout,"Event: %s\n",buff); EvmEventDestroy(cbdata->event); break; default: break; } }
EvmConnFdGet()
を使用して,接続に割り当てられたファイル記述子を検索します。
[例に戻る]
この例では,入出力アクティビティを監視するときに
select
を使用しています。
select
を使用すると,複数のファイル記述子を監視できます。
select
呼び出しが戻ったときに,アクティビティが発生したファイル記述子を確認し,適切に処理します。
[例に戻る]
EvmConnCheck()
を使用して,EVM 接続上で未処理のアクティビティが存在するかどうかを確認します。
接続のファイル記述子がわかっているので,FD_ISSET()
を使用することもできます。
[例に戻る]
HandleInput()
関数は,stdin
から入力行を読み取り,stdout
にエコーします。
エラーが発生するか空の行を読み込んだ場合は,プログラムが終了します。
[例に戻る]
イベントのコールバック関数は,前の例で使用したものと同じです。 [例に戻る]
イベント受信者によっては,さまざまな基準を使用してイベントを監視し,着信イベントの属性に応じて異なる対応が必要になることがあります。 たとえば,EVM ロガーでは,構成ファイルからフィルタ文字列を読み込んで,その文字列に記述されているすべてのイベントを受信します。 このため,イベントを適切なログに書き込むには,イベントが着信したときに,イベントと一致するフィルタ文字列を識別する必要があります。
たとえば,EVM デーモンに対して複数の接続を作成し,接続ごとに別個のフィルタ文字列を使用して受信する方法があります。 しかし,この方法の場合は,接続のオーバヘッドが大きくなり,同じイベントが 2 つ以上の接続を介して送信される可能性が大きくなります。
もっと効率的な方法として,論理演算子 OR を使用して,フィルタ文字列をすべて取り込み,それらを結合して 1 つの論理文字列にする方法があります。 結合された文字列は,単一の接続上で一致するイベントをすべて受信するときに使用することができます。 結合された文字列は後で破棄できますが,元の文字列は保持しておく必要があります。 接続の再確立またはフィルタの変更が必要になった場合は,元の文字列を使用して再受信することができます。
ただし,イベントが着信したときには,イベントの処理方法を決定するために,イベントと一致する元のフィルタ文字列を識別する必要があります。 このとき,EVM フィルタ・エバリュエータを使用することができます。 フィルタ・エバリュエータは,ユーザが作成できるオブジェクトで,フィルタ文字列とともにロードされ,フィルタと一致するイベントを識別する (一致が存在する場合) ために複数のイベントが渡されます。 元の各フィルタ文字列に対して別個のエバリュエータを割り当てておくと,着信イベントごとにそれぞれのエバリュエータを適用して,イベントと一致するエバリュエータを識別することができます。
例 14-9 はこの方法の例です。 簡単な 3 つのフィルタ文字列を使用して,一致が存在する場合は,着信イベントと一致するフィルタに応じて異なるメッセージを出力しています。
この例では,次の関数について説明します。
EvmFilterCreate
-- フィルタ・エバリュエータのインスタンスを生成し,ハンドルを返す
(詳細は,
EvmFilterCreate
(3)EvmFilter
(5)
EvmFilterSet
-- 後続の照合で使用されるフィルタ文字列を,フィルタ・エバリュエータに渡す
(詳細は,
EvmFilterSet
(3)EvmFilter
(5)
EvmFilterTest
-- 指定のイベントを,フィルタ・エバリュエータに現在関連付けられているフィルタ文字列と比較する。
イベントとフィルタ文字列が一致した場合は,EvmTRUE
を返し,一致しない場合は
EvmFALSE
を返す
(詳細は,
EvmFilterTest
(3)EvmFilter
(5)
EvmFilterDestroy
-- フィルタ・エバリュエータを破壊し,関連付けられたリソースをすべて解放する
(詳細は,
EvmFilterDestroy
(3)EvmFilter
(5)
#include <stdio.h> #include <sys/time.h> #include <evm/evm.h> void EventCB(EvmConnection_t conn, EvmCallbackArg_t cbarg, EvmCallbackData_t *cbdata); #define FILTER_1 "[name *.class_1]" [1] #define FILTER_2 "[name *.class_2]" #define FILTER_3 "([name *.class_2] | [name *.class_3]) & [priority >= 300]" /*=============================================== * Function: main() *===============================================*/ main() { EvmConnection_t conn; Evmstatus_t status; int conn_fd; char *filter_string; status = EvmConnCreate(EvmCONNECTION_LISTEN, EvmRESPONSE_CALLBACK, NULL,EventCB,NULL,&conn); if (status != EvmERROR_NONE) { fprintf(stderr,"Failed to create EVM listening connection\n"); exit(1); } filter_string = (char *)malloc(strlen(FILTER_1) + strlen(FILTER_2) + strlen(FILTER_3) + 30); [2] sprintf(filter_string,"(%s) | (%s) | (%s)",FILTER_1,FILTER_2,FILTER_3); status = EvmConnSubscribe(conn,NULL,filter_string); [3] if (status != EvmERROR_NONE) { fprintf(stderr,"Failed to subscribe for event notification\n"); exit(1); } free(filter_string); for (;;) [4] { status = EvmConnWait(conn,NULL); if (status != EvmERROR_NONE) { fprintf(stderr,"Connection error\n"); exit(1); } if (EvmConnDispatch(conn) != EvmERROR_NONE) { fprintf(stderr,"Connection dispatch error\n"); exit(1); } } } /*=============================================== * Function: EventCB() *===============================================*/ void EventCB(EvmConnection_t conn, EvmCallbackArg_t cbarg, EvmCallbackData_t *cbdata) { EvmBoolean_t match; static EvmFilter_t f1,f2,f3; [5] static EvmBoolean_t filters_initialized = EvmFALSE; if (! filters_initialized) { if (EvmFilterCreate(&f1) != EvmERROR_NONE) { fprintf(stderr,"Failed to create filter evaluator\n"); exit(1); } if (EvmFilterSet(f1,FILTER_1) != EvmERROR_NONE) { fprintf(stderr,"Failed to set filter evaluator\n"); exit(1); } EvmFilterCreate(&f2); EvmFilterSet(f2,FILTER_2); EvmFilterCreate(&f3); EvmFilterSet(f3,FILTER_3); filters_initialized = EvmTRUE; } switch (cbdata->reason) { [6] case EvmREASON_EVENT_DELIVERED: EvmFilterTest(f1,cbdata->event,&match); if (match) fprintf(stdout,"Filter 1 event received\n"); EvmFilterTest(f2,cbdata->event,&match); if (match) fprintf(stdout,"Filter 2 event received\n"); EvmFilterTest(f3,cbdata->event,&match); if (match) fprintf(stdout,"Filter 3 event received\n"); EvmEventDestroy(cbdata->event); break; default: break; } }
3 つの簡単なフィルタ文字列を定義します。 最初の 2 つは,名前だけを基にしてフィルタを実行します。 3 番目の文字列は,300 以上の優先度が設定されたイベントのうち,2 つの名前のいずれかと一致するイベントを選択します。 [例に戻る]
3 つのフィルタ文字列を,1 つの論理式に結合します。 各部分文字列はカッコで囲まれ,論理演算子 OR で区切られています。 この結果,イベントが 1 つ以上の部分文字列と一致したときに,EVM デーモンから通知されます。 [例に戻る]
結合された文字列を使用してイベントを受信します。 その後,文字列の使用が終了したため,その領域を解放します。 何らかの理由で再受信が必要になった場合は,いつでも部分文字列を再度結合できます。 [例に戻る]
エバリュエータを設定したら,受信するすべてのイベントに対して使用できるように保存します (つまり,静的要素にします)。 もう 1 つの方法として,イベントを受信するたびに新しいエバリュエータを作成し,関数を終了するときに破壊することもできます。 ただし,保存しておくと,セットアップおよび破棄の繰り返しによるオーバヘッドを回避できます。 [例に戻る]
EvmFilterCreate()
を使用して 3 つのフィルタ・エバリュエータを作成し,3 つのフィルタ文字列をロードします。
わかりやすくするために,この例では最初のフィルタの戻り状態だけを確認していますが,製品コードでは各フィルタの戻り状態を確認してください。
このコードは,イベントを最初に受信した場合にだけ実行されます。
[例に戻る]
前述のセクションで設定した 3 つのフィルタ・エバリュエータに対して,各着信イベントを検査し,イベントと一致したエバリュエータごとに異なるメッセージを出力しています。 イベントが複数のエバリュエータと一致することもあり,この場合は,複数のメッセージを出力します。 [例に戻る]
EVM の命名ポリシでは,基本イベント名の後に任意の数のコンポーネントを追加して拡張することができます。 つまり,コンポーネントが追加されている可能性があるため,イベント名が元の名前と全く同じである保証はありません。
このため,イベント名を既知のイベント名と比較する場合は,通常の文字列比較関数を使用しないでください。 コンポーネントが追加されている場合は,適切に名前を照合することができません。 代わりに,EVM の名前照合関数を使用します。 名前照合関数を使用すると,指定したパターンを基にしてイベント名が照合され,照合するイベント名にコンポーネントが追加されていても無視されます。 また,名前パターンにワイルドカード文字を含めることもできます。
例 14-10 では,次の関数について説明します。
EvmEventNameMatch
-- イベント名文字列 (ワイルドカード文字も使用可能) およびイベントを入力引数として指定できる。
イベントが名前文字列と一致するかどうかを返す。
次の関数は,EvmEventNameMatch
に関連しています。
EvmEventNameMatchStr
-- イベント名をイベントから抽出せずに,文字列として指定する。
#include <stdio.h> #include <evm/evm.h> /*=============================================== * Function: main() *===============================================*/ main() { EvmStatus_t status; EvmEvent_t event; EvmBoolean_t match; char buff[80]; while (EvmERROR_NONE == EvmEventRead(fileno(stdin),&event)) [1] { EvmEventNameMatch("*.msg",event,&match); if (match) { EvmEventFormat(buff,sizeof(buff),event); fprintf(stdout,"%s\n",buff); } } }
stdin
からイベントを読み取り,ワイルドカード文字列
*.msg
と一致するイベントだけを表示します。
この種類のイベントの名前は通常
sys.unix.evm.msg.user
または
sys.unix.evm.msg.admin
ですが,照合は機能します。
[例に戻る]
開発中のアプリケーションが,短期間に大量に発信されるイベントのセットを受信する場合,プログラムが EVM デーモンにより,1 つまたは複数のイベントを失ったと通知することがあります。 これは,プログラムの処理量がひじょうに多く,新しくイベントが到着してもすぐに対処できず,未処理のイベントで通信バッファが満杯になってしまうような場合に起こりやすくなります。 失われたイベントについての詳細は,14.7.10 項 を参照してください。
例 14-11
では,イベントをすべて受信し,各イベントを到着時に
stdout
に表示します。
これは,コールバック関数に
EvmREASON_EVENTS_MISSED
という理由を入れることで失われたイベントの通知を監視し,失ったイベントの数を含むメッセージを表示します。
#include <stdio.h> #include <evm/evm.h> void EventCB(EvmConnection_t conn, EvmCallbackArg_t cbarg, EvmCallbackData_t *cbdata); /*=============================================== * Function: main() *===============================================*/ main() { EvmConnection_t conn; EvmStatus_t status; int conn_fd; status = EvmConnCreate(EvmCONNECTION_LISTEN, EvmRESPONSE_CALLBACK, NULL,EventCB,NULL,&conn); if (status != EvmERROR_NONE) { fprintf(stderr,"Failed to create EVM listening connection\n"); exit(1); } status = EvmConnSubscribe(conn,NULL,"[name *]"); if (status != EvmERROR_NONE) { fprintf(stderr,"Failed to subscribe for event notification\n"); [1] exit(1); } for (;;) { status = EvmConnWait(conn,NULL); if (status != EvmERROR_NONE) { fprintf(stderr,"Connection error\n"); exit(1); } if (EvmConnDispatch(conn) != EvmERROR_NONE) { fprintf(stderr,"Connection dispatch error\n"); exit(1); } } } /*=============================================== * Function: EventCB() *===============================================*/ void EventCB(EvmConnection_t conn, EvmCallbackArg_t cbarg, EvmCallbackData_t *cbdata) { char buff[256]; switch (cbdata->reason) { case EvmREASON_EVENT_DELIVERED: EvmEventFormat(buff, sizeof(buff), cbdata->event); fprintf(stdout,"Event: %s\n",buff); EvmEventDestroy(cbdata->event); sleep(1); [2] break; case EvmREASON_EVENTS_MISSED: [3] fprintf(stdout,"*** Missed %d incoming events\n", cbdata->extension.eventMissedData.missedCount); break; default: break; } }
この例では,すべてのイベントの通知を受信しています。 [例に戻る]
イベントが失われた状態を示すために,各イベントを受信した後に 1 秒間スリープしています。 これは,負荷の超過が発生した状況をシミュレートしており,イベントの負荷が大きい場合は,入力接続バッファがいっぱいになることが確認されます。 [例に戻る]
イベントが失われたため,EVM デーモンがイベントを送信できない場合は,コールバック関数が理由コード
EvmREASON_EVENTS_MISSED
で呼び出されます。
コールバック・データ・メンバ
extension.eventMissedData.missedCount
には,失われたイベント数が格納されます。
[例に戻る]
イベント・チャネルという言葉は,イベント情報を公開または取得するために使用する機能を表します。 また,次のいずれかを表す場合もあります。
単純なログ・ファイル
イベント管理システム
ステータス情報のスナップショットを取得するために実行されるプログラム
イベント・チャネルには,アクティブ・チャネルとパッシブ・チャネルがあります。 アクティブ・チャネルでは,イベントが発生すると直ちに固有のイベント情報が EVM に発信されます。 パッシブ・チャネルでは,イベント情報はチャネル内に蓄積され,検索するには EVM からのアクションが必要です。
イベント・チャネルは,正式なイベント通知メカニズムである必要はありません。 情報の格納,あるいは状態または状態変更の表示を行うことができるものであれば,何でも構いません。 次に例を示します。
アプリケーションまたはシステム・コンポーネントで独自のログ・ファイルに状態情報を書き込む場合は,そのログ・ファイルの各エントリをイベントと見なすことができます。 新しいエントリがあるかどうかについてログ・ファイルを定期的に確認し,新しいエントリが検出されるたびにイベントを発信することができます。 ログ・ファイル自体も,過去のイベントを取得するための場所として機能します。
一部のアプリケーションおよびシステム・コンポーネントには,状態を照会する機能があります。 これらのアプリケーションおよびシステム・コンポーネントでは,状態を定期的に監視し,重大な変更が検出された場合にイベントを発信することができます。 このようなイベント・チャネルには,通常,イベント情報を格納する手段はないため,EVM のロギング機能を使用してイベントのログを記録することができます。
アプリケーションの中心部分でそのアプリケーションのイベント情報をすべて処理する場合は,イベント情報を EVM に転送できるように処理コードを変更することができます。 これは,アクティブ・イベント・チャネルの例です。
既存のイベント・チャネルを EVM を介してアクセスできるようにする処理は,カプセル化と呼ばれます。
EVM イベント・チャネルは,チャネル構成ファイルを使用して構成します。 このファイルは,EVM の起動時に EVM チャネル・マネージャによって読み込まれ,また,チャネル情報が必要な場合は,コマンド行ユーティリティでも使用されます。 このファイルを変更する場合は,次のコマンドを入力して,チャネル・マネージャに変更を通知する必要があります。
evmreload -c
チャネル構成ファイルの構文については,
evmchannel.conf
(4)
取得関数 --
evmget
が実行されたときに,チャネルから過去のイベントを取得する。
詳細関数 --
evmshow
が
-d
オプションを指定して実行されたときに,イベント・ストリームを詳細に表示する。
説明関数 --
evmshow
が
-x
オプションを指定して実行されたときに,イベント・ストリームの説明テキストを提供する。
この関数は,一般にチャネルの詳細関数でも起動される。
監視関数 -- EVM チャネル・マネージャによって定期的に実行され,チャネル状態をチェックし,必要に応じてイベントの発信を行う。
クリーンアップ関数 -- EVM チャネル・マネージャによって毎日実行され,チャネルに必要なクリーンアップ処理を行う。
これらの関数はすべてオプションです。 チャネル構成ファイルのチャネル定義に適切なエントリを追加することにより,チャネルに対して定義されます。 チャネル関数には任意の種類の実行可能ファイルを使用できますが,この後の各項で説明するとおりに動作する必要があります。
一時ファイルを使用するチャネル関数では,終了前に必ずクリーンアップを実行する必要があります。 また,割り込みが発生した場合でも,クリーンアップを実行できなければなりません。
また,次の操作が必要です。
新しいイベント・チャネルを介して発信または取得するイベントに対するイベント・テンプレートの追加。 イベント・テンプレートの追加については,14.6.3 項 を参照。
必要に応じて EVM 権限ファイルを変更することによる,イベントに適切な発信およびアクセス権限が割り当てられていることの確認。 イベントに対するアクセスの制御方法についての詳細は,『システム管理ガイド』を参照。
チャネルの取得関数は,EVM の
get_server
によって実行されます。
get_server
は,EVM デーモンによって実行され,evmget
を介して行われたイベント取得要求を処理します。
この関数は常に root として実行されるので,適切なセキュリティ対策が必要です。
この関数では,次の呼び出し構文を使用します。
function-name
[-f
filter-string]
必要に応じて,その他の引数も関数に渡すことができます。 チャネル構成ファイルの該当する関数の行に,引数を指定してください。
取得関数を実行すると,イベントがチャネルのログ・ファイルから取得されて,EVM のイベント・フォーマットに変換され,変換後の EVM イベントが
stdout
ストリームに書き込まれます。
filter-string
を指定すると,フィルタと一致するイベントだけが
stdout
に書き込まれます。
エラー・メッセージは,stderr
に書き込まれ,evmget
に渡されてから,その
stderr
ストリームに出力されます。
このため,エラー・メッセージがこの関数で発生したことを明示的に示す必要があります。
stdout
には,EVM イベント以外は書き込まないでください。
取得スクリプトの形式は,元のイベントの格納形式に大きく依存します。 標準では,次のステップが実行されます。
grep
,awk
および
sed
などの UNIX の標準ツールか,または perl などのプログラミング言語を使用して,イベント行の選択およびブランク行とコメントの削除を行い,次のステップに必要な形式にフォーマットします。
イベントが単一行テキストで構成され,各行のフォーマットが一定しており,タイムスタンプ,ホスト名,およびメッセージなどの項目がすべての行で同じ位置に配置されている場合,この作業は簡単に行うことができます。
各行を EVM イベントに変換します。
これを行うには,UNIX ツールを使用して,各行を
evmpost
への入力に適した形式にフォーマットし,発信するのではなく,-r
オプションを使用して,EVM イベントを
stdout
に出力します。
迅速に変換する方法として,EVM チャネル・ユーティリティの
/usr/share/evm/channels/bin/text2evm
を使用することもできます。
このツールを使用する場合は,現在,次の形式で入力する必要があります。
evm-event-name date time host user message
各項目の意味は以下のとおりです。
evm-event-name
はツールによって作成される EVM イベントの
NAME
です。
特定のチャネルを通じて渡されるすべてのイベントは,イベントをチャネルに対応づけることができるように,名前のコンポーネントのうち,最初の数個が同じでなければなりません。
date
および
time
は,イベントの
TIMESTAMP
項目を構成します。
日付のコンポーネントは基本フォーマット
year/month/day
でなければなりません。
ここでスラッシュ (/
) 文字は次の文字のいずれかで置き換えることができます。
ハイフン (-
),コロン (:
),ピリオド (.
)
ログファイルのフォーマットにバリエーションを許し,シェル・スクリプトで実行する変換の作業量を最小限にするために,値のフォーマットにはある程度の柔軟性もあります。
年は 2 桁あるいは 4 桁にするか,または疑問符 (?
) 文字に置き換えることができます。
4 桁の数値を指定すると,年は変更されません。
2 桁の数値を指定すると,値が 90 以上であれば 1900 が加算されて年になります。
値が 90 未満であれば,2000 が加算されます。
年の代わりに
?
文字を指定すると,指定されたタイムスタンプの月と日を現在の日付と比較して,省略された年をツールが計算します。
タイムスタンプの月と日が現在より後の日付を示していれば,年の値は前年になり,それ以外の場合は今年になります。
月は 1 〜 12 までの 2 桁の数値か,月の名前で指定します。 月の名前は,省略形 (Feb など) と省略していない形式 (February) のいずれでも指定できます。 月の名前は,英語またはシステムの省略時ロケールの言語で指定します。
時刻は
hours:
minutes:
seconds
というフォーマットで指定します。
host
は
HOST_NAME
項目であり,hostname
コマンドで調べることができます。
user
は
USER_NAME
項目です。
ログ内の項目がすべて 1 つのアプリケーション・プログラムまたはサブシステムによって記録される場合は,ログファイルの所有者を user フィールドに指定します。
message
はイベントのメッセージ・テキストであり,FORMAT
データ項目としてイベントに挿入されます。
filter-string
を指定した場合は,-f
および
-r
オプションを指定した
evmshow
を介してその出力を渡すと,フィルタで要求されている文字列だけに出力が制限されます。
最後に,取得したイベントに対してイベント・テンプレートに含まれるデータ項目を設定したい場合は,EVM チャネル・ユーティリティの
/usr/share/evm/channels/bin/merge_template
を介して出力をパイプすることもできます。
このプログラムは
stdin
の EVM イベントを読み取り,各イベントに対応するテンプレートをEVM デーモンから取得します。
次にテンプレート情報をイベントにマージし,処理結果の展開済みイベントを
stdout
に書き込みます。
チャネルのログ・ファイルを EVM フォーマットに変換するのが困難な場合,たとえば,各エントリが構造化されていない複数のテキスト行で構成されているため,簡単に解析できない場合は,取得関数を使用しないで,イベントが発信されたときに EVM ロガーでログが記録されるようにすることをお勧めします。 この場合,イベントが 2 つの場所に格納されるため,記憶域の使用量が多くなりますが,取得時間およびプログラミング工数が大幅に削減されます。
チャネルに対して独自の取得関数を使用する場合は,EVM ロガーの構成ファイルのフィルタ文字列を変更して,イベントが EVM ログ内で重複しないようにする必要があります。
EVM ロガーの構成ファイルを変更する方法については,『システム管理ガイド』を参照してください。
14.8.2 詳細関数
詳細関数は,evmshow
に
-d
オプションを指定して呼び出したときに実行されます。
現在は
evmshow
を実行するユーザの権限で実行されますが,今後のリリースでは変更される可能性があるため,適切なセキュリティ対策が重要になります。
この関数では,次の呼び出し構文を使用します。
function-name [arguments]
チャネル構成ファイルで,詳細関数の行に引数が指定されると,これらは実行時に直接関数に渡されます。
詳細関数は,stdin
を介して EVM のイベント・ストリームを受信し,各イベントの内容を説明するテキスト・ストリームを
stdout
に表示する必要があります。
出力を作成するときは,さまざまな形式の
evmshow
(特に
-x
と
-D
) が役に立ちますが,-d
オプションは使用しないように注意してください。
再帰的なループが発生する可能性があります。
stderr
に書き込まれたメッセージは,リダイレクトされない限り,evmshow
の
stderr
ストリームに出力されます。
必要な場合は,この関数によって書き込まれたことを明示的に記述してください。
新しいチャネルに対する詳細スクリプトを開発するためのモデルとして,evmlog
チャネル関数,/usr/share/evm/channels/evmlog/evmlog_details
が使用できます。
詳細関数を指定していないときには,evmshow
とイベント・ビューアは,詳細表示が要求されたときに,チャネルに属するイベントのダンプをフォーマットして表示します。
14.8.3 説明関数
説明関数は,evmshow
に
-x
オプションを指定して呼び出したときに実行されます。
現在は
evmshow
を実行するユーザの権限で実行されますが,今後のリリースでは変更される可能性があるため,適切なセキュリティ対策が重要になります。
この関数では,次の呼び出し構文を使用します。
function-name event-name [reference]
説明関数は,説明が必要なイベントの名前およびオプションの参照値を指定して呼び出します。
参照値を指定した場合は,イベントの参照データ項目の内容が参照されます。
参照値が利用できない場合は,evmshow
はこの引数としてハイフン (-) を渡しますが,この引数を省略することもできます。
説明関数は,引数を使用して,指定されたイベント名に対応するイベントの説明をフォーマットし,テキスト行として
stdout
に書き込みます。
説明が見つからない場合は,代わりに適切なメッセージを
stdout
に書き込みます。
stderr
に書き込まれたメッセージは,リダイレクトされない限り,evmshow
の
stderr
ストリームに出力されます。
このため,必要な場合は,この関数によって書き込まれたことを明示的に記述してください。
説明関数では,次の基準を満たす場合にだけ,evmlog
説明関数の
/usr/share/evm/channels/evmlog/evmlog_explain
を呼び出すことができます。
event-name
引数の他に,cat:
catalog-name[:
set_number] という形式の参照引数を渡す場合。
このとき,catalog-name
は,チャネルのイベントの説明が格納されている I18N カタログ・ファイルの名前であり,オプションの
set_number
は,説明が含まれるメッセージ・セットの番号です (たとえば
cat:myprod.cat:3
のようになります)。
カタログ内の各説明が,中カッコで囲まれたイベント名で開始している場合。
たとえば,{myco.myprod.myapp.startup}
。
メッセージ・カタログは,通常の I18N 規則に従って配置されていなければなりません。
検索時間を最小限に抑えるには,説明をいくつかのセットにグループ化し,イベントの参照データ項目にセット番号を指定します。
カタログ・ファイルを生成する手順については,
mkcatdefs
(1)gencat
(1)14.8.4 監視関数
監視関数は,EVM チャネル・マネージャによって実行されます。
チャネル・マネージャの起動時,およびチャネル・マネージャが
evmreload
によって再構成されたときは,引数
-init
が必要ですが,その後は引数
-init
を指定しないで定期的に実行されます。
実行期間は,チャネル値
mon_period
で制御されます。
この関数は,常に root として実行されるので,適切なセキュリティ対策が必要です。
この関数では,次の呼び出し構文を使用します。
function-name
[init
]
引数
init
が指定されているかどうかによって,この関数が管理している作業ファイルの初期化が必要かどうかが決定されます。
必要な場合には,チャネル構成ファイルの該当するコマンド行に引数を設定することにより,追加の引数を渡すことができます。
ただし,引数
init
は常に最後の引数として渡されることに注意してください。
監視関数によって実行されるアクションについて制限はありませんが,通常,このジョブでは,状態をチェックして,状態の変化を検出した場合はイベントを発信します。
この関数は,stdout
を指定せず,チャネル・マネージャのログ・ファイルに
stderr
を指定して呼び出します。
関数が
stderr
の再割り当てを行わない場合,ここに書き込まれるメッセージはすべて,チャネル・マネージャのログ・エントリと同じフォーマットになるので,そのチャネルから送られたこと明確に分かるようにする必要があります。
または,エラー・メッセージを EVM イベントとして送信し,関数が起動されるたびに同じ状態を不必要に通知することのないようにします。
次の監視スクリプトの例では,ログ・ファイルの行数をカウントし,そのカウントを状態ファイルに保存することにより,初期化を行っています。
後続の呼び出しでは,ファイルの行数を古い行数と比較し,新しい行を UNIX の
tail
コマンドで抽出してから,evmpost
を使用して EVM イベントとして発信します。
#! /bin/sh INIT=$1 STATE=/tmp/mylog.state LOG=/tmp/mylog EVENT_NAME=myco.admin.mylog.line_added # No log? Create one! if [ ! -f $LOG ] then touch $LOG fi # If we're initializing then save the current logfile # state and exit: if [ "$INIT" != "" ] then # Count the lines in the demolog, and save the count # in the state file: wc -l $LOG | awk '{print $1}' > $STATE exit fi # Find out how many lines there were in the file last time # we checked: OLDCOUNT=`cat $STATE` # How many now? NEWCOUNT=`wc -l $LOG | awk '{print $1}'` if [ $NEWCOUNT > $OLDCOUNT ] then # Save the new line count to the state file: echo $NEWCOUNT > $STATE # What's the difference between the old and new counts? diff=`expr $NEWCOUNT - $OLDCOUNT | awk '{print $1}'` # Post an event for each new line: tail -$diff $LOG | while read LINE do echo 'event { name '${EVENT_NAME} \ ' var {name msg type STRING value "'$LINE'"} }' | evmpost done fi
クリーンアップ関数は,EVM チャネル・マネージャによって毎日実行されます。 チャネル構成ファイルに指定されている時間に,チャネルのログ・ファイルの保管や削除などのハウスキーピング処理が行われます。 この関数は常に root として実行されるので,適切なセキュリティ対策が必要です。
クリーンアップ関数は,コマンド行として指定し,そのまま実行されます。
このため,必要に応じて,コマンド行から引数を渡すことができます。
この関数では,任意の必要なアクションを実行できます。
この関数は,stdout
を指定せず,チャネル・マネージャのログ・ファイルに
stderr
を指定して実行します。
このため,状態メッセージが必要な場合は,stderr
には書き込まずに,通常は
evmpost
を使用して EVM イベントの形式で発信します。
関数が
stderr
の再割り当てを行わない場合,ここに書き込まれるメッセージはすべて,チャネル・マネージャのログ・エントリと同じフォーマットになるので,そのチャネルから送られたことが明確に分かるようにする必要があります。
stdout
には何も書き込まないでください。
この関数は,実行する時間にかかわらず同じ結果が得られるように作成します。
たとえば,find
コマンドの
-mtime
オプションを使用して,保管するログ・ファイルを特定することがあります。
14.8.6 チャネルのセキュリティ
ほとんどの場合,チャネル関数は EVM デーモンの子プロセスによって実行されるため,完全な root 権限で実行されることになります。 このため,システムの一貫性を保持するために,次の点に従ってください。
制限された書き込み権限のあるディレクトリに配置する。
関数自体にも,制限された書き込みおよび実行権限を割り当てる。
この関数から,適切な権限が割り当てられていないほかのプログラムを呼び出さない。