diff --git a/cmd/watch.go b/cmd/watch.go index 66029d8..010af9e 100644 --- a/cmd/watch.go +++ b/cmd/watch.go @@ -25,7 +25,7 @@ import ( "log" "net/url" "strings" - "time" + "sync" "github.com/Kashkovsky/hostmonitor/core" "github.com/spf13/cobra" @@ -33,7 +33,7 @@ import ( type WatchConfig struct { configUrl string - testInterval int64 + testInterval int requestTimeout int } @@ -49,26 +49,31 @@ var watchCmd = &cobra.Command{ func runWatch(cmd *cobra.Command, args []string) { log.Default().Println("Testing URLs from config ", watchConfig.configUrl) printer := core.NewPrinter() + res := sync.Map{} + + c, _, err := doWatch() + if err != nil { + log.Fatalf("Fatal: %v", err) + return + } + for { - res, err := doWatch() - if err != nil { - log.Fatalf("Fatal: %v", err) - return - } + rec := <-c + res.Store(rec.Id, rec) printer.ToTable(&res) - time.Sleep(time.Duration(watchConfig.testInterval) * time.Second) } } -func doWatch() ([]core.TestResult, error) { +func doWatch() (chan core.TestResult, int, error) { config, err := core.GetStringFromURL(watchConfig.configUrl) + outC := make(chan core.TestResult, 50) if err != nil { log.Fatalf("Could not obtain a config: %v", err.Error()) - return []core.TestResult{}, err + + return outC, 0, err } records := strings.Split(config, "\n") - outC := make(chan core.TestResult, 50) for _, addr := range records { u, err := url.Parse(addr) if err != nil { @@ -76,22 +81,15 @@ func doWatch() ([]core.TestResult, error) { continue } - go core.Test(u, watchConfig.requestTimeout, outC) + go core.Test(u, watchConfig.requestTimeout, watchConfig.testInterval, outC) } - results := []core.TestResult{} - - for { - results = append(results, <-outC) - if len(results) == len(records) { - return results, nil - } - } + return outC, len(records), nil } func init() { rootCmd.AddCommand(watchCmd) watchCmd.Flags().StringVarP(&watchConfig.configUrl, "configUrl", "c", core.ITArmyConfigURL, "Url of config containing url list") - watchCmd.Flags().Int64VarP(&watchConfig.testInterval, "testInterval", "i", 10, "Interval in seconds between test updates") + watchCmd.Flags().IntVarP(&watchConfig.testInterval, "testInterval", "i", 10, "Interval in seconds between test updates") watchCmd.Flags().IntVarP(&watchConfig.requestTimeout, "requestTimeout", "t", 5, "Request timeout") } diff --git a/core/printer.go b/core/printer.go index 0b0def1..d802d90 100644 --- a/core/printer.go +++ b/core/printer.go @@ -5,12 +5,14 @@ import ( "os/exec" "runtime" "strconv" + "sync" "github.com/jedib0t/go-pretty/v6/table" ) type Printer struct { clearFns map[string]func() + t table.Writer } func NewPrinter() Printer { @@ -26,21 +28,27 @@ func NewPrinter() Printer { cmd.Run() } - return Printer{clearFns: clear} -} - -func (p *Printer) ToTable(results *[]TestResult) { - p.Clear() t := table.NewWriter() t.SetStyle(table.StyleColoredBright) t.SetOutputMirror(os.Stdout) t.AppendHeader(table.Row{"Address", "Connection", "Status"}) - for _, r := range *results { - t.AppendRow(table.Row{r.url.Host, strconv.FormatInt(r.duration.Milliseconds(), 10) + "ms", r.status}) - } - t.AppendSeparator() - t.Render() + return Printer{clearFns: clear, t: t} +} + +func (p *Printer) ToTable(results *sync.Map) { + p.Clear() + p.t.ResetRows() + results.Range(func(k any, r interface{}) bool { + testResult, ok := r.(TestResult) + if ok { + p.t.AppendRow(table.Row{k, strconv.FormatInt(testResult.duration.Milliseconds(), 10) + "ms", testResult.status}) + } + return true + }) + p.t.SortBy([]table.SortBy{{Name: "Address"}}) + p.t.AppendSeparator() + p.t.Render() } func (p *Printer) Clear() { diff --git a/core/utils.go b/core/utils.go index cdbbadb..3a9f935 100644 --- a/core/utils.go +++ b/core/utils.go @@ -35,23 +35,30 @@ func GetStringFromURL(url string) (string, error) { } type TestResult struct { + Id string url url.URL status string duration time.Duration } -func Test(url *url.URL, timeoutSeconds int, out chan TestResult) { +func Test(url *url.URL, timeoutSeconds int, testInterval int, out chan TestResult) { timeout := time.Duration(timeoutSeconds) * time.Second tp := NewTransport(timeout) - _, err := tp.Dial(url.Scheme, url.Host) + for { + out <- TestResult{Id: url.Host, url: *url, status: "Test"} - if err != nil { - out <- TestResult{url: *url, status: formatError(err, url), duration: tp.ConnDuration()} - return - } + _, err := tp.Dial(url.Scheme, url.Host) + + if err != nil { + out <- TestResult{Id: url.Host, url: *url, status: formatError(err, url), duration: tp.ConnDuration()} + return + } - out <- TestResult{url: *url, status: "OK", duration: tp.Duration()} + out <- TestResult{Id: url.Host, url: *url, status: "OK", duration: tp.Duration()} + time.Sleep(time.Duration(testInterval) * time.Second) + + } } func formatError(err error, url *url.URL) string { diff --git a/monitor b/monitor index 610f135..158a8a5 100755 Binary files a/monitor and b/monitor differ