LoginSignup
24
27

More than 5 years have passed since last update.

golangでhttpを監視するscriptを書いて結果をslackにpostする

Last updated at Posted at 2015-09-02

golangで簡単なscriptを書いてみる

ぐぐると、簡単な1ファイルのサンプルスクリプトは出て来るが、もうちょっと拡張性のある、ライブラリ置き場や設定ファイル置き場を分けた様な構成でscriptを書いてみる事にした。

という事で、今回はgolangを使ってhttp監視をしてみる事にする。

ディレクトリ構成

GOPATH以下の構成。基本的にGOPATH/src以下にプロジェクトを作っていく事が推奨らしい。
src以下にprojectというディレクトリを作りその下に各ディレクトリを配置。

src - project - config - secrets.go
              |        |
              |        - targets.go
              |
              - libs - slack - slack.go
              |
              - scripts - check_http.go

config : 設定ファイル置き場。secrets.goにはgit管理したくない物を入れて.gitignoreしておくと吉。

libs : slackにpostする周りのライブラリ置き場

scripts : mainの監視用script

ソースコード

各ファイルの名前と中身、ちょっとしたコメント。

config/secrets.go

slackのincomingのurlを書いておく。
人には知られるとまずい物なので、その他のファイルとは独立させておく。

package config

var (
    IncomingUrl string = "https://hooks.slack.com/services/XXXXXXXXXXXXXXXXXXXXXX"
)

config/targets.go

テスト用に、3つドメインを用意してみた。最初の一つだけ成功して後は失敗するテスト。

package config

import (
)

type HttpConfigSlice struct {
    Http []HttpConfig
}

type HttpConfig struct {
    Name string
    Host string
    Path string
    Proto string
    Domain string
}

func HttpTargets() []HttpConfig {
    return []HttpConfig{
        HttpConfig{Name: "Google", Host: "google.com", Path: "/", Proto: "http", Domain: "google.com"},
        HttpConfig{Name: "Google", Host: "google.com", Path: "/no-such-path", Proto: "http", Domain: "google.com"},
        HttpConfig{Name: "NiseGoogle", Host: "nisegoogle.com", Path: "/", Proto: "http", Domain: "nisegoogle.com"},
    }
}

libs/slack/slack.go

引数で貰ったmsgをそのままslackにPOSTするやつ。実はslackのgo用ライブラリがあったっぽいが書いた後に気づいた。
これ。https://github.com/nlopes/slack

書いちゃったので、今回は自分のを使う。

configをimportする時には、GOPATH/src以下からのpathで読める。
pathの前に名前をつけるとエイリアスになって便利。

package slack

import (
    "log"
    "net/http"
    "net/url"
    "strings"
    "encoding/json"
    "time"

    config "project/config"
)

type CheckConfig struct {
    Http []HttpConfig `json:"http"`
}

type HttpConfig struct {
    Name   string `json:"name"`
    Host   string `json:"host"`
    Path   string `json:"path"`
    Proto  string `json:"proto"`
    Domain string `json:"domain"`
}

type Slack struct {
    Text     string `json:"text"`
    Username string `json:"username"`
}

func Post(msg string) {
    params, _ := json.Marshal(Slack{
        msg,
        "MonitoringBot",
    })

    client := &http.Client{Timeout: 5 * time.Second}

    values := url.Values{"payload": {string(params)}}
    req, err := http.NewRequest("POST", config.IncomingUrl, strings.NewReader(values.Encode()))
    if err != nil {
        log.Print(err)
        return
    }

    req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

    resp, err := client.Do(req)
    if err != nil {
        log.Print(err)
        return
    }
    defer resp.Body.Close()
}

scripts/check_http.go

監視のおおもとのやつ。単純に、ターゲット持ってきて、httpチェックをするだけ。地味にリトライ入れてみた。

package main

import (
    "net/http"
    "crypto/tls"
    "time"
    "fmt"

    slack "project/libs/slack"
    config "project/config"
)

func main() {
    for _, target := range config.HttpTargets() {
        check(target)
    }
}

func check(target config.HttpConfig) {
    errorNum := 0
    checkNum := 0
    fatalNum := 2
    errorMessage := ""
    for checkNum < fatalNum {
        checkNum += 1
        targetPath := target.Proto + "://" + target.Host + target.Path
        tr := &http.Transport{
            TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
        }
        client := &http.Client{Timeout: 5 * time.Second, Transport: tr}
        req, err := http.NewRequest("GET", targetPath, nil)
        if err != nil {
            slack.Post(err.Error())
            return
        }

        req.Header.Add("Host", target.Domain)
        resp, err := client.Do(req)
        if err != nil {
            slack.Post(err.Error())
            return
        }

        if resp.StatusCode != 200 {
            errorNum += 1
            if (errorNum >= fatalNum) {
                errorMessage += targetPath + " [" + target.Name + "] " + "returns " + fmt.Sprint(resp.StatusCode) + "\n"
            }
        } else {
            break
        }

        defer resp.Body.Close()
    }

    if errorMessage != "" {
        slack.Post(errorMessage)
    }
}

slack post結果

実行してみる。

$ go run scripts/check_http.go

期待通り、pathがおかしいやつが404、ドメイン変なやつが no such hostになった。
スクリーンショット 2015-09-02 18.58.38.png

意外に簡単に書ける、go言語。

24
27
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
27