├── .gitignore ├── .envexample ├── slack └── slack.go ├── readme.md ├── main.go ├── redis └── redis.go └── tracker └── tracker.go /.gitignore: -------------------------------------------------------------------------------- 1 | .env -------------------------------------------------------------------------------- /.envexample: -------------------------------------------------------------------------------- 1 | SLACK_WEBHOOK_URL="https://hooks.slack.com/services/id" 2 | REDIS_HOST="0.0.0.0" 3 | REDIS_PASSWORD="" -------------------------------------------------------------------------------- /slack/slack.go: -------------------------------------------------------------------------------- 1 | package slack 2 | 3 | import ( 4 | "log" 5 | "os" 6 | 7 | slackHandler "github.com/ashwanthkumar/slack-go-webhook" 8 | ) 9 | 10 | func Post(message string) { 11 | webhookURL := os.Getenv("SLACK_WEBHOOK_URL") 12 | payload := slackHandler.Payload{ 13 | Text: message, 14 | Username: "go-track", 15 | Channel: "#gotrack", 16 | IconEmoji: ":monkas:", 17 | } 18 | 19 | err := slackHandler.Send(webhookURL, "", payload) 20 | if err != nil { 21 | log.Fatal(err) 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # go-track 2 | 3 | URL monitor written in Go. 4 | 5 | @TODO 6 | > 1. Write tests 7 | > 2. Get urls from a txt-file etc. 8 | 9 | ## Settings are set inside the .env file 10 | ```golang 11 | SLACK_WEBHOOK_URL="https://hooks.slack.com/services/id" 12 | REDIS_HOST="0.0.0.0" 13 | REDIS_PASSWORD="" 14 | ``` 15 | 16 | ## URL's to ping 17 | For the moment it's located in main.go 18 | 19 | ```golang 20 | urls = []string{"https://www.google.com/urldoesntexist", "https://www.google.com/"} 21 | ``` 22 | 23 | ## Run 24 | ```golang 25 | go run main.go 26 | ``` 27 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "sync" 5 | 6 | "github.com/robinryden/go-track/tracker" 7 | 8 | "github.com/robfig/cron" 9 | "github.com/subosito/gotenv" 10 | ) 11 | 12 | var ( 13 | wg sync.WaitGroup 14 | urls = []string{"https://www.reddit.com/", "https://www.reddit.com/r/golang/"} 15 | ) 16 | 17 | func init() { 18 | gotenv.Load() 19 | } 20 | 21 | func main() { 22 | cronWorker := cron.New() 23 | 24 | go tracker.Start() 25 | 26 | wg.Add(1) 27 | cronWorker.AddFunc("1/5 * * * * *", func() { 28 | go checkURLS() 29 | }) 30 | 31 | cronWorker.Start() 32 | wg.Wait() 33 | } 34 | 35 | func checkURLS() { 36 | for _, url := range urls { 37 | go func(url string) { 38 | wg.Add(1) 39 | tracker.TrackURL(url) 40 | wg.Done() 41 | }(url) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /redis/redis.go: -------------------------------------------------------------------------------- 1 | package redis 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "log" 7 | "os" 8 | "time" 9 | 10 | "github.com/go-redis/redis" 11 | ) 12 | 13 | type Log struct { 14 | Name string 15 | StatusCode int 16 | Time time.Time 17 | } 18 | 19 | func Connect() (*redis.Client, error) { 20 | client := redis.NewClient(&redis.Options{ 21 | Addr: os.Getenv("REDIS_HOST"), 22 | Password: os.Getenv("REDIS_PASSWORD"), 23 | DB: 0, 24 | }) 25 | return client, nil 26 | } 27 | 28 | func Logger(url string, statusCode int, timestamp time.Time) { 29 | client, err := Connect() 30 | if err != nil { 31 | log.Fatal(err) 32 | } 33 | 34 | logged := &Log{ 35 | url, 36 | statusCode, 37 | timestamp, 38 | } 39 | 40 | data, err := json.Marshal(*logged) 41 | if err != nil { 42 | log.Fatal(err) 43 | } 44 | 45 | client.Set(url, data, 0) 46 | fmt.Println(client.Get(url)) 47 | } 48 | -------------------------------------------------------------------------------- /tracker/tracker.go: -------------------------------------------------------------------------------- 1 | package tracker 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | "time" 8 | 9 | "github.com/robinryden/go-track/redis" 10 | "github.com/robinryden/go-track/slack" 11 | ) 12 | 13 | type TrackedURL struct { 14 | name string 15 | statusCode int 16 | timestamp time.Time 17 | } 18 | 19 | var ( 20 | Tracked = make(chan *TrackedURL) 21 | ) 22 | 23 | func Start() { 24 | for { 25 | select { 26 | case trackedURL := <-Tracked: 27 | go HealthCheck(trackedURL) 28 | fmt.Printf("Tracked URL %v with statusCode %v\n", trackedURL.name, trackedURL.statusCode) 29 | } 30 | } 31 | } 32 | 33 | // TrackURL ... 34 | func TrackURL(url string) { 35 | ping, err := http.Get(url) 36 | if err != nil { 37 | log.Fatal(err) 38 | } 39 | defer ping.Body.Close() 40 | 41 | Tracked <- &TrackedURL{ 42 | url, 43 | ping.StatusCode, 44 | time.Now(), 45 | } 46 | } 47 | 48 | func HealthCheck(url *TrackedURL) { 49 | // log url check to redis 50 | go redis.Logger(url.name, url.statusCode, url.timestamp) 51 | 52 | switch url.statusCode { 53 | case http.StatusForbidden: 54 | fallthrough 55 | case http.StatusNotFound: 56 | fallthrough 57 | case http.StatusInternalServerError: 58 | go slack.Post(fmt.Sprintf("%s resulted in a %d at %s\n", 59 | url.name, 60 | url.statusCode, 61 | url.timestamp.Format("2006-01-02 15:04:05"), 62 | )) 63 | } 64 | } 65 | --------------------------------------------------------------------------------