Example #1
0
func (bs *BytesSamples) Average() procstats.Bytes {
	bytes := procstats.Bytes(0)

	valid := 0

	for _, s := range bs.slice {
		if s > 0 {
			bytes += s
			valid++
		}
	}

	return bytes / procstats.Bytes(valid)
}
Example #2
0
func (bs *BytesSamples) Median() procstats.Bytes {
	is := make([]int, len(bs.slice))

	for idx, val := range bs.slice {
		is[idx] = int(val)
	}

	sort.Ints(is)

	return procstats.Bytes(is[len(is)/2])
}
Example #3
0
func RunLoop(u *upstart.Conn, c *Config) error {
	if c.Poll.Seconds == 0 {
		c.Poll.Seconds = defaultPollSeconds
	}

	if c.Poll.Samples == 0 {
		c.Poll.Samples = defaultPollSamples
	}

	if c.Poll.Significant == 0 {
		c.Poll.Significant = (c.Poll.Samples / 2) + 1
	}

	sig := make(chan os.Signal)
	signal.Notify(sig, syscall.SIGHUP)

	e := NewEventDispatcher(c)

	sm := make(ServiceMetrics)

	var work []*Work

	for _, s := range c.Services {
		j, err := u.Job(s.Name)
		if err != nil {
			return err
		}

		s.action = j

		e.Dispatch(&Event{"monitor/start", s, nil})

		w := &Work{
			job:       j,
			srv:       s,
			memMetric: sm.Add(s, "memory/limit", c.Poll.Samples),
		}

		w.memMetric.Significant = c.Poll.Significant

		if mem := w.srv.Memory; mem != "" {
			bytes, err := mem.Bytes()
			if err != nil {
				continue
			}

			w.memMetric.Limit = procstats.Bytes(bytes)
		}

		work = append(work, w)
	}

	for {
		forest, err := procstats.DiscoverForest()
		if err != nil {
			return err
		}

		for _, w := range work {
			rpid, err := w.job.Pid()
			if err != nil {
				if w.pid == -1 {
					continue
				}

				w.pid = -1

				e.Dispatch(&Event{"monitor/down", w.srv, nil})
				continue
			}

			pid := procstats.Pid(rpid)

			if w.pid == -1 {
				e.Dispatch(&Event{"monitor/up", w.srv, nil})
			} else if w.pid != pid {
				e.Dispatch(&Event{"monitor/pid-change", w.srv, pid})
				w.memMetric.Reset()
			}

			w.pid = pid

			if gs, ok := forest.Processes[pid]; ok {
				rss := gs.TotalRSS()
				e.Dispatch(&Event{"memory/measured", w.srv, rss})
				w.memMetric.Add(e, rss)
			}
		}

		select {
		case <-sig:
			signal.Stop(sig)
			return ErrReload
		case <-time.After(time.Duration(c.Poll.Seconds) * time.Second):
			continue
		}
	}

	return nil
}