package main import ( "log" "net/http" "os" "time" "github.com/go-ping/ping" "golang.org/x/image/colornames" "gonum.org/v1/plot" "gonum.org/v1/plot/plotter" "gonum.org/v1/plot/vg" "gonum.org/v1/plot/vg/draw" "gonum.org/v1/plot/vg/vgsvg" ) type stat struct { t time.Duration errs int ok bool } var csec = 0 var pastHour [3600]stat var cmin = 0 var pastWeek [10080]stat func pinger() { var q [60]time.Duration pinger := ping.New("1.1.1.1") // pinger.Interval = time.Millisecond * 1000 pinger.OnRecv = func(p *ping.Packet) { pastHour[p.Seq-3600*(p.Seq/3600)] = stat{t: p.Rtt, ok: true} sec := p.Seq - 60*(p.Seq/60) q[sec] = p.Rtt // fmt.Printf("%+v\n", p) if p.Seq%60 == 0 { var errs int var sum time.Duration for _, x := range q { sum += x if sum == 0 { errs++ } } sum /= (60 - time.Duration(errs)) pastWeek[(p.Seq-10080*(p.Seq/10080))/60] = stat{t: sum, ok: true} // fmt.Println("past minute", sum) } } pinger.OnSend = func(p *ping.Packet) { pastHour[p.Seq-3600*(p.Seq/3600)] = stat{t: p.Rtt, ok: true} sec := p.Seq - 60*(p.Seq/60) csec = p.Seq - 3600*(p.Seq/3600) q[sec] = p.Rtt // fmt.Printf("%+v\n", p) if p.Seq%60 == 0 { var sum time.Duration for _, x := range q { sum += x } sum /= 60 cmin = (p.Seq - 10080*(p.Seq/10080)) / 60 //fmt.Println(cmin) pastWeek[(p.Seq-10080*(p.Seq/10080))/60] = stat{t: sum, ok: true} // fmt.Println("past minute", sum) } } if len(os.Args) > 1 { pinger.SetPrivileged(true) } if err := pinger.Resolve(); err != nil { log.Fatalln(err) } if err := pinger.Run(); err != nil { log.Fatalln(err) } } func pingEP(w http.ResponseWriter, r *http.Request) { p := plot.New() p.Title.Text = "Ping over past hour" p.X.Label.Text = "Time (seconds)" p.Y.Label.Text = "Ping (ms)" current := csec var period = pastHour[:] if r.URL.Query().Get("week") != "" { period = pastWeek[:] p.Title.Text = "Ping over past week" p.X.Label.Text = "Time (minutes)" current = cmin } maxPing := 0. maxErrs := 0 var pingpoints = make(plotter.XYs, len(period)) var errspoints = make(plotter.XYs, len(period)) for i, x := range period { if !x.ok { pingpoints = pingpoints[:i] errspoints = errspoints[:i] break } pingpoints[i] = plotter.XY{ Y: float64(x.t) / float64(time.Millisecond), X: float64(i), } errs := 0 switch { case x.errs != 0: errs = x.errs case x.t == 0: errs = 1 } errspoints[i] = plotter.XY{ Y: float64(errs), X: float64(i), } if float64(x.t)/float64(time.Millisecond) > maxPing { maxPing = float64(x.t) / float64(time.Millisecond) } if errs > maxErrs { maxErrs = errs } } switch { case maxErrs == 0: case maxErrs == 1: for i := range errspoints { errspoints[i].Y *= maxPing } default: for i, x := range errspoints { errspoints[i].Y = (x.Y / float64(maxErrs)) * maxPing } } p.Legend.Top = true /* plotutil.DefaultColors = []color.Color{ colornames.Dodgerblue, colornames.Darkseagreen, colornames.Red, } plotutil.DefaultDashes = [][]vg.Length{ {vg.Points(2), vg.Points(4)}, {}, {}, } plotutil.AddLines(p, "Now", plotter.XYs{{X: float64(current), Y: maxPing}, {X: float64(current), Y: 0}}, "Ping", pingpoints, "Errs", errspoints, )*/ nowline, err := plotter.NewLine(plotter.XYs{{X: float64(current), Y: maxPing}, {X: float64(current), Y: 0}}) if err != nil { panic(err) } nowline.Color = colornames.Dodgerblue nowline.Dashes = []vg.Length{vg.Points(2), vg.Points(4)} p.Add(nowline) p.Legend.Add("Now", nowline) pingline, err := plotter.NewLine(pingpoints) if err != nil { panic(err) } pingline.Color = colornames.Darkseagreen p.Add(pingline) p.Legend.Add("Ping", pingline) errsline, err := plotter.NewLine(errspoints) if err != nil { panic(err) } errsline.Color = colornames.Red p.Add(errsline) p.Legend.Add("Errors", errsline) canv := vgsvg.New(vg.Millimeter*290, vg.Millimeter*200) p.Draw(draw.New(canv)) w.Header().Set("content-type", "image/svg+xml") canv.WriteTo(w) }