func createPingFactory( config *Config, hostname string, port uint16, tls *transport.TLSConfig, request *http.Request, body []byte, validator RespCheck, ) func(*net.IPAddr) monitors.TaskRunner { fields := common.MapStr{ "scheme": request.URL.Scheme, "port": port, "url": request.URL.String(), } timeout := config.Timeout isTLS := request.URL.Scheme == "https" checkRedirect := makeCheckRedirect(config.MaxRedirects) return monitors.MakePingIPFactory(fields, func(ip *net.IPAddr) (common.MapStr, error) { addr := net.JoinHostPort(ip.String(), strconv.Itoa(int(port))) d := &dialchain.DialerChain{ Net: dialchain.ConstAddrDialer("tcp_connect_rtt", addr, timeout), } if isTLS { d.AddLayer(dialchain.TLSLayer("tls_handshake_rtt", tls, timeout)) } measures := common.MapStr{} dialer, err := d.BuildWithMeasures(measures) if err != nil { return nil, err } var httpStart, httpEnd time.Time client := &http.Client{ CheckRedirect: checkRedirect, Timeout: timeout, Transport: &SimpleTransport{ Dialer: dialer, OnStartWrite: func() { httpStart = time.Now() }, OnStartRead: func() { httpEnd = time.Now() }, }, } event, err := execPing(client, request, body, timeout, validator) if event == nil { event = measures } else { event.Update(measures) } if !httpEnd.IsZero() { event["http_rtt"] = look.RTT(httpEnd.Sub(httpStart)) } return event, err }) }
func create( info monitors.Info, cfg *common.Config, ) ([]monitors.Job, error) { config := DefaultConfig if err := cfg.Unpack(&config); err != nil { return nil, err } // TODO: check icmp is support by OS + check we've // got required credentials (implementation uses RAW socket, requires root + // not supported on all OSes) // TODO: replace icmp package base reader/sender using raw sockets with // OS specific solution var jobs []monitors.Job addJob := func(t monitors.Job, err error) error { if err != nil { return err } jobs = append(jobs, t) return nil } ipVersion := config.Mode.Network() if len(config.Hosts) > 0 && ipVersion == "" { err := fmt.Errorf("pinging hosts requires ipv4 or ipv6 mode enabled") return nil, err } var loopErr error loopInit.Do(func() { debugf("initialize icmp handler") loop, loopErr = newICMPLoop() }) if loopErr != nil { debugf("Failed to initialize ICMP loop %v", loopErr) return nil, loopErr } typ := config.Name network := config.Mode.Network() pingFactory := monitors.MakePingIPFactory(nil, createPingIPFactory(&config)) for _, host := range config.Hosts { ip := net.ParseIP(host) if ip != nil { name := fmt.Sprintf("icmp-ip@%v", ip.String()) err := addJob(monitors.MakeByIPJob(name, typ, ip, pingFactory)) if err != nil { return nil, err } continue } name := fmt.Sprintf("%v-host-%v@%v", config.Name, network, host) err := addJob(monitors.MakeByHostJob(name, typ, host, config.Mode, pingFactory)) if err != nil { return nil, err } } return jobs, nil }