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になった。
意外に簡単に書ける、go言語。