Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

この記事は 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 の導入を考えてみては如何でしょうか。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away