この記事は 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 が必要です。
これを実行するとセキュリティ関連パッチがリリースされたその夜に以下の様なアラートが上がります。
あとは Mackerel から送られてきたアラートメールを見て Windows Update すれば ok です。
※実行に時間が掛かるので mackerel-agent からは呼び出すのは推奨しません。
まとめ
作り手が面倒だと思っている監視の大部分を Mackerel 側で行ってくれるため、多くの時間を節約する事ができて良いですね。監視はしたいけど、メール通知やステータス管理が面倒という方は Mackerel の導入を考えてみては如何でしょうか。