2012年3月25日日曜日

Zabbixがうまく動かないときに参考になる情報

Zabbixがうまく動かない!というときに原因を調べる方法や参考になるサイトや資料、本家にバグ報告を行う方法までをまとめてみました。こういった情報はあまりまとまったものがないので、思ったように動かない、パフォーマンスが出ない、他の人はどうしてるんだろう?、バグのような気がするんだけど…という時に参考にして頂ければと思います。

Googleなどを使ってネットを検索する

オープンソースのソフトウェアの場合は最も一般的な方法です。IT系のサイトの記事や個人のブログなどで問題の解決方法が書かれている場合もあるので、うまく検索にヒットする場合は解決策が見つかる可能性が高いと思います。

ただ、Zabbixの場合はZabbix SIAやZABBIX-JPのサイトに情報が集中していると思います。Googleなどで検索をかけるよりも、各サイトのフォーラムやドキュメントなどを見る方が効率的な場合も多いです。

ドキュメントを読む

監視の設定が合っているかどうか分からない、というような場合はまずドキュメントを見てみましょう。Zabbixの公式ドキュメントは以下のURLで公開されています。

英語版は日々更新されていますので、以前見つからなかった場合でも改善されている可能性もあります。日本語版は後から追随する形になるので、日本語版になくても英語版には記載がある可能性もあります。

英語のドキュメントは…という人も、勉強だと思って根気よく読んでみることをお勧めします。オープンソースソフトウェアを利用するには、英語のドキュメントに慣れることは重要です。

フォーラムとサポートシステムの投稿を検索する

英語、日本語ともにコミュニティのフォーラムには活発に投稿があるので、フォーラムを検索することで同じ問題を抱える人やその回答が見つかるかもしれません。

また、Zabbix SIAにはサポートシステムがあり、バグ報告や新機能の追加要望などはこちらで管理されています。

アカウントの作成は自由にできますので、気になるバグ報告があればログインしてウォッチしておくことで更新時にメールを受け取ることができます。

また、サポートシステムで重要だと思うバグ報告や、欲しいと思う機能改善/追加要望があればぜひVote(投票)をしておいてください。投票の数が多いほど実現の可能性が高くなります。

書籍を参考にする

手前味噌ですが、Zabbixの書籍を執筆しています。こちらにも参考になる情報を記載していますので、試しに書店で手に取ってみて頂ければと思います。

ログをじっくり見る

基本中の基本ではあるのですが、ソフトウェアのログは英語で出力されることがほとんどなので、意外と見落としがちです。

コンパイル時の問題であればコンパイルのログにエラーが出力されます。人によっては意味不明なエラーに見えるかもしれませんが、前後のログも含めて少しじっくり見てみてください。意外と重要なエラーを見落としていることもよくあります。エラーメッセージでネット検索をかけてみるのも良い方法です。

Zabbixの監視設定でつまづいた時も、ZabbixサーバやZabbixエージェントのログを確認してみてください。Zabbixの場合、監視設定がWebインターフェースなので忘れがちですが、実際に監視の処理を行っているのはOS上のプロセスなので、ログに重要なエラーが出力されているかもしれません。

ちなみに、Zabbixに関連のあるログは以下の4つです。

  • Zabbixサーバのログ: /var/log/zabbix/zabbix_server.log
  • Zabbixエージェントのログ: /var/log/zabbix/zabbix_agentd.log
  • Zabbixプロキシサーバのログ: /var/log/zabbix/zabbix/_proxy.log
  • Webインターフェース関連のログ: /var/log/httpd/error.log

フォーラムに投稿する

フォーラムで同じ投稿が見つからなければ、質問を投稿してみるのもコミュニティへの参加の1つです。その際、以下のことに気をつけて投稿すると良い回答をもらえる可能性が高いと思います。

  • 同じ質問がすでに投稿されていないか、まずは検索してみる。
  • 利用しているZabbixのバージョンや、問題が発生する設定の内容、必要な場合は利用しているOSや環境の説明を書くこと。回答する人はすべての環境やパターンを知っているわけではありません。
  • まずは自分で試してみた上で、その結果、問題が出ている箇所を質問すること。可能性があるすべてのことを回答するのは手間がかかりますし、場合によっては非現実的です。

公開フォーラムで質問をするということは、同じ問題に遭遇した人の助けになるということでもあります。他の人の参考になることも考えて、具体的に状況を書いた方が良いです。また、フォーラムの支援を受けて最終的に解決したかどうか、そのときの設定や解決方法なども投稿すれば、それは他のユーザの有用な情報になります。

デバッグログを出力する

Zabbixはデバッグログを出力できるようになっています。Zabbixエージェント、サーバ、プロキシサーバの各プロセスは、設定ファイルで以下のように設定して再起動するとでバッグログを出力できます。

DebugLevel=4

内部で実行している関数の実行状況や、重要な変数のデータ、実行しているSQLクエリなどがログに出力されるようになり、デバッグログを参照することでどこで問題が発生しているかを特定できる可能性があります。

Webインターフェースでも以下の手順でデバッグログを出力できます。

  • ユーザーグループの設定でデバッグモードを有効にする
  • デバッグモードを有効にしたユーザーグループに所属するユーザーでログイン
  • 右上の「デバッグ」のリンクをクリック

すると、今表示している画面を出力する際にかかった時間や利用したメモリ容量、実行したSQLと要した時間などが表示できます。Webインターフェスのパフォーマンスが悪いといった場合に有用な情報を得ることができます

ソースコードを読む

オープンソースであることの一番のメリットは、誰でもソースコードを読めることです。当然ですが、ソフトウェアはソースコード以外のものからは出来ていないので、問題解決にあたってソースコードを読まない手はないと思います。

ログやデバッグログなどである程度問題個所の特定ができれば、ソースコードを調べればソフトウェアそのものが原因なのか、それとも外部の要因(環境依存、利用しているライブラリの問題)なのかが明確に分かります。内部の動きを知ることで、より深くZabbixを理解することもできますので、問題の調査のときは参照してみると良いと思います。

一般的にオープンソースのソフトウェアに仕様書はありません。だいたいの場合、定められたコーディングルールに沿って実現する機能を実装し、途中でレビューを入れながら細かく修正を入れていく、というスタイルだと思いますし、Zabbixもそのように開発されています。ドキュメントは出来上がったソフトウェアの動きをベースに作成されています。

つまりは今あるソースコードが仕様書なわけで、最新のドキュメントであり、それが全てです。ソースコードを読めるかどうかはオープンソースソフトウェアを利用する上で、問題解析にあたって大きな差が出てくると思います。

バグ報告や機能改善要望を送る

オープンソースソフトウェアというのはバグ出しや機能改善要望をユーザーと一緒にやっていくところに面白さがあると思いますし、そのプロセスがとても重要だと思います。開発側はユーザーからのフイードバックをダイレクトに受けられますし、ユーザー側は開発に協力したり、リクエストを出してそのフィードバックがすぐに受けることができます。

マニュアルを見た、ログも確認した、コミュニティフォーラムにも解決方法はない、だけど、どうにも動きがおかしい。というときはバグの第一発見者である可能性があります。可能であればデバッグログを出してみたり、ソースを読んでみるとバグかどうか確実性が高まると思います。

多分これはバグだ!となれば、ぜひZabbix SIAにバグ報告をしてみましょう。誰かがバグ報告をしなければその問題は永遠に直らないかもしれませんし、バグ報告できるのは第一発見者の特権です。パッチを付けて取り込まれた場合はリリースノートに名前を載せてもらえます。

Zabbix SIAへのバグ報告は上にも書いたサポートシステムから行います。サポートシステムへの投稿は必ず英語でお願いします。これは投稿の文章もそうですが、スクリーンショットを取るときの画面の言語、ログに含まれる言語などにも注意してください。ちなみに日本語はダメですが、ラトビア語かロシア語なら大丈夫です。

バグ報告の場合はZABBIX BUGS AND ISSUES(ZBX)に、新規機能追加要望の場合はZABBIX FEATURE REQUESTS(ZBXNEXT)に投稿します。

バグ報告するときは、上の「フォーラムに投稿するときの注意点」と同様のことに注意することと、加えて以下のことにも注意しておくと良いです。

  • 問題の内容を簡潔に書く。(1)どのような環境/操作/設定のときに、(2)どのような動作をする。(3)どのような点が問題で、(4)どのようにするのが良いか。といった形で書くのが良いと思います。箇条書きで良いので簡潔に、分かりやすく。
  • ある程度の大きさのパッチを作成する場合、Zabbixのコーディングルールに従うようにする
  • 仕様が大きく変わるようなパッチの作成はできるだけ避ける
  • どうしても仕様が変わらざるを得ない問題の場合、説明をより詳細に書いてディスカッションする

基本的に、他の部分にも影響が出るようなパッチは簡単には取り込まれませんし、取り込まれるとしても時間がかかります。大きな修正を取り込む場合、他に良い修正方法がないか検討する必要も出てきますし、他の機能への影響やテストも必要になります。大きめのパッチを投稿するような場合は、ディスカッションをより重視した方が良いです。

Zabbix SIAのエンジニアとコミュニケーションを取る

バグ報告するにあたってコミュニケーションも重要と書きましたが、Zabbix SIAのエンジニアと直接コミュニケーションを取るにあたり、一番リアルタイムにレスポンスがもらえるのはIRCでチャットすることです。

Zabbixの公式IRCチャネルがfreenodeサーバのzabbixグループにあり、誰でも参加できます。常に100人程度のユーザが参加していますし、Zabbix SIAの開発者や世界中のアクティブなZabbixコミュニティメンバーが集まっています。

発言しなくても参加してみるだけでも有益な情報が得られて面白いと思います。あまり発言は多くないですが、私も昼間は基本的にログインしています。

バグ報告/機能追加要望をしてみたい!という人に

Zabbix SIAに直接バグ報告や機能追加要望をしてみたい、けど自信が無い、という場合は以下の方法で誰か詳しい人にコンタクトを取ってみてください。Zabbixのコミュニティは親切な人が多いので、誰かが手助けしてくれると思います。

  • ZABBIX-JPフォーラムに投稿する
  • Twitterで#zabbixまたは#zabbix_jpハッシュタグをつけてつぶやく
  • Twitterで私の個人アカウント@kodai74、もしくはZabbix SIA公式日本語アカウント@zabbix_jpに聞いてみる

IRCで私にダイレクトメッセージを送ってもらっても構いません。バグ報告やパッチ投稿の手助けも何かしらできると思いますので気軽にご連絡ください。

「Zabbixのバグを見つけたけど、誰かがバグ報告して修正されるまで待っていよう」というよりは、小さなものでも、パッチがなくても良いので開発元に報告することがオープンソースの活動への参加と貢献につながると思います。

2012年3月5日月曜日

Zabbix SIAが仮想環境の監視機能のスポンサーシップを募集

この記事はZabbix SIAのblogの翻訳です。原文はDevelopent sponsorship of VM environment supportを参照ください。


現行バージョンのZabbixでも仮想化環境の監視を行うことは可能ですが、そのためには監視のための設定に時間がかかり、Zabbixと統合されたものにはなりません。

現在、VMware, Xen, KVM (可能であれば他の仮想環境も)に対応し、ハイパーバイザーとゲストOSの双方のステータスを簡単に監視できる、より統合された仮想環境の監視機能の開発を検討しています。

現在の一般的なアプローチはZabbixエージェントを各ゲストOSにインストールして監視する方法です。これは仮想環境特有のステータスやハイパーバイザーレベルのステータスを監視することが難しく、外部チェックやユーザパラメーター、Zabbix senderを利用する必要があります。この方法は悪くはありませんが、Zabbixのネイティブな監視方法ではありませんし、大規模なシステムではパフォーマンスが悪くなる場合があります。

検討を行っている機能には以下のものが含まれます:

  • VMware, Xen, KVMをサポート
  • ハイパーバイザーのAPIを利用して、ハイパーバイザー自体とゲストOSのステータスを監視
  • ZabbixのフロントエンドからゲストOSの管理

しかしながら、よりパワフルで簡単に監視できるような機能を実装するための支援が必要です。もし仮想環境の監視機能の開発のスポンサーシップに興味のある会社をご存知でしたら、ぜひ教えてください。

すでに数社がこのスポンサーシップに興味を持って頂いていますが、この機能を2.2で実装するためにはより多くの支援が必要です。スポンサーシップ企業には以下のメリットがあります。

  • 仕様策定への参加
  • 開発状況の通知と共有
  • 開発バージョンの早期テスト
  • 実装された機能へのフィードバックと議論
  • 共同マーケティングの機会

もしスポンサーシップへ興味を持って頂けたら、sales /at/ zabbix /dot/ comへメールを送付いただくか、問い合わせフォームからご連絡ください。より詳細なプランをお送りします。


日本の企業向けには日本語で対応も可能です。興味のある企業様はぜひご連絡ください!

2012年2月15日水曜日

Zabbixのlog[]とlogrt[]キーの動作

Zabbixにはログ監視用のアイテムとしてlog[]とlogrt[]キーがあります。ともにテキストベースのログファイルを監視し、1行を1データとしてZabbixサーバに送付、文字列マッチを行って障害判定をすることができます。

これらのキーを使ったときに、Zabbix内部ではどのような動作をしているのかというのが見えにくいですし、ログ関係はZABBIX-JPのフォーラムでもよく質問があります。私自身、質問を受けるたびに何度もソースコードを調べている気がするので、一度まとめておこうと思います。

解説に利用しているソースコードは1.8.10です。間違っていたらコメントでご指摘いただけると助かります。

log[]キーの動き

log[]キーはZabbix 1.1から追加されれいるログ監視用のキーです。1.6まではログ監視をするにはこのキーを利用する以外の手段はありませんでした。アイテムのキーには以下のように実際に監視するファイル名をそのままオプションに設定します。

log[file_path,regexp,encoding,maxlines]

regexp以降は1.8で追加されたオプションです。単純にファイルを監視するだけであれば、以下のように設定できます。

log[/var/log/messages]

logキーの処理はソースコードのsrc/zabbix_agent/logfiles.cの598行目から始まるprocess_log()関数で定義されています。

/* handling of file shrinking */
if (0 != zbx_stat(filename, &buf))
{
    zabbix_log(LOG_LEVEL_WARNING, "cannot stat [%s]: %s", filename, zbx_strerror(errno));
    return ret;
}

ここでファイルをの状態を取得し、

if (buf.st_size < *lastlogsize)
    *lastlogsize = 0;

ここでファイルのサイズがlastlogsizeよりも小さければ、lastlogsizeを0に設定しています。

lastlogsizeというのはログファイルをどこまで読んだかを記録しておく変数で、つまり、前回読んだバイト数よりもファイルが小さくなっていれば、ファイルが新規作成もしくはローテートされたと判断して、ファイルを先頭から読みにいくようになっています。

if (-1 == (f = zbx_open(filename, O_RDONLY)))
{
    zabbix_log(LOG_LEVEL_WARNING, "cannot open [%s]: %s", filename, zbx_strerror(errno));
    return ret;
}

ファイルをREADONLYでオープンし、

if ((off_t)-1 != lseek(f, (off_t)*lastlogsize, SEEK_SET))
{
    if (-1 != (nbytes = zbx_read(f, buffer, sizeof(buffer), encoding)))
    {
        if (0 != nbytes)
        {
            *lastlogsize += nbytes;
            *value = convert_to_utf8(buffer, nbytes, encoding);
            zbx_rtrim(*value, "\r\n ");
        }
        ret = SUCCEED;
    }
    else
        zabbix_log(LOG_LEVEL_WARNING, "cannot read from [%s]: %s", filename, zbx_strerror(errno));
}
else
    zabbix_log(LOG_LEVEL_WARNING, "cannot set position to [%li] for [%s]: %s", *lastlogsize, filename, zbx_strerror(errno));

close(f);

lastlogsize以降の文字列をutf8に変換しながら読み込み、読んだバイト分lastlogsizeを増加させ、ファイルをクローズしています。このときbufferのサイズはMAX_BUFFER_LENで定義されている65536B=64KBなので、それを超えない行末までを1度に読み込んでいます。

ここでvalueに読み込まれた文字列とlastvalueの値は最終的にソースのsrc/zabbix_agent/active.cの753行目あたりからの処理

while (SUCCEED == (ret = process_log(filename, &lastlogsize, &value, encoding)))
{
    if (NULL == value) /* End of file. The file could become empty, must save `lastlogsize'. */
    {
        active_metrics[i].lastlogsize = lastlogsize;
        break;
    }

    if (SUCCEED == regexp_match_ex(regexps, regexps_num, value, pattern, ZBX_CASE_SENSITIVE))
    {
        send_err = process_value(server, port, CONFIG_HOSTNAME,
                active_metrics[i].key_orig, value, &lastlogsize,
                NULL, NULL, NULL, NULL, NULL, 1);
        s_count++;
    }
    p_count++;

    zbx_free(value);

    if (SUCCEED == send_err)
        active_metrics[i].lastlogsize = lastlogsize;
    else
    { /* buffer is full, stop processing active checks till the buffer is cleared */
        lastlogsize = active_metrics[i].lastlogsize;
        goto ret;
    }

    /* do not flood Zabbix server if file grows too fast */
    if (s_count >= (maxlines_persec * active_metrics[i].refresh))
        break;

    /* do not flood local system if file grows too fast */
    if (p_count >= (4 * maxlines_persec * active_metrics[i].refresh))
        break;
} /* while processing a log */

でvalueの値はprocess_value()関数に処理され、lastvalueの値はactive_metrics配列にセットされています。active_metrics配列にはZabbixサーバから取得したアクティブチェックのアイテム設定が入っています。これらの値は最終的にZabbixサーバに送付され処理されます。

このwhile部分は1回の監視処理で1度呼ばれ、gotoまたはbreakが呼ばれるまで繰り返しprocess_log()関数を実行して64KBづつファイルを読んでいます。

ループを抜ける条件としては、

  • ログファイルの末尾まで読む
  • Zabbixエージェントのバッファ(Zabbixサーバに送信前のデータを溜めておくもの)が一杯になる
  • s_count(Zabbixサーバに送付する行数)がmaxlinex_persec * アイテムの監視間隔(秒)に達する
  • p_count(読み込んだログの行数)が4 * maxlinex_persec * アイテムの監視間隔(秒)に達する

のいずれかです。ログの途中で終了した場合は次の監視の時に続きから読みます。

maxlines_persecはlog[]キーのmaxlinesパラメータで指定された値か、zabbix_agentd.confのMaxLinesPerSecondパラメータで指定された値を使用します。

logrt[]キーの動き

logrt[]キーはローテーションをするログファイルを監視するためのキーで、1.8から新しく追加されています。アイテムのキーには以下のように設定します。

logrt[file_format,regexp,encoding,maxlines]

log[]キーと異なるのはファイル指定部分に正規表現が利用できる点です。例えば以下のように指定します。

logrt[/var/log/messages.*]

logrt[]キーの動作としてはフォルダを探索し、マッチするファイルを抜き出し、監視すべきファイルを選定してからファイルを読みます。この処理が入るためlog[]キーよりは動作が複雑です。それ以外はlog[]キーとほぼ同じ動作をしますので、ここではファイルの選択ロジックについてのみ解説します。

ちなみに、ファイル名部分に利用できるのは正規表現です。正規表現をシェルのワイルドカードと誤解している人をよく見かけます。正規表現で*は「直前の文字の0回以上の繰り返し」なので、間違えると思いがけないファイルまで読んでしまう場合があるので注意してください。

logrtキーの処理はソースコードのsrc/zabbix_agent/logfiles.cの366行目から始まるprocess_logrt()関数で定義されています。Windowsとそれ以外で処理が分かれているので、ここではWindows部分の解説は飛ばします。

/* splitting filename */
if (SUCCEED != split_filename(filename, &directory, &format))
{
    zabbix_log(LOG_LEVEL_WARNING, "filename [%s] does not contain a valid directory and/or format", filename);
    return FAIL;
}

ここで指定されたパスをディレクトリとファイル名に分けて、

if (NULL == (dir = opendir(directory)))
{
    zabbix_log(LOG_LEVEL_WARNING, "cannot open directory [%s] for reading: %s", directory, zbx_strerror(errno));
    zbx_free(directory);
    zbx_free(format);
    return FAIL;
}

ディレクトリをオープン

while (NULL != (d_ent = readdir(dir)))
{
    logfile_candidate = zbx_dsprintf(logfile_candidate, "%s%s", directory, d_ent->d_name);

    if (-1 == zbx_stat(logfile_candidate, &file_buf) || !S_ISREG(file_buf.st_mode))
    {
        zabbix_log(LOG_LEVEL_DEBUG, "cannot process read entry [%s]", logfile_candidate);
    }
    else if (NULL != zbx_regexp_match(d_ent->d_name, format, &length))
    {
        zabbix_log(LOG_LEVEL_DEBUG, "adding the file [%s] to logfiles", logfile_candidate);
        add_logfile(&logfiles, &logfiles_alloc, &logfiles_num, d_ent->d_name, (int)file_buf.st_mtime);
    }
    else
        zabbix_log(LOG_LEVEL_DEBUG, "[%s] does not match [%s]", logfile_candidate, format);

    zbx_free(logfile_candidate);
}

ディレクトリにあるファイルから、指定された正規表現にマッチするファイルを探してlogfiles配列に追加しています。

途中にあるadd_logfile()関数でlogfiles配列への追加処理を行っているのですが、この関数内は

  • ファイルのmtime(ファイルの更新日時)が古い順
  • mtimeが同じ場合はアルファベット/数字の降順(z->a, 9->0)

に並ぶように処理されています。

/* find the oldest file that match */
for (i = 0; i < logfiles_num; i++)
{
    if (logfiles[i].mtime < *mtime)
        continue;   /* not interested in mtimes less than the given mtime */
    else
        break;  /* the first occurrence is found */
}

ここで*mtimeとなっているのは、前回ログを読み込んだ際に記憶しておいたmtimeです。つまり、logfiles配列にあるログファイルのmtimeと前回読んだファイルのmtimeを比較して、最初に見つけた「前回よりもmtimeが新しいファイル」のインデックスが変数iに入ります。logfiles配列の先頭から読んでいるので、配列の順番が重要です。

/* escaping those with the same mtime, taking the latest one (without exceptions!) */
for (j = i + 1; j < logfiles_num; j++)
{
    if (logfiles[j].mtime == logfiles[i].mtime)
        i = j;  /* moving to the newer one */
    else
        break;  /* all next mtimes are bigger */
}

ここでは先ほど見つけたmtimeが新しいログファイルを基準に、それよりもlogfiles配列の後ろにあるファイルを探索してmtimeを比較しています。mtimeが同じファイルがあれば、より配列の後ろにあるファイルが選択されます。(実際にはインデックスが変数iに入る)

/* if all mtimes are less than the given one, take the latest file from existing ones */
if (0 < logfiles_num && i == logfiles_num)
    i = logfiles_num - 1;   /* i cannot be bigger than logfiles_num */

最終的にインデックスiが配列の最後まで行ってしまった場合は、logfiles配列の一番後ろのログファイルが選択されます。

ここから実際にログファイルを読む部分です。少し長いですがそのまま貼付けます。

/* processing matched or moving to the newer one and repeating the cycle */
for ( ; i < logfiles_num; i++)
{
    logfile_candidate = zbx_dsprintf(logfile_candidate, "%s%s", directory, logfiles[i].filename);
    if (0 != zbx_stat(logfile_candidate, &file_buf))/* situation could have changed */
    {
        zabbix_log(LOG_LEVEL_WARNING, "cannot stat [%s]: %s", logfile_candidate, zbx_strerror(errno));
        break;  /* must return, situation could have changed */
    }

    *mtime = (int)file_buf.st_mtime;    /* must contain the latest mtime as possible */
    if (file_buf.st_size < *lastlogsize)
    {
        *lastlogsize = 0;   /* maintain backward compatibility */
    }

    if (-1 == (fd = zbx_open(logfile_candidate, O_RDONLY)))
    {
        zabbix_log(LOG_LEVEL_WARNING, "cannot open [%s]: %s", logfile_candidate, zbx_strerror(errno));
        break;  /* must return, situation could have changed */
    }

    if ((off_t)-1 != lseek(fd, (off_t)*lastlogsize, SEEK_SET))
    {
        if (-1 != (nbytes = zbx_read(fd, buffer, sizeof(buffer), encoding)))
        {
            if (0 != nbytes)
            {
                *lastlogsize += nbytes;
                *value = convert_to_utf8(buffer, nbytes, encoding);
                zbx_rtrim(*value, "\r\n ");
                ret = SUCCEED;
                break;  /* return at this point */
            }
            else    /* EOF is reached, but there can be other files to try reading from */
            {
                if (i == logfiles_num - 1)
                {
                    ret = SUCCEED;  /* EOF of the the most current file is reached */
                    break;
                }
                else
                {
                    zbx_free(logfile_candidate);
                    *lastlogsize = 0;
                    close(fd);
                    continue;   /* try to read from more current file */
                }
            }
        }
        else    /* cannot read from the file */
        {
            zabbix_log(LOG_LEVEL_WARNING, "cannot read from [%s]: %s",
                    logfile_candidate, zbx_strerror(errno));
            break;  /* must return, situation could have changed */
        }
    }
    else    /* cannot position in the file */
    {
        zabbix_log(LOG_LEVEL_WARNING, "cannot set position to [%li] for [%s]: %s",
                *lastlogsize, logfile_candidate, zbx_strerror(errno));
        break;  /* must return, situation could have changed */
    }
}   /* trying to read from logfiles */

forループ内でここまでで決めたインデックスiを使って、logfiles[i]以降にあるログファイル全てを読みにいこうとしています。つまり、ログローテーションしてmessagesがmessages.1になった場合、先にmessages.1の残りの部分を読んでから、新しいmessagesファイルを読みに行こうとします。

その後にあるファイル情報の取得、lastlogsizeの処理、64KBづつログファイルを読み込んでutf8変換などの処理はlog[]キーと同様です。少し異なるのは、ファイルのmtimeを変数に保存しておいたり、ファイルの末尾まで読んだときにlogfiles配列に次のファイルが残っていたら、続けて次のファイルを先頭から(lastlogsize=0)読もうとする点です。

valueに読み込まれた文字、lastlogsizeの値の処理はlog[]キーと同様に処理されます。logrt[]の場合はmtimeもlastlogsizeと同様にactive_metrics配列に保存されます。

2012年2月12日日曜日

ラトビアでスノーボードに行ってきました

会社の人に誘われて、ラトビアでスノーボードに行ってきました。

行ってきたのはリガから80キロほど離れたCēsisという街の近くにあるŽagarkalnsというスキー場です。ほかにもリガから50キロほど離れたSiguldaにもスキー場があるらしいのですが、スノーボードにはŽagarkalnsの方が良いんだそうです。

先週末が一番寒い時期だったようで、リガでも最低気温が-30度近くまで下がりました。今週は寒くても-20度くらい、昼間は-10度くらいになるので一時期よりは暖かくなりましたが、それでも寒いことには変わらないです。Cēsisは少し内陸部にあるので、リガよりは少し寒くなります。

スキー場の木もとても寒そうなことになっています。

http://farm8.staticflickr.com/7061/6863963243_89d345f09d.jpg

スキー場はそれなりに混雑していました。スキーヤーの方が多く、スキーとスノーボードの割合が7:3くらいの割合でしょうか。

http://farm8.staticflickr.com/7189/6863961989_e421eb2884.jpg

到着したのが昼の1時過ぎくらいと遅めだったこともあってか、スノーボードの板は借りれたもののウェアを借りることができず、普段着のまま滑ることになってしまいました。ウェアは数が少ないので借りれないかもしれない、と前日に聞いてはいたので覚悟はしていたのですが、転ばないように気をつけながらになるので、あまり思い切りすべれないのが残念です。

ちなみに、ラトビアは日本と違って山がありません。一番標高の高いところで海抜300mくらいなんだそうです。300mといえば東京タワーと同じくらいですね。

なので、スキー場といっても日本ほど長いコースはなく、短いところで1分くらい、長くても3〜5分で滑りきってしまうくらいの長さです。ところどころ急な斜面もあったり、ジャンプ台のようなものもあったりと、コース自体は楽しめる作りになっていました。

http://farm8.staticflickr.com/7208/6863966059_b7538c7372.jpg

コースの一番下にあった開けた場所。これは川が凍ってるんだそうです。名前を聞かなかったので分からないのですが、川幅から察するに年末にボートツアーに行った川なんじゃないかと思います。

http://farm8.staticflickr.com/7206/6863967835_32634a3ab2.jpg

滑り始めたのが遅かったこともあり、2時間くらい滑ったところで日が暮れ始めたので、Cēsis市内に戻って食事してから帰ろうということになりました。

今年初めてのスノーボードだったので2時間でも十分楽しめました。普段着で転倒しないように注意しながらだったので思い切り滑れなかったのが残念でした。今日は宿が取れずに日帰りになってしまったので、次回は早めに宿を確保して1泊で来たいね、と話しながらCēsisに向かいました。

Cēsisでピザを食べて、少し周辺を歩いてからリガに向かうことになりました。これはCēsis市内の中心にあるモニュメント。

http://farm8.staticflickr.com/7036/6863969079_5e6625c18c.jpg

これはヴェンデン城跡です。昼間は中に入って見学できるんだそうです。

http://farm8.staticflickr.com/7177/6863970177_9a85c80e6b.jpg

Cēsisの古い町並み

http://farm8.staticflickr.com/7061/6863971257_91038ca5be.jpg

今回スノーボードに誘ってくれた人は、Cēsisはラトビアの中でも一番好きな街の一つだと言っていました。今回は夜も遅く、寒かったのであまり見て回れませんでしたが、次回は暖かいときにゆっくり観光に来てみたいと思います。

2012年1月1日日曜日

ラトビアのボートツアーと年越しパーティ

いよいよ2011年も最後、特に予定もないけれど年末年始はどう過ごそうかと考えていたときに、会社の同僚からボートツアーに誘われました。この寒い時期にボートツアー?と最初は断っていたのですが、ぜひ来なよ、という誘いもあって行ってみることにしました。

実は夏前くらいから何度となくボートツアーに誘われていたのですが、誘ってくれていた人が忙しくタイミングを逃していました。今の気温はそれほど低くないし、次回の春先にあるツアーは今よりも寒くて雪解け水で川の流れも早くなってより濡れるから、今回の条件はそれほど悪くないよ、とのことでした。

当日の朝は快晴にはならなかったものの、気温もそれほど低くなく風も穏やかな日になりました。正確な気温は覚えていないですが、最高気温5度、最低気温0度くらいだったと思います。私たちは車を持っていないので、誘ってくれた同僚の知り合いにリガ市内まで迎えに来てもらい、一旦同僚の家で準備をしてから出発地まで向かいました。

出発地はCesisという街の近く、リガの中心地から北東に100キロほど離れた場所です。車で1時間くらいのドライブの間、同僚はずっとビールを飲みっぱなし。私も一緒に飲んでいたのですが、彼は自宅で準備している間も飲んでいたので、到着までに500mlのボトルを3-4本開けてたんじゃないだろうかという勢いです。ラトビア人恐るべし。

これから下る川です。かなり緩やかな流れで安心しました。ラトビアは12月にもなると気温も氷点下になり、このあたりも雪で覆われているのが普通で、今年の気温は記録的に暖かいんだそうです。

http://farm8.staticflickr.com/7029/6614851409_0fe4b5c37f.jpg

みんなで協力してボートの準備。ゴムボートを足踏みタイプの空気入れで膨らましているところ。

http://farm8.staticflickr.com/7169/6614850653_a87c126085.jpg

念のためのライフジャケットを着ていざ出発です。ある程度着込んでいたことと、オールを漕ぐので寒さは全く感じませんでした。時期も時期なので両岸に動物を見ることはありませんでしたが、鳥が水面を泳いでいるのを見たり、ほとんど音のない中、森を両手にボートで進むのは久々に自然を満喫した気分でした。

http://farm8.staticflickr.com/7157/6614852545_804f1707a6.jpg

ボートから撮った夕日。今の時期ラトビアは日本よりも日が短く、4時くらいには日が沈んでしまいます。ボートに乗る前は2時間くらいで目的地に到着予定だったのですが(同僚はもっとかかるだろうと思っていたそうですが)、川の流れが緩いためか予定より時間がかかってしまい、急がないと日が暮れてしまいそうです。

http://farm8.staticflickr.com/7146/6614854477_945c9e2247.jpg

急がないと暗くなっちゃうねー、なんて話していると…急に空がどんよりしてきたかと思うと、小さな霰(あられ)が降ってきました。不吉な予感

http://farm8.staticflickr.com/7174/6614853429_a25cc0535e.jpg

最初の霰は小降りで一旦止んだのですが、2回目は本格的に降ってきました。

http://farm8.staticflickr.com/7151/6614855253_2a81f0c4e8.jpg

ボートの上もこんな状況

http://farm8.staticflickr.com/7003/6614856245_54640d5256.jpg

このあとは寒さと雪と日暮れのためあまり写真は撮れませんでした。最終的に霰は雪に変わり、予定より1-2キロほど早めに岸に上がって車で迎えにきてもらいました。迎えに来てくれた人は、こんな日にボートツアーに行くなんてクレイジーだと行っていましたし、実際に最後の方は大変でしたが忘れられない良い思い出になりました。後でGPSのデータを見てみると16.4キロのボートツアーでした。

ボートツアーから帰ってきたあと、ボートツアーに誘ってくれた同僚が自宅でパーティーをやるんだけど、よければ参加しない?と誘ってくれ、特に年越しのときの予定もなかったので参加させてもらうことにしました。

ボートツアーの出発の前にも少し寄らせてもらった同僚の家ですが、森の中の暖炉のある家、といういかにも北欧な感じのする素敵な家でした。

みんなで集まれるキッチンや、

http://farm8.staticflickr.com/7161/6621409387_76cc84142a.jpg

家の真ん中にある暖炉

http://farm8.staticflickr.com/7029/6621410525_7ea55635ea.jpg

2階には卓球台ががありました。

http://farm8.staticflickr.com/7026/6621408349_81fbc9535a.jpg

これは採ってきた草やハーブなどでお茶を作ってるんだそうです。

http://farm8.staticflickr.com/7157/6621933709_9d708f247b.jpg

ラトビアでは年越などイベントのときにはコイを食べるんだとか。スーパーなどでも水槽で泳いでいるのをよく見かけます。

http://farm8.staticflickr.com/7169/6614857219_d109bc689e.jpg

このコイにバター、レモン、ハーブ、ニンニクなどをつめて、ポテトと一緒にホイルに包み、

http://farm8.staticflickr.com/7155/6614857967_3be02bb545.jpg

オーブンで1時間くらい焼いてできあがり。

http://farm8.staticflickr.com/7016/6614860821_fde001174f.jpg

日本ではコイというとあまり美味しそうなイメージがないですが、白身魚のような全く癖のない味でとても美味しかったです。

他にもラトビアではよく食べられているサラダやチーズ、Laimaのチョコレートなどなど、色々な食事がありました。

http://farm8.staticflickr.com/7012/6621399723_6cb5a9141c.jpg

これは採ってきた野菜を使って作った手作りのピクルス。ラトビアでは色々なものをピクルスにして食べます。

http://farm8.staticflickr.com/7145/6621932365_fd100c275a.jpg

これはツナの入った何か。食べた感じはツナマヨのタコス巻きという感じでした。

http://farm8.staticflickr.com/7003/6614861837_26fe0d8b2a.jpg

ラトビアでよく食べられている黒いライ麦のパンです。これは中にナッツが入っていました。このパンにチーズや野菜、サラダなどを挟んで食べていました。

http://farm8.staticflickr.com/7034/6621402679_9f67b6dfee.jpg

ラトビアではちょうど年を越す12:00には皆で外にでてスパークリングワインを開けるんだそうです。その準備も万端。RIGASと書いてあるのがラトビア産のもので、お祝いごとがあると必ずといっていいほど飲まれています。味は甘めで癖がなく飲みやすいです。

http://farm8.staticflickr.com/7012/6614859919_fa7b39fff7.jpg

みんなで遅くまで飲んだり食べたりして楽しんで、この日はそのまま泊まらせてもらうことになりました。今日はボートツアーから年越しのパーティまで、ラトビアを満喫できた1日でした。