Mackerel チェック機能の意外と知られていないテクニック集

  • 17
    いいね
  • 0
    コメント

この記事は Mackerel Advent Calendar 2016 の22日目の記事です。

はじめに

Mackerel と聞くと、どうしてもサービスメトリクスに着目しがちなのですが実際には Mackerel には大きく2つ機能があります。

  • サービスメトリクス(リソース情報の可視化)
  • チェック機能(アラート通知)

サービスメトリクスの上限値などからアラート通知を行う事もできるのですが、何らかの事象を継起にアラート通知を発生させる事も可能です。自前でこういった物を作る場合

  • 発生と復旧のステータス管理
  • メール通知の再送制御

などなど、後から面倒な事が出てきて割とめんどくさい事だったりします。しかし Mackerrel のチェック機能を使えばその辺りを全て Mackerel に任せられます。今日はこの Mackerel のチェック機能を使った、意外と知られていないテクニックをご紹介しますよ、奥さん!

大売出し

check-log

ログファイルに出力される特定の文言を検出します。

[plugin.checks.log]
command = "/path/to/check-log --file=/path/to/file --pattern=REGEXP --warning-over=N --critical-over=N"

ログファイル /path/to/file にてパターン REGEXP が検出されると警告や障害として扱います。文言が出現するたびにエラーになられると困る人は、--warning-over--critical-over で出現回数 N を指定する事もできます。

お得情報

ここからがお得情報。実はちょっと前--encoding オプションが追加されています。Windows な人は --encoding sjis を付け加える事で、Shift_JIS のログファイルも扱えます。

check-procs

プロセスに関するあらゆる監視が可能です。プロセスのリソース値が一定以上であれば障害とする、等といった事が可能です。

[plugin.checks.procs]
command = "/path/to/check-procs --pattern=PROCESS_NAME --state=STATE --warning-under=N"

--pattern で正規表現が扱えるので任意のユーザが起動するコマンドも監視できますね。

お得情報

例えば、身近でこんな事は無いでしょうか。

何かコマンド実行を実行したまま、しばしば落とすのを忘れて帰ってしまう

コマンドが課金対象だったりすると大変ですね。こんな場合でも check-procs は使えます。

[plugin.checks.procs]
command = "/path/to/check-procs --pattern='ping aws-server' --critical-over 0 --esec-over 3600"

--critical-over を 0 に、--esec-over を許容する秒数に設定する事で、「起動していないならエラーとしないけど、起動しているなら起動時間が 3600 秒以上だとエラーにする」といった事が実現可能です。上記の例だと ping aws-server が実行されてから 3600 秒経過すると Mackerel 経由でアラートが送信されます。

check-ntservice

Windows ではNTサービスも監視対象となり得ます。しかし Windows サービス名は特殊で check-procs では検出できない物があります。そこで check-ntservice を使います。

[plugin.checks.ntservice]
command = "/path/to/check-ntservice --service-name=SERVICE_NAME"

SERVICE_NAME で示すサービスが停止するとアラートが上がります。

お得情報

この Windows サービス名、どの値を設定するか分からないと思うかもしれません。そんな場合はプラグインが置かれているディレクトリ(C:/Program Files (x86)/Mackerel/mackerel-agent)で以下のコマンドを実行します。

check-ntservice -l

すると、検査可能なサービスの名前が一覧表示されます。

・・・略・・・
PNRPAutoReg: PNRP Machine Name Publication Service
PNRPsvc: Peer Name Resolution Protocol
PolicyAgent: IPsec Policy Agent
postgresql-x64-9.4: postgresql-x64-9.4 - PostgreSQL Server 9.4
Power: Power
ProfSvc: User Profile Service
ProtectedStorage: Protected Storage
・・・略・・・

この左側(例: postgresql-x64-9.4)を SERVICE_NAME に設定します。簡単ですね。

おまけ

Windows のサーバを運用していると Windows Update に伴う脆弱性パッチのリリースを気に掛ける必要があります。気付くのが遅くて脆弱性を突かれた、なんて事が起きたら大変ですね。

お得情報

こういった場合であっても Mackerel であればチェックAPIが公開されているので以下の様なチェッカーを作る事で簡単に監視する事ができます。

package main

import (
    "bytes"
    "encoding/json"
    "flag"
    "io"
    "log"
    "net/http"
    "os"
    "regexp"
    "strings"
    "time"

    "github.com/go-ole/go-ole"
    "github.com/go-ole/go-ole/oleutil"
)

var (
    hostId  = flag.String("h", "", "hostId for mackerel")
    pattern = flag.String("p", "", "pattern to grab process")
    dryrun  = flag.Bool("d", false, "dry run")
)

type source struct {
    Type   string `json:"type"`
    HostId string `json:"hostId"`
}

type alert struct {
    Source     source `json:"source"`
    Name       string `json:"name"`
    Status     string `json:"status"`
    Message    string `json:"message"`
    OccurredAt int64  `json:"occurredAt"`
}

func sendAlert(msg string) error {
    var buf bytes.Buffer
    json.NewEncoder(&buf).Encode(&struct {
        Reports []alert `json:"reports"`
    }{
        Reports: []alert{{
            Source:     source{Type: "host", HostId: *hostId},
            Name:       "windows-update",
            Status:     "CRITICAL",
            Message:    msg,
            OccurredAt: time.Now().Unix(),
        }},
    })
    req, err := http.NewRequest("POST", "https://mackerel.io/api/v0/monitoring/checks/report", &buf)
    if err != nil {
        return err
    }
    req.Header.Set("X-Api-Key", os.Getenv("MACKEREL_API_KEY"))
    req.Header.Set("content-type", "application/json")
    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        return err
    }
    io.Copy(os.Stdout, resp.Body)
    resp.Body.Close()
    return nil
}

func main() {
    flag.Parse()
    if *pattern == "" || *hostId == "" {
        flag.Usage()
        os.Exit(2)
    }
    re, err := regexp.Compile(*pattern)
    if err != nil {
        log.Fatal(err)
    }
    if os.Getenv("MACKEREL_API_KEY") == "" {
        log.Fatal("require $MACKEREL_API_KEY")
    }
    os.Setenv("GODEBUG", "http2client=0")

    ole.CoInitialize(0)
    unk, err := oleutil.CreateObject("Microsoft.Update.Session")
    if err != nil {
        log.Fatal(err)
    }
    defer unk.Release()

    updateSession := unk.MustQueryInterface(ole.IID_IDispatch)
    defer updateSession.Release()

    updateSearcher := oleutil.MustCallMethod(updateSession, "CreateUpdateSearcher").ToIDispatch()
    defer updateSearcher.Release()

    searchResult := oleutil.MustCallMethod(updateSearcher, "Search", "IsInstalled=0 and Type='Software' and AutoSelectOnWebSites=1").ToIDispatch()
    updates := oleutil.MustGetProperty(searchResult, "Updates").ToIDispatch()
    count := int(oleutil.MustGetProperty(updates, "Count").Value().(int32))

    titles := []string{}
    for i := 0; i < count; i++ {
        update := oleutil.MustGetProperty(updates, "Item", i).ToIDispatch()
        title := oleutil.MustGetProperty(update, "Title").ToString()
        log.Println(title)
        if re.MatchString(title) {
            titles = append(titles, title)
        }
    }
    if !*dryrun && len(titles) > 0 {
        title := strings.Join(titles, "\n")
        rs := []rune(title)
        if len(rs) > 1024 {
            title = string(rs[:1021]) + "..."
        }
        sendAlert(title)
    }
}

これをビルドして出来た実行モジュールをタスクスケジューラで毎晩起動する様にしておきます。引数は以下の通り。

check-widnowsupdate -h XXXX -p セキュリティ

※ホストID XXXX は mackerel のホスト詳細を開いた際の URL 末尾になります。
※起動には環境変数 MACKEREL_API_KEY が必要です。

これを実行するとセキュリティ関連パッチがリリースされたその夜に以下の様なアラートが上がります。

WindowsUpdateが出たよ

あとは Mackerel から送られてきたアラートメールを見て Windows Update すれば ok です。
※実行に時間が掛かるので mackerel-agent からは呼び出すのは推奨しません。

まとめ

作り手が面倒だと思っている監視の大部分を Mackerel 側で行ってくれるため、多くの時間を節約する事ができて良いですね。監視はしたいけど、メール通知やステータス管理が面倒という方は Mackerel の導入を考えてみては如何でしょうか。

この投稿は Mackerel Advent Calendar 201622日目の記事です。