Zabbix 2.2 イベントの詳細にトリガの説明(comments)を表示させる
Zabbixでログ監視を設定したのは良いものの,上がってきたイベントにはログが表示されてなくて,わざわざヒストリを見にいくのは不便だったので無理やり改造してみた.
改造の流れ
- 「トリガの設定」で「名前」にマクロ
{ITEM.VALUE}
を入れるだけで,「イベント詳細」画面左カラムにある「イベントソースの詳細」テーブルの「トリガー」行にログが表示される.- 悪くないけど「トリガ画面」の「名前」列の表示もログになってしまって微妙だったのでもう少し頑張ってみる.
- 「イベント詳細」画面左カラム「イベント詳細」テーブルに「イベント」行がある.
- デフォルトだとトリガの名前が入ってるけど,ここにログが表示されれば入れられれば収まりがよさそう.
- 「トリガの設定」に「説明」(comments)欄があるのでここにマクロ
{ITEM.VALUE}
を書いて,それが上の「イベント」行に表示されるようにしよう.
- 「トリガの設定」に「説明」(comments)欄があるのでここにマクロ
- デフォルトだとトリガの名前が入ってるけど,ここにログが表示されれば入れられれば収まりがよさそう.
改造内容
表示するデータを作っているinclude/events.inc.php
のmake_event_details()
内にある
CMacrosResolverHelper::resolveEventDescription
を
CMacrosResolverHelper::resolveTriggerDescriptions
あたりに変更したら行けそうにみえたけど,マクロ{ITEM.VALUE}
の変換結果が常に最新のログになってしまったので少し強引に改造.
events.php
--- events.php.ORG 2013-12-11 02:45:09.000000000 +0900 +++ events.php 2014-02-07 14:11:58.165892875 +0900 @@ -652,7 +652,7 @@ 'triggerids' => zbx_objectValues($events, 'objectid'), 'selectHosts' => array('hostid'), 'selectItems' => array('name', 'value_type', 'key_'), - 'output' => array('description', 'expression', 'priority', 'flags', 'url') + 'output' => array('description', 'expression', 'priority', 'flags', 'url', 'comments') )); $triggers = zbx_toHash($triggers, 'triggerid');
- トリガのデータを取得しているところで「説明」欄の内容も取得するように変更.
include/events.inc.php
--- include/events.inc.php.ORG 2013-12-11 02:45:05.000000000 +0900 +++ include/events.inc.php 2014-02-07 11:01:27.587964245 +0900 @@ -179,7 +179,13 @@ $config = select_config(); $table = new CTableInfo(); - $table->addRow(array(_('Event'), CMacrosResolverHelper::resolveEventDescription(array_merge($trigger, $event)))); + $trigger_for_comments = $trigger; + $trigger_for_comments['description'] = $trigger_for_comments['comments']; + + $table->addRow(array(_('Event'), CMacrosResolverHelper::resolveEventDescription(zbx_array_merge($trigger_for_comments, array( + 'clock' => $event['clock'], + 'ns' => $event['ns'] + ))))); $table->addRow(array(_('Time'), zbx_date2str(_('d M Y H:i:s'), $event['clock']))); if ($config['event_ack_enable']) {
- 「イベント詳細」画面左カラム「イベント詳細」テーブル「イベント」行を作成するところで内容を差し替える.
CMacrosResolverHelper::resolveEventDescription
が引数にとる配列のキーdescription
を変換していたので,これを変更する.- 他に影響が出ないように引数用の配列
$trigger
を別配列$trigger_for_comments
にコピー. - 配列
$trigger_for_comments
のキーdescription
をキーcomments
で上書き.- キー
comments
は上記events.php
の改造で使えるようになっている.
- キー
- 他に影響が出ないように引数用の配列
CMacrosResolverHelper::resolveEventDescription
の引数を配列$trigger_for_comments
に変更.
おまけ
「最新のイベント」画面の「説明」カラムにトリガの「説明」を表示させる
--- events.php.ORG 2013-12-11 02:45:09.000000000 +0900 +++ events.php 2014-02-07 14:11:58.165892875 +0900 @@ -702,6 +702,16 @@ 'ns' => $event['ns'] ))); + $trigger_for_comments = $trigger; + $trigger_for_comments['description'] = $trigger_for_comments['comments']; + + $comments = CMacrosResolverHelper::resolveEventDescription(zbx_array_merge($trigger_for_comments, array( + 'clock' => $event['clock'], + 'ns' => $event['ns'] + ))); + + $description = $comments; + $triggerDescription = new CSpan($description, 'pointer link_menu'); $triggerDescription->setMenuPopup(getMenuPopupTrigger($trigger, $triggerItems, null, $event['clock']));
表示できるようにしたログが20バイトで切られてしまっていたので1024バイトまで表示されるようにする
--- include/items.inc.php.ORG 2013-12-11 02:45:05.000000000 +0900 +++ include/items.inc.php 2014-02-07 11:43:03.020497499 +0900 @@ -989,8 +989,8 @@ // break; is not missing here case ITEM_VALUE_TYPE_TEXT: case ITEM_VALUE_TYPE_LOG: - if ($trim && zbx_strlen($value) > 20) { - $value = zbx_substr($value, 0, 20).'...'; + if ($trim && zbx_strlen($value) > 1024) { + $value = zbx_substr($value, 0, 1024).'...'; } if ($mapping !== false) {
ZWSでCGI
http://support.zeus.com/ZWSUserGuide.pdf を自分用にまとめ
ZWSも基本はCGIスクリプトの場所指定
- CGIスクリプト用の特別なディレクトリをConfiguring Aliases for CGI Script DirectoriesからZWSに設定する.
- Configuring Aliases for CGI Script Directories≒ApacheのScriptAlias
任意のディレクトリでCGIスクリプトを実行
You can choose whether to enable CGI scripts to run in any directory, or whether to confine them to specified directories. If they can be run from any directory then CGI scripts are identified using the application/x-httpd-cgi MIME type.
ApacheでCGI
http://httpd.apache.org/docs/2.2/howto/cgi.html を自分用にまとめ
基本はScriptAlias
ScriptAlias
ScriptAlias /cgi-bin/ /usr/local/apache2/cgi-bin/
- /cgi-bin/で始まるリソースへのリクエストは,ディレクトリ/usr/local/apache2/cgi-bin/にマップしてCGIプログラムとして扱うようApacheに示している.
- URL http://www.example.com/cgi-bin/test.pl が要求された場合,Apacheはファイル/usr/local/apache2/cgi-bin/test.plを実行してその出力を返すことを試みる.
- Aliasディレクティブとかなり似ている.
- AliasとScriptAliasは通常,DocumentRootディレクトリ外のディレクトリのために使用される.
- AliasとScriptAliasの違いは,ScriptAliasが接頭辞で始まるすべてのURLをCGIプログラムとみなすという追加の意味を含んでいること.
ScriptAliasディレクトリ外のCGI
- 任意のディレクトリでCGIの実行を許可するには二段階の設定が必要になる.
- AddHandlerやSetHandlerディレクティブによってcgi-scriptハンドラを使用可能にする.
- どのファイルがCGIファイルかをApacheに伝えている.
- OptionsディレクティブでExecCGIを指定する.
- 特定のディレクトリ配下でCGIの実行を許可している.
- AddHandlerやSetHandlerディレクティブによってcgi-scriptハンドラを使用可能にする.
AddHandler
AddHandler cgi-script .cgi
- 拡張子extensionが名前にあるファイルを指定されたhandler-nameで扱うようApacheに設定する. マッピングは既にある他のマッピングに追加され,同じ拡張子extensionのマッピングを上書きする.
- 上記の例は拡張子".cgi"で終わるファイルをCGIスクリプトとして扱う設定.
SetHandler
SetHandler cgi-script
- .htaccessやDirectoryセクション,Locationセクションに書かれた場合,このディレクティブはそこにあるすべてのファイルがhandler-nameで指定されたハンドラで扱われることを強制する.
- SetHandlerはデフォルトのハンドラをオーバーライドするので,通常の挙動,たとえば,スラッシュで終わるURLがリクエストされたときにディレクトリやインデックスファイルを返すような挙動が行われなくなる.
- 上記の例はすべてCGIスクリプトとして扱う設定
ExecCGI
<Directory /usr/local/apache2/htdocs/somedir> Options +ExecCGI </Directory>
- mod_cgiによるCGIスクリプトの実行を許可する.
- 上記の例では/usr/local/apache2/htdocs/somedir配下でCGIの実行を許可している.
その他
- CGI
- Common Gateway Interface. ウェブサーバが外部プログラムと協調して動作するための方法を定義している.
- ハンドラ
- ファイルが呼ばれたときに実行される動作のApacheにおける内部表現.
- 通常,ファイルにはファイルタイプに基づいた暗黙のハンドラがある.
- すべてのファイルは単にサーバに扱われるが,ファイルタイプの中には別に「ハンドル(扱う)」されるものもある.
- ファイルタイプに関係なくファイルの拡張子や置いている場所に基づいて明示的にハンドラを指定することもできる.
- ファイルにタイプとハンドラの両方を関連付けることができるという点で優れている.
- ハンドラはサーバに組み込んだり,モジュールとして含めたりして追加することができる.
- mod_cgi/cgi-scriptハンドラ
- cgi-scriptハンドラが指定されているファイルはCGIスクリプトとして扱われ実行される.
- ファイルはAddHandlerディレクティブに指定された拡張子を名前に含むか, ScriptAliasディレクトリに存在することによりこのハンドラになる.
- 後方互換性のため,MIMEタイプがapplication/x-httpd-cgiのファイルにも CGIスクリプトのハンドラが有効になる.
- この独自MIMEタイプの利用は非推奨.
トランザクション分離レベル
じぶんなりにまとめてみた
トランザクション分離レベル
SERIALIZABLE
REPEATABLE READ
- 同じトランザクション中では同じデータは何度読み取りしても毎回同じ値を読むことができる
- ただしファントム・リードが発生する可能性がある
READ COMMITTED
- 他のトランザクションによる更新については,常にコミット済みのデータのみを読み取る
- MVCCはREAD COMMITTEDを実現する実装の一つ
- ファントム・リード に加え,非再現リードが発生する可能性がある
READ UNCOMMITTED
- 他の処理によって行われている、書きかけのデータまで読み取る
- ファントム・リード,非再現リードさらにダーティ・リードが発生する可能性がある
ファントム・リード
- 並行して動作する他のトランザクションが追加したり削除したデータが途中で見えてしまう現象
非再現リード
- 同じトランザクション中でも同じデータを読み込むたびに値が変わってしまう現象
ダーティ・リード
- 確定前の不完全なデータや,計算途中のデータを読み取ってしまう現象
トランザクション分離レベルと発生する現象の表
分離レベル | ファントム・リード | 非再現リード | ダーティ・リード |
---|---|---|---|
SERIALIZABLE | 発生しない | 発生しない | 発生しない |
REPEATABLE READ | 発生する | 発生しない | 発生しない |
READ COMMITTED | 発生する | 発生する | 発生しない |
READ UNCOMMITTED | 発生する | 発生する | 発生する |
これらの分離レベルを実現するため暗黙的にロックが行われているはずだけど,ステートメントに応じてどのような暗黙的ロックが行われるのかはデータベースマネジメントシステムの実装による(と思う)
用語
MVCC
- MultiVersion Concurrency Control(多版型同時実行制御)
- データベース管理システムの可用性を向上させる制御技術のひとつ
- 複数同時に処理要求が行われた場合でも同時並行性を失わずに処理し,かつ情報の一貫性を保証する仕組み
- READ COMMITTEDを実現する実装の一つ
疑問とか
SLELECT, UPDATE, DELETEはレコードが存在しているので挙動を想像しやすいが,トランザクション開始時点でレコードの存在しないINSERTは挙動が想像しにくい たとえば,分離レベルがSERIALIZABLEである複数トランザクションから同一キーをを持つレコードをINSERTしようとした時はどのような挙動になるだろう?
推測
以下の観点から考えてみた
- 後続トランザクションから
こたえあわせ
- 先行トランザクション開始
mysql> use isolation_test Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> set session transaction isolation level serializable; Query OK, 0 rows affected (0.00 sec) mysql> start transaction; Query OK, 0 rows affected (0.00 sec) mysql> select @@tx_isolation; +----------------+ | @@tx_isolation | +----------------+ | SERIALIZABLE | +----------------+ 1 row in set (0.00 sec)
- 後続トランザクション開始
mysql> use isolation_test Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> set session transaction isolation level serializable; Query OK, 0 rows affected (0.00 sec) mysql> start transaction; Query OK, 0 rows affected (0.00 sec) mysql> select @@tx_isolation; +----------------+ | @@tx_isolation | +----------------+ | SERIALIZABLE | +----------------+ 1 row in set (0.00 sec) mysql>
- 先行トランザクションでレコードをINSERT
mysql> insert into id_tbl values (1, 'taro'); Query OK, 1 row affected (0.00 sec) mysql> select * from id_tbl; +----+------+ | id | name | +----+------+ | 1 | taro | +----+------+ 1 row in set (0.00 sec)
- 後続トランザクションでSELECT
mysql> select * from id_tbl; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
ファントム・リードが起きていないことの確認のつもりだったが,ブロックされてしまった
- 後続トランザクションで同じキーをもつレコードをINSERT
mysql> insert into id_tbl values (1, 'taro');
予想通り待たされる
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
これも予想通り制約違反となった
ちょっと深追い
概ね予想通りだったが,後続トランザクションでSELECTがブロックされたのが気になったので調べてみた
mysql> select * from information_schema.innodb_trx order by trx_id\G *************************** 1. row *************************** trx_id: 1817 trx_state: RUNNING trx_started: 2013-06-25 20:06:39 trx_requested_lock_id: NULL trx_wait_started: NULL trx_weight: 3 trx_mysql_thread_id: 24 trx_query: select * from information_schema.innodb_trx order by trx_id trx_operation_state: NULL trx_tables_in_use: 0 trx_tables_locked: 0 trx_lock_structs: 2 trx_lock_memory_bytes: 376 trx_rows_locked: 1 trx_rows_modified: 1 trx_concurrency_tickets: 0 trx_isolation_level: SERIALIZABLE trx_unique_checks: 1 trx_foreign_key_checks: 1 trx_last_foreign_key_error: NULL trx_adaptive_hash_latched: 0 trx_adaptive_hash_timeout: 10000 trx_is_read_only: 0 trx_autocommit_non_locking: 0 *************************** 2. row *************************** trx_id: 1818 trx_state: LOCK WAIT trx_started: 2013-06-25 20:07:11 trx_requested_lock_id: 1818:6:3:4 trx_wait_started: 2013-06-25 20:07:11 trx_weight: 3 trx_mysql_thread_id: 25 trx_query: select * from id_tbl trx_operation_state: fetching rows trx_tables_in_use: 1 trx_tables_locked: 1 trx_lock_structs: 3 trx_lock_memory_bytes: 376 trx_rows_locked: 3 trx_rows_modified: 0 trx_concurrency_tickets: 0 trx_isolation_level: SERIALIZABLE trx_unique_checks: 1 trx_foreign_key_checks: 1 trx_last_foreign_key_error: NULL trx_adaptive_hash_latched: 0 trx_adaptive_hash_timeout: 10000 trx_is_read_only: 0 trx_autocommit_non_locking: 0 2 rows in set (0.00 sec)
mysql> select * from information_schema.innodb_locks order by lock_id\G *************************** 1. row *************************** lock_id: 1817:6:3:4 lock_trx_id: 1817 lock_mode: X lock_type: RECORD lock_table: `isolation_test`.`id_tbl` lock_index: PRIMARY lock_space: 6 lock_page: 3 lock_rec: 4 lock_data: 3 *************************** 2. row *************************** lock_id: 1818:6:3:4 lock_trx_id: 1818 lock_mode: S lock_type: RECORD lock_table: `isolation_test`.`id_tbl` lock_index: PRIMARY lock_space: 6 lock_page: 3 lock_rec: 4 lock_data: 3 2 rows in set (0.00 sec)
先行トランザクションにより対象テーブルがロックされていてSELECTがブロックされているのかと思ったが,実際は先行トランザクションが排他ロックしたレコードを後続トランザクションが共有ロックしようとして競合しロック獲得待ちになっていた
CentOS 6.3にMySQL 5.6インストールでmysql-libs-5.1.61-4.el6.x86_64と競合する問題
CentOS 6.3にMySQL 5.6のLinux GenericなRPMをインストールしようとすると,
# rpm -ivh MySQL-server-5.6.12-1.linux_glibc2.5.x86_64.rpm 準備中... ########################################### [100%] ファイル /usr/share/mysql/charsets/README (パッケージ MySQL-server-5.6.12-1.linux_glibc2.5.x86_64 から) は、パッケージ mysql-libs-5.1.61-4.el6.x86_64 からのファイルと競合しています。 ファイル /usr/share/mysql/czech/errmsg.sys (パッケージ MySQL-server-5.6.12-1.linux_glibc2.5.x86_64 から) は、パッケージ mysql-libs-5.1.61-4.el6.x86_64 からのファイルと競合しています。 ※※※ 中略 ※※※ ファイル /usr/share/mysql/charsets/macroman.xml (パッケージ MySQL-server-5.6.12-1.linux_glibc2.5.x86_64 から) は、パッケージ mysql-libs-5.1.61-4.el6.x86_64 からのファイルと競合しています。 ファイル /usr/share/mysql/charsets/swe7.xml (パッケージ MySQL-server-5.6.12-1.linux_glibc2.5.x86_64 から) は、パッケージ mysql-libs-5.1.61-4.el6.x86_64 からのファイルと競合しています。
のような感じで元から入っているMySQL 5.1の共有ライブラリと競合してしまう.
この共有ライブラリを一旦消して入れなおそうにも
# rpm -e mysql-libs-5.1.61-4.el6.x86_64 エラー: 依存性の欠如: libmysqlclient.so.16()(64bit) は (インストール済み)postfix-2:2.6.6-2.2.el6_1.x86_64 に必要とされています libmysqlclient.so.16(libmysqlclient_16)(64bit) は (インストール済み)postfix-2:2.6.6-2.2.el6_1.x86_64 に必要とされています mysql-libs は (インストール済み)postfix-2:2.6.6-2.2.el6_1.x86_64 に必要とされています
# rpm -e postfix-2.6.6-2.2.el6_1.x86_64 エラー: 依存性の欠如: /usr/sbin/sendmail は (インストール済み)cronie-1.4.4-7.el6.x86_64 に必要とされています /usr/sbin/sendmail は (インストール済み)redhat-lsb-4.0-3.el6.centos.x86_64 に必要とされています
依存性にはばまれて中々めんどくさい.
この問題を以下のようにして解決できたのでメモ.
MySQL 5.6の互換共有ライブラリをインストール
# rpm -ivh MySQL-shared-compat-5.6.12-1.linux_glibc2.5.x86_64.rpm 準備中... ########################################### [100%] 1:MySQL-shared-compat ########################################### [100%]
「互換」がポイント. rpm -qiしてみると
This package includes the shared client libraries for previous MySQL versions. Install this package, if you have applications that are dynamically linked against older versions of the MySQL client library and you want to upgrade to MySQL 5.6.12 without breaking the library dependencies.
と書かれていて,まさにって感じ.
MySQL 5.1の共有ライブラリを削除
# rpm -e mysql-libs-5.1.61-4.el6.x86_64 #
MySQLクライアント向けの共有ライブラリをMySQL 5.6の互換共有ライブラリに置き換えたことで,元から入っていたMySQL 5.1の共有ライブラリに対する依存性が解消されている.
MySQL 5.6 Serverのインストール
競合していたパッケージを削除できたので,あとはインストールするだけ
# rpm -ivh MySQL-server-5.6.12-1.linux_glibc2.5.x86_64.rpm 準備中... ########################################### [100%] 1:MySQL-server ########################################### [100%] ※※※ 後略 ※※※
カーディナリティが多対多の概念データモデルがなぜ関係モデルとして論理データモデルに変換できないか
今読んでいる本に
「多対多のリレーションシップが存在すると、そのままでは関係モデルとして取り扱うことができません。」
とだけ書かれていて,よくわからなかったので自分なりに考えてみた.
前提
- まずいろいろ考えてて以下のことに気づいた
関係モデルとして概念データモデルを論理データモデルへの変換する時,エンティティ間のリレーションシップは共通の属性を持つことで表現する
- 次にリレーションシップのカーディナリティが多対多となる概念データモデルを考えてみる
- エンティティ「売上」
- 属性「売上番号」
- 属性「売上日」
- エンティティ「商品」
- 属性「商品コード」
- 属性「商品名」
- 売上に複数の商品が含まれることも,商品が複数の売上に含まれることもあるので
エンティティ「売上」とエンティティ「商品」間のリレーションシップのカーディナリティは多対多になる.
- エンティティ「売上」
エンティティ「売上」に属性「商品コード」を持つことでリレーションシップを表現する場合の関係モデル
売上番号 | 売上日 | 商品コード |
---|---|---|
001 | 2013-06-05 | Item017 |
Item044 | ||
Item057 |
- 一つの売上に複数の商品が含まれる場合に商品コードのところがおかしなこと(非単純定義域)になってしまう.
エンティティ「商品」に属性「売上番号」を持つことでリレーションシップを表現する場合の関係モデル
商品コード | 商品名 | 売上番号 |
---|---|---|
Item017 | おもち | 001 |
007 | ||
059 |
- 一つの商品が複数の売上に含まれる場合に売上番号のところがおかしなこと(非単純定義域)になってしまう.
というわけで,たしかにそのままだと関係モデルとして扱えないことがわかった.
おまけ
- 関係モデルとして概念データモデルを論理データモデルへ変換する際,リレーションシップを表現するために共通の属性を持つときは
「多」側のエンティティに「1」側の属性を持つ
ようにする. (非単純定義域のことを考えると当たり前なんだけど,この当たり前がイメージできなかった…)
nginxのエラーログ
Note that error_log off does not disable logging - the log will be written to a file named "off". To disable logging, you may use:
error_log /dev/null crit;
オフにできないからレベルを上げたうえで/dev/nullに捨てるのかぁ.