Ejemplo n.º 1
0
func (m *Monitor) Start() error {
	if m.Name == "" {
		return e.New("empty name")
	}
	if m.Url == "" {
		return e.New("empty url")
	}
	if m.Periode == 0 {
		return e.New("periode must be greater than zero")
	}
	m.chclose = make(chan chan struct{})
	go func() {
		for {
			select {
			case ch := <-m.chclose:
				ch <- struct{}{}
				return
			case <-time.After(m.Periode):
				resp := m.ping()
				select {
				case err := <-resp:
					if err == nil {
						if m.status != statusOk && m.OnUnFail != nil {
							err := m.OnUnFail(m)
							if err != nil {
								log.Errorf("OnUnFail for %v returned an error: %v", m.Name, err)
							}
						}
						m.status = statusOk
						continue
					}
					m.fail()
					continue
				case <-time.After(m.Timeout):
					log.Errorf("Ping timeout for %v", m.Name)
					m.fail()
				}
			}
		}
	}()
	return nil
}
Ejemplo n.º 2
0
func (m *Monitor) ping() (resp chan error) {
	resp = make(chan error)
	go func() {
		log.DebugLevel().Printf("Pinging %v", m.Name)
		start := time.Now()
		err := ping.PingRawUrl(m.Url)
		if err != nil {
			log.Errorf("Ping failed for %v with error: %v", m.Name, e.Trace(e.Forward(err)))
			resp <- e.Forward(err)
			return
		}
		log.DebugLevel().Printf("Ping ok for %v (%v)", m.Name, time.Since(start))
		resp <- nil
	}()
	return
}
Ejemplo n.º 3
0
func (m *Monitor) fail() {
	m.count++
	if m.Fails != 0 || m.Fails <= m.count {
		m.count = 0
		m.status = statusFail
		if m.OnFail == nil {
			return
		}
		err := m.OnFail(m)
		if err != nil {
			log.Errorf("Onfail function on %v returned an error: %v", m.Name, err)
		}
		log.Printf("%v going to sleep for %v", m.Name, m.Sleep)
		select {
		case <-time.After(m.Sleep):
		case ch := <-m.chclose:
			ch <- struct{}{}
			return
		}
	}
}
Ejemplo n.º 4
0
func (c *Client) client(addr string) (*Response, error) {
	ip, err := ipport(c.Interface, addr, "0")
	if err != nil {
		return nil, e.Push(err, ErrCantFindInt)
	}
	client, err := net.ResolveUDPAddr("udp", ip)
	if err != nil {
		return nil, e.Push(err, ErrCantFindInt)
	}
	c.conn, err = net.ListenUDP("udp", client)
	if err != nil {
		return nil, e.Push(err, ErrCantFindInt)
	}
	var dst *net.UDPAddr
	if c.iface.Flags&net.FlagLoopback == net.FlagLoopback {
		ip, err := ipport(c.Interface, addr, c.Port)
		if err != nil {
			return nil, e.Push(err, ErrCantFindInt)
		}
		dst, err = net.ResolveUDPAddr("udp", ip)
		if err != nil {
			return nil, e.Push(err, ErrCantFindInt)
		}
	} else if !c.NotMulticast && c.iface.Flags&net.FlagMulticast == net.FlagMulticast {
		dst, err = c.multicast(c.conn.LocalAddr())
		if err != nil {
			return nil, e.Push(err, ErrCantFindInt)
		}
	} else if c.iface.Flags&net.FlagBroadcast == net.FlagBroadcast {
		dst, err = broadcast(c.conn.LocalAddr(), c.Port)
		if err != nil {
			return nil, e.Push(err, ErrCantFindInt)
		}
	} else {
		return nil, e.Push(e.New("interface isn't suported: %v", c.iface.Flags), ErrCantFindInt)
	}
	log.ProtoLevel().Tag("discover", "client").Printf("Local ip %v.", c.conn.LocalAddr())
	log.ProtoLevel().Tag("discover", "client").Printf("Try to contact server in %v.", dst)
	now := time.Now()
	end := now.Add(c.Timeout)
	for d := now; d.Before(end) || d.Equal(end); d = time.Now() {
		req, err := c.Request(dst)
		if err != nil {
			return nil, e.Forward(err)
		}

		req.Id = c.Id
		req.Ip = c.conn.LocalAddr().String()

		err = c.encode(protoReq, req, dst)
		if e.Contains(err, "i/o timeout") {
			log.Errorf("Error %v -> %v: %v", c.conn.LocalAddr(), dst, err)
			continue
		} else if err != nil {
			return nil, e.Forward(err)
		}

		resp, err := c.response()
		if e.Contains(err, "i/o timeout") {
			log.Errorf("Error %v -> %v: %v", c.conn.LocalAddr(), dst, err)
			continue
		} else if err != nil {
			return nil, e.Forward(err)
		}

		c.Id = resp.Id

		err = c.encode(protoConfirm, resp.Id, dst)
		if e.Contains(err, "i/o timeout") {
			log.Errorf("Error %v -> %v: %v", c.conn.LocalAddr(), dst, err)
			continue
		} else if err != nil {
			return nil, e.Forward(err)
		}

		rp, err := c.response()
		if e.Contains(err, "i/o timeout") {
			log.Errorf("Error %v -> %v: %v", c.conn.LocalAddr(), dst, err)
			continue
		} else if err != nil {
			return nil, e.Forward(err)
		}

		if rp.Id != resp.Id {
			return nil, e.New("protocol fail wrong response")
		}

		go func(dst *net.UDPAddr) {
			for {
				select {
				case <-time.After(c.Keepalive):
					log.ProtoLevel().Tag("client", "discover").Printf("Send keep alive to %v", dst)
					err := c.keepalive(dst)
					if err != nil {
						log.Tag("client", "discover").Errorf("Keep alive to %v failed: %v", dst, err)
						return
					}
				case ch := <-c.stopKa:
					ch <- struct{}{}
					return
				}
			}
		}(dst)

		return resp, nil
	}
	return nil, e.New("can't find the server")
}
Ejemplo n.º 5
0
func main() {
	println("Starting monlite...")
	// Configuration
	var opts options
	_, err := flags.Parse(&opts)
	if err != nil {
		log.Fatal("can't parse the command line options:", err)
	}
	cfg, err := ini.Load(opts.Conf)
	if err != nil {
		log.Fatal("Error reading configuratio file:", opts.Conf)
	}

	// Log stuff
	println("Log...")
	name := appname
	pid := os.Getpid()
	pidstr := strconv.FormatInt(int64(pid), 10)
	name = name + " (" + pidstr + ")"

	fnull, err := os.OpenFile("/dev/null", os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0660)
	if err != nil {
		log.Fatal("open log file failed:", err)
	}
	defer fnull.Close()
	stderrBack := log.NewWriter(fnull).F(log.DefFormatter)
	if opts.Level != "" && opts.Level != "nolog" {
		level, err := log.ParseLevel(opts.Level)
		if err != nil {
			log.Fatal("Invalid log level.")
		}
		stderrBack = log.Filter(
			log.NewWriter(os.Stderr).F(log.DefFormatter),
			log.Op(log.Ge, "level", level),
		)
	}

	logfile := cfg.Section("log").Key("file").MustString("/var/log/monlite.log")
	if opts.Log != "" {
		logfile = opts.Log
	}
	loglevel := cfg.Section("log").Key("level").MustString("debug")
	level, err := log.ParseLevel(loglevel)
	if err != nil {
		log.Fatal("Invalid log level.")
	}
	var fileBack log.LogBackend
	if logfile != "" {
		f, err := os.OpenFile(logfile, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0660)
		if err != nil {
			log.Fatalf("open log file %v failed: %v", logfile, err)
		}
		defer f.Close()
		fileBack = log.Filter(
			log.NewWriter(f).F(log.DefFormatter),
			log.Op(log.Ge, "level", level),
		)
	}

	log.Log = log.New(stderrBack, true).Domain(name).InfoLevel()
	if fileBack != nil {
		log.Log = log.New(
			log.NewMulti(
				stderrBack,
				log.DefFormatter,
				fileBack,
				log.DefFormatter,
			),
			true,
		).Domain(name).InfoLevel()
	}

	log.Println("Log Ok!")

	dns.SetLookupHostFunction(net.LookupHost)

	log.Println("Configuration...")

	cfgMail := cfg.Section("mail")

	smtpTimeout, err := cfgMail.Key("timeout").Int()
	if err != nil {
		log.Fatal("invalid smtp timeout")
	}

	server := cfgMail.Key("smtp").String()
	s := strings.Split(server, ":")
	if len(s) > 0 {
		server = s[0]
	}

	auth := smtp.PlainAuth(
		"",
		cfgMail.Key("account").String(),
		cfgMail.Key("password").String(),
		server,
	)

	hostname := "your system"
	if hn, err := os.Hostname(); err == nil {
		hostname = hn
	}

	mons := make([]*monlite.Monitor, 0)
	for _, sec := range cfg.Sections() {
		if !strings.HasPrefix(sec.Name(), "service.") {
			continue
		}
		name := strings.TrimPrefix(sec.Name(), "service.")
		log.DebugLevel().Printf("Adding monitor %v for url: %v", name, sec.Key("url").String())
		to, err := sec.Key("timeout").Int()
		if err != nil {
			log.Fatalf("invalid value in timeout for %v", name)
		}
		p, err := sec.Key("periode").Int()
		if err != nil {
			log.Fatalf("invalid value in timeout for %v", name)
		}
		sleep, err := sec.Key("sleep").Int()
		if err != nil {
			log.Fatalf("invalid value in sleep for %v", name)
		}
		fails, err := sec.Key("fails").Int()
		if err != nil {
			log.Fatalf("invalid value in fails for %v", name)
		}
		mons = append(mons, &monlite.Monitor{
			Name:    name,
			Url:     sec.Key("url").String(),
			Timeout: time.Duration(to) * time.Second,
			Periode: time.Duration(p) * time.Second,
			Sleep:   time.Duration(sleep) * time.Second,
			Fails:   fails,
			OnFail: func(m *monlite.Monitor) error {

				body := "Mime-Version: 1.0\n"
				body += "Content-Type: text/plain; charset=utf-8\n"
				body += "From:" + cfgMail.Key("from").String() + "\n"
				body += "To:" + cfgMail.Key("to").String() + "\n"
				body += "Subject: [" + hostname + "] " + "Monitor fail for " + m.Name + "\n"
				body += "Hi! This is " + hostname + ".\n\n"
				body += "Monitor fail for " + m.Name + " " + m.Url + "\n\n"
				body += "Tank you, our lazy boy.\n"
				body += time.Now().Format(time.RFC1123Z)

				err := mysmtp.SendMail(
					cfgMail.Key("smtp").String(),
					auth,
					cfgMail.Key("from").String(),
					[]string{cfgMail.Key("to").String()},
					cfgMail.Key("helo").String(),
					[]byte(body),
					time.Duration(smtpTimeout)*time.Second,
					false,
				)
				if err != nil {
					return e.Forward(err)
				}
				return nil
			},
			OnUnFail: func(m *monlite.Monitor) error {

				body := "Mime-Version: 1.0\n"
				body += "Content-Type: text/plain; charset=utf-8\n"
				body += "From:" + cfgMail.Key("from").String() + "\n"
				body += "To:" + cfgMail.Key("to").String() + "\n"
				body += "Subject: [" + hostname + "] " + "Monitor ok for " + m.Name + "\n"
				body += "Hi! This is " + hostname + ".\n\n"
				body += "Monitor ok for " + m.Name + " " + m.Url + "\n\n"
				body += "Tank you, our lazy boy.\n"
				body += time.Now().Format(time.RFC1123Z)

				err := mysmtp.SendMail(
					cfgMail.Key("smtp").String(),
					auth,
					cfgMail.Key("from").String(),
					[]string{cfgMail.Key("to").String()},
					cfgMail.Key("helo").String(),
					[]byte(body),
					time.Duration(smtpTimeout)*time.Second,
					false,
				)
				if err != nil {
					return e.Forward(err)
				}
				return nil
			},
		})
	}

	log.Println("Starting monitors...")

	for _, m := range mons {
		err := m.Start()
		if err != nil {
			log.Fatalf("Failed to start monitor for %v. Error: %v", m.Name, err)
		}
	}

	log.Println("Monitors ok!")

	sig := make(chan os.Signal)
	signal.Notify(sig, syscall.SIGINT, syscall.SIGKILL, syscall.SIGTERM)
	<-sig

	log.Println("Stop monitors...")

	for _, m := range mons {
		log.DebugLevel().Printf("Stop monitor %v", m.Name)
		err := m.Stop()
		if err != nil {
			log.Errorf("Failed to start monitor for %v. Error: %v", m.Name, err)
		}
	}
	log.Println("End.")
}