package dial import ( "fmt" "net/url" "os" "path/filepath" "strings" "time" "github.com/go-ping/ping" "github.com/pkg/errors" "github.com/rs/zerolog/log" "github.com/httprunner/httprunner/v4/hrp/internal/builtin" ) type PingOptions struct { Count int Timeout time.Duration Interval time.Duration SaveTests bool } type PingResult struct { Suc bool `json:"suc"` ErrMsg string `json:"errMsg"` Ip string `json:"ip"` AvgCost int `json:"avgCost"` MaxCost int `json:"maxCost"` MinCost int `json:"minCost"` Lost int `json:"lost"` PingCount int `json:"pingCount"` PacketSize int `json:"packetSize"` ReceivePacketCount int `json:"receivePacketCount"` SendPacketCount int `json:"sendPacketCount"` SuccessCount int `json:"successCount"` DebugLog string `json:"debugLog"` } func DoPing(pingOptions *PingOptions, args []string) (err error) { if len(args) != 1 { return errors.New("there should be one argument") } var pingResult PingResult defer func() { if pingOptions.SaveTests { dir, _ := os.Getwd() pingResultName := fmt.Sprintf("ping_result_%v.json", time.Now().Format("20060102150405")) pingResultPath := filepath.Join(dir, pingResultName) err = builtin.Dump2JSON(pingResult, pingResultPath) if err != nil { log.Error().Err(err).Msg("save ping result failed") } } }() pingTarget := args[0] parsedURL, err := url.Parse(pingTarget) if err == nil && parsedURL.Host != "" { log.Info().Msgf("parse input url %v and extract host %v", pingTarget, parsedURL.Host) pingTarget = strings.Split(parsedURL.Host, ":")[0] } log.Info().Msgf("ping host %v", pingTarget) pinger, err := ping.NewPinger(pingTarget) if err != nil { log.Error().Err(err).Msgf("fail to get pinger for %s", pingTarget) pingResult.Suc = false pingResult.ErrMsg = err.Error() pingResult.DebugLog = err.Error() return } pinger.Count = pingOptions.Count pinger.Timeout = pingOptions.Timeout pinger.Interval = pingOptions.Interval pinger.OnRecv = func(pkt *ping.Packet) { pingResult.DebugLog += fmt.Sprintf("%d bytes from %s: icmp_seq=%d time=%v\n", pkt.Nbytes, pkt.IPAddr, pkt.Seq, pkt.Rtt) } pinger.OnFinish = func(stats *ping.Statistics) { pingResult.DebugLog += fmt.Sprintf("\n--- %s ping statistics ---\n", stats.Addr) pingResult.DebugLog += fmt.Sprintf("%d packets transmitted, %d packets received, %v%% packet loss\n", stats.PacketsSent, stats.PacketsRecv, stats.PacketLoss) pingResult.DebugLog += fmt.Sprintf("round-trip min/avg/max/stddev = %v/%v/%v/%v\n", stats.MinRtt, stats.AvgRtt, stats.MaxRtt, stats.StdDevRtt) } pingResult.DebugLog += fmt.Sprintf("PING %s (%s):\n", pinger.Addr(), pinger.IPAddr()) err = pinger.Run() // blocks until finished if err != nil { log.Error().Err(err).Msgf("fail to run ping for %s", parsedURL) pingResult.Suc = false pingResult.ErrMsg = err.Error() pingResult.DebugLog = err.Error() return } fmt.Print(pingResult.DebugLog) stats := pinger.Statistics() // get send/receive/rtt stats pingResult.Ip = pinger.IPAddr().String() pingResult.AvgCost = int(stats.AvgRtt / time.Millisecond) pingResult.MaxCost = int(stats.MaxRtt / time.Millisecond) pingResult.MinCost = int(stats.MinRtt / time.Millisecond) pingResult.Lost = int(stats.PacketLoss) pingResult.PingCount = pingOptions.Count pingResult.PacketSize = pinger.Size pingResult.ReceivePacketCount = stats.PacketsRecv pingResult.SendPacketCount = stats.PacketsSent pingResult.SuccessCount = stats.PacketsRecv pingResult.Suc = true pingResult.ErrMsg = "" return }