Exemple #1
0
func (l *Launchd) Restart(serviceName string) error {
	path := l.resolvePlist(serviceName)
	if path == "" {
		return &ServiceError{l.Name(), serviceName, ErrServiceNotFound}
	}

	cmd := exec.Command("launchctl", "unload", path)
	sout, err := util.SafeRun(cmd)
	if err != nil {
		return &ServiceError{l.Name(), serviceName, err}
	}

	lines, err := util.ReadLines(sout)
	if len(lines) != 0 {
		return &ServiceError{l.Name(), serviceName, errors.New("Unexpected output: " + strings.Join(lines, "\n"))}
	}

	cmd = exec.Command("launchctl", "load", path)
	sout, err = util.SafeRun(cmd)
	if err != nil {
		return &ServiceError{l.Name(), serviceName, err}
	}

	lines, err = util.ReadLines(sout)
	if len(lines) != 0 {
		return &ServiceError{l.Name(), serviceName, errors.New("Unexpected output: " + strings.Join(lines, "\n"))}
	}
	return nil
}
Exemple #2
0
func (hs *hostStorage) collectDisk(path string) error {
	var lines []string

	if path == "" {
		cmd := exec.Command("df", "-P")
		sout, err := util.SafeRun(cmd)
		if err != nil {
			return err
		}
		lines, err = util.ReadLines(sout)
		if err != nil {
			return err
		}
	} else {
		data, err := ioutil.ReadFile(path)
		if err != nil {
			return err
		}
		lines, err = util.ReadLines(data)
		if err != nil {
			return err
		}
	}

	usage := map[string]float64{}

	for _, line := range lines {
		if line[0] == '/' {
			items := strings.Fields(line)
			if len(items) < 5 {
				util.Debug("Cannot parse df output: %v", items)
				continue
			}
			pct := items[4]
			if pct[len(pct)-1] == '%' {
				val, err := strconv.ParseInt(pct[0:len(pct)-1], 10, 32)
				if err != nil {
					util.Debug("Cannot parse df output: " + line)
				}
				usage[items[len(items)-1]] = float64(val)
			}

		}
	}

	for name, used := range usage {
		hs.saveType("disk", name, used, Gauge)
	}
	return nil
}
Exemple #3
0
func (rs *redisSource) runCli(funk executor) (metrics.Map, error) {
	sout, err := funk("redis-cli", rs.buildArgs(), nil)
	lines, err := util.ReadLines(sout)
	if err != nil {
		return nil, err
	}

	values := map[string]float64{}

	for _, line := range lines {
		if line == "" || line[0] == '#' {
			continue
		}
		parts := strings.Split(line, ":")
		if rs.metrics[parts[0]] {
			val, err := strconv.ParseInt(parts[1], 10, 64)
			if err != nil {
				return nil, errors.New("Invalid metric input for '" + line + "': " + err.Error())
			}
			values[parts[0]] = float64(val)
		}
	}

	if len(rs.metrics) > len(values) {
		for k := range rs.metrics {
			if _, ok := values[k]; !ok {
				util.Warn("Could not find metric redis(%s), did you spell it right?", k)
			}
		}
	}

	return values, nil
}
Exemple #4
0
func (rs *mysqlSource) runRepl(values metrics.Map, funk executor) (metrics.Map, error) {
	args := rs.buildArgs()
	args = append(args, "-e")
	args = append(args, "show slave status\\G")
	sout, err := funk("mysql", args, nil)
	lines, err := util.ReadLines(sout)
	if err != nil {
		return nil, err
	}

	for _, line := range lines {
		if line == "" || line[0] == '*' {
			continue
		}
		parts := strings.Fields(line)
		if parts[0] == "Seconds_Behind_Master:" {
			if parts[0] == "NULL" {
				values["Seconds_Behind_Master"] = 999999
			} else {
				val, err := strconv.ParseInt(parts[1], 10, 64)
				if err != nil {
					return nil, errors.New("Invalid metric input for '" + line + "': " + err.Error())
				}
				values["Seconds_Behind_Master"] = float64(val)
			}
		}
	}
	return values, nil
}
Exemple #5
0
/*
  Collecting total RSS for a process is actually rather involved on Linux.
	Because of this, we only collect the value if the user defines a rule
	for it.  This is a "dynamicCollector".
*/
func totalRssCollector(mypid int, ps *processStorage) error {
	matches, err := filepath.Glob(fmt.Sprintf("%s/[1-9][0-9]*/status", ps.path))
	if err != nil {
		return err
	}
	var live []processEntry

	for _, file := range matches {
		pe := processEntry{}

		data, err := ioutil.ReadFile(file)
		if err != nil {
			// race condition between globbing and reading, process
			// can disappear at any moment
			continue
		}

		lines, err := util.ReadLines(data)
		if err != nil {
			return err
		}
		for _, line := range lines {
			if line[0] == 'V' || line[0] == 'P' {
				items := strings.Split(line, ":")
				switch items[0] {
				case "Pid":
					pid, err := strconv.Atoi(strings.TrimSpace(items[1]))
					if err != nil {
						return err
					}
					pe.pid = pid
				case "PPid":
					ppid, err := strconv.Atoi(strings.TrimSpace(items[1]))
					if err != nil {
						return err
					}
					pe.ppid = ppid
				case "VmRSS":
					vals := strings.Fields(items[1])
					val, err := strconv.ParseInt(vals[0], 10, 64)
					if err != nil {
						return err
					}
					pe.rss = val * 1024
				}
			}
		}

		if pe.rss != 0 {
			live = append(live, pe)
		}
	}
	util.DebugDebug("Calculating %d processes", len(live))

	rss := memoryFor(live, mypid)
	util.DebugDebug("Total RSS for %d: %d", mypid, rss)

	ps.Save("memory", "total_rss", float64(rss))
	return nil
}
Exemple #6
0
func runSql(pg *pgSource, stmt string) ([][]string, error) {
	args := pg.buildArgs()
	args = append(args, "-c")
	args = append(args, stmt)
	sout, err := pg.execFunk("psql", args, nil)
	if err != nil {
		return nil, errors.New(string(sout))
	}

	lines, err := util.ReadLines(sout)
	if err != nil {
		return nil, err
	}

	var table [][]string

	for _, line := range lines {
		if line == "" {
			continue
		}
		var row []string
		cells := strings.Split(line, "|")
		for _, cell := range cells {
			row = append(row, strings.TrimSpace(cell))
		}
		table = append(table, row)
	}

	return table, nil
}
Exemple #7
0
func (ps *processStorage) captureVM(pid int) error {
	dir := ps.path + "/" + strconv.Itoa(int(pid))
	data, err := ioutil.ReadFile(dir + "/status")
	if err != nil {
		return err
	}

	lines, err := util.ReadLines(data)
	if err != nil {
		return err
	}
	for _, line := range lines {
		if line[0] == 'V' {
			items := strings.Fields(line)
			switch items[0] {
			case "VmRSS:":
				val, err := strconv.ParseInt(items[1], 10, 64)
				if err != nil {
					return err
				}
				ps.Save("memory", "rss", float64(1024*val))
			}
		}

	}

	return nil
}
Exemple #8
0
func (l *Launchd) LookupService(serviceName string) (*ProcessStatus, error) {
	cmd := exec.Command("launchctl", "list")
	sout, err := util.SafeRun(cmd)
	if err != nil {
		return nil, &ServiceError{l.Name(), serviceName, err}
	}

	lines, err := util.ReadLines(sout)
	if err != nil {
		return nil, &ServiceError{l.Name(), serviceName, err}
	}

	for _, line := range lines {
		if strings.Contains(line, serviceName) {
			util.Debug("launchctl found " + serviceName)
			parts := strings.SplitN(line, "\t", 3)
			pid, err := strconv.ParseInt(parts[0], 10, 32)
			if err != nil {
				return nil, &ServiceError{l.Name(), serviceName, err}
			}

			return &ProcessStatus{int(pid), Up}, nil
		}
	}

	path := l.resolvePlist(serviceName)
	if path != "" {
		return &ProcessStatus{0, Down}, nil
	}

	return nil, &ServiceError{l.Name(), serviceName, ErrServiceNotFound}
}
Exemple #9
0
func (u *Upstart) LookupService(serviceName string) (*ProcessStatus, error) {
	matches, err := filepath.Glob(u.path + "/" + serviceName + ".conf")
	if err != nil {
		return nil, &ServiceError{u.Name(), serviceName, err}
	}

	if len(matches) == 0 {
		return nil, &ServiceError{u.Name(), serviceName, ErrServiceNotFound}
	}

	var sout []byte
	if u.dummyOutput != nil {
		sout = []byte(*u.dummyOutput)
	} else {
		cmd := exec.Command("initctl", "status", serviceName)
		sout, err = util.SafeRun(cmd)
		if err != nil {
			return nil, &ServiceError{u.Name(), serviceName, err}
		}
	}

	lines, err := util.ReadLines(sout)
	if len(lines) != 1 {
		return nil, &ServiceError{u.Name(), serviceName, errors.New("Unexpected output: " + strings.Join(lines, "\n"))}
	}

	// mysql start/running, process 14190
	// sshdgenkeys stop/waiting
	line := lines[0]
	if strings.Contains(line, "Unknown job") {
		return nil, &ServiceError{u.Name(), serviceName, ErrServiceNotFound}
	}

	results := pidScanner.FindStringSubmatch(line)

	if len(results) == 4 && len(results[3]) > 0 {
		pid, err := strconv.ParseInt(results[3], 10, 32)
		if err != nil {
			return nil, &ServiceError{u.Name(), serviceName, err}
		}
		return &ProcessStatus{int(pid), Up}, nil
	}

	if len(results) == 4 {
		switch {
		case results[1] == "start":
			return &ProcessStatus{0, Starting}, nil
		case results[1] == "stop":
			return &ProcessStatus{0, Down}, nil
		}
	}

	return nil, &ServiceError{u.Name(), serviceName, errors.New("Unknown upstart output: " + line)}
}
Exemple #10
0
/*
 * So many hacks in this.  OSX support can be seen as "bad" at best.
 */
func (ps *processStorage) capturePs(pid int) error {
	cmd := exec.Command("ps", "So", "rss,time,utime", "-p", strconv.Itoa(pid))
	sout, err := util.SafeRun(cmd)
	if err != nil {
		return err
	}

	lines, err := util.ReadLines(sout)
	if err != nil {
		return err
	}

	if len(lines) < 2 {
		return errors.New("Insufficient output from ps")
	}

	fields := strings.Fields(lines[1])
	val, err := strconv.ParseInt(fields[0], 10, 64)
	if err != nil {
		return err
	}

	ps.Save("memory", "rss", float64(1024*val))

	times := timeRegexp.FindStringSubmatch(fields[1])
	if times == nil {
		util.Debug("Unable to parse CPU time in " + lines[1])
		return nil
	}
	min, _ := strconv.ParseUint(times[1], 10, 32)
	sec, _ := strconv.ParseUint(times[2], 10, 32)
	cs, _ := strconv.ParseUint(times[3], 10, 32)

	ticks := min*60*100 + sec*100 + cs

	times = timeRegexp.FindStringSubmatch(fields[2])
	if times == nil {
		util.Debug("Unable to parse User time in " + lines[1])
		return nil
	}
	min, _ = strconv.ParseUint(times[1], 10, 32)
	sec, _ = strconv.ParseUint(times[2], 10, 32)
	cs, _ = strconv.ParseUint(times[3], 10, 32)

	uticks := min*60*100 + sec*100 + cs

	ps.Save("cpu", "user", float64(uticks))
	ps.Save("cpu", "system", float64(ticks-uticks))

	return nil
}
Exemple #11
0
func (hs *hostStorage) collectLoadAverage() error {
	// TODO make this a one-time check so we don't incur the overhead
	// on every cycle.
	ok, err := util.FileExists(hs.path + "/loadavg")
	if err != nil {
		return err
	}

	var loadavgString string
	if ok {
		contentBytes, err := ioutil.ReadFile(hs.path + "/loadavg")
		if err != nil {
			return err
		}
		loadavgString = string(contentBytes)
	} else {
		cmd := exec.Command("sysctl", "-n", "vm.loadavg")
		cmd.Env = []string{"LANG=C"}
		sout, err := util.SafeRun(cmd)
		if err != nil {
			return err
		}
		lines, err := util.ReadLines(sout)
		if err != nil {
			return err
		}
		loadavgString = lines[0][2 : len(lines[0])-2] // trim braces
	}

	slices := strings.Split(loadavgString, " ")
	load1, err := strconv.ParseFloat(slices[0], 64)
	if err != nil {
		return err
	}
	load5, err := strconv.ParseFloat(slices[1], 64)
	if err != nil {
		return err
	}
	load15, err := strconv.ParseFloat(slices[2], 64)
	if err != nil {
		return err
	}

	hs.Save("load", "1", load1)
	hs.Save("load", "5", load5)
	hs.Save("load", "15", load15)
	return nil
}
Exemple #12
0
func (s *Systemd) LookupService(serviceName string) (*ProcessStatus, error) {
	var sout []byte
	var err error

	if len(s.dummyOutput) != 0 {
		sout = []byte(s.dummyOutput)
	} else {
		cmd := exec.Command("systemctl", "show", "-p", "MainPID", serviceName)
		sout, err = util.SafeRun(cmd)
	}

	if err != nil {
		return nil, &ServiceError{s.Name(), serviceName, ErrServiceNotFound}
	}
	lines, err := util.ReadLines(sout)
	if len(lines) != 1 {
		return nil, &ServiceError{s.Name(), serviceName, errors.New("Unexpected output: " + strings.Join(lines, "\n"))}
	}

	// Output will be "MainPID=1234" or
	// "MainPID=0" if service does not exist.
	line := lines[0]
	fields := strings.Split(line, "=")
	if fields[1] != "0" {
		pid, err := strconv.ParseInt(fields[1], 10, 32)
		if err != nil {
			return nil, &ServiceError{s.Name(), serviceName, err}
		}
		return &ProcessStatus{int(pid), Up}, nil
	}

	if len(s.dummyOutput2) != 0 {
		sout = []byte(s.dummyOutput2)
	} else {
		cmd := exec.Command("systemctl", "is-enabled", serviceName)
		sout, err = util.SafeRun(cmd)
	}

	if err != nil || string(sout) != "enabled\n" {
		return nil, &ServiceError{s.Name(), serviceName, ErrServiceNotFound}
	}
	return &ProcessStatus{0, Down}, nil
}
Exemple #13
0
func (u *Upstart) serviceCommand(serviceName string, command string, timeout time.Duration, expectedLines int) error {
	var err error
	var sout []byte

	if u.dummyOutput != nil {
		sout = []byte(*u.dummyOutput)
	} else {
		cmd := exec.Command("initctl", command, serviceName)
		sout, err = util.SafeRun(cmd, timeout)
		if err != nil {
			return &ServiceError{u.Name(), serviceName, err}
		}
	}

	lines, err := util.ReadLines(sout)
	if len(lines) != expectedLines {
		return &ServiceError{u.Name(), serviceName, errors.New("Unexpected output: " + strings.Join(lines, "\n"))}
	}
	return nil
}
Exemple #14
0
func (ps *processStorage) captureCPU(pid int) error {
	dir := ps.path + "/" + strconv.Itoa(int(pid))
	data, err := ioutil.ReadFile(dir + "/stat")
	if err != nil {
		return err
	}

	lines, err := util.ReadLines(data)
	if err != nil {
		return err
	}
	for _, line := range lines {
		fields := strings.Fields(line)
		utime, err := strconv.ParseInt(fields[13], 10, 64)
		if err != nil {
			return err
		}
		stime, err := strconv.ParseInt(fields[14], 10, 64)
		if err != nil {
			return err
		}
		cutime, err := strconv.ParseInt(fields[15], 10, 64)
		if err != nil {
			return err
		}
		cstime, err := strconv.ParseInt(fields[16], 10, 64)
		if err != nil {
			return err
		}
		ps.Save("cpu", "user", float64(utime))
		ps.Save("cpu", "system", float64(stime))
		ps.Save("cpu", "total_user", float64(cutime))
		ps.Save("cpu", "total_system", float64(cstime))
	}

	return nil
}
Exemple #15
0
func (rs *memcachedSource) runCli(funk executor) (metrics.Map, error) {
	sout, err := funk("nc", []string{rs.Hostname, rs.Port}, []byte("stats\n"))
	if err != nil {
		return nil, err
	}
	lines, err := util.ReadLines(sout)
	if err != nil {
		return nil, err
	}

	values := map[string]float64{}

	for _, line := range lines {
		if line == "" || line[0] != 'S' {
			continue
		}
		parts := strings.Fields(line)
		if rs.metrics[parts[1]] {
			val, err := strconv.ParseFloat(parts[2], 64)
			if err != nil {
				return nil, errors.New("Invalid metric input for '" + line + "': " + err.Error())
			}
			values[parts[1]] = val
		}
	}

	if len(rs.metrics) > len(values) {
		for k := range rs.metrics {
			if _, ok := values[k]; !ok {
				util.Info("Could not find metric %s(%s), did you spell it right?", rs.Name(), k)
			}
		}
	}

	return values, nil
}
Exemple #16
0
func (rs *mysqlSource) runStatus(funk executor) (metrics.Map, error) {
	args := rs.buildArgs()
	args = append(args, "-e")
	args = append(args, "show global status")
	sout, err := funk("mysql", args, nil)
	lines, err := util.ReadLines(sout)
	if err != nil {
		return nil, err
	}

	values := map[string]float64{}

	for _, line := range lines {
		if line == "" || line[0] == '#' {
			continue
		}
		parts := strings.Fields(line)
		if rs.metrics[parts[0]] {
			val, err := strconv.ParseInt(parts[1], 10, 64)
			if err != nil {
				return nil, errors.New("Invalid metric input for '" + line + "': " + err.Error())
			}
			values[parts[0]] = float64(val)
		}
	}

	if len(rs.metrics) > len(values) {
		for k := range rs.metrics {
			if _, ok := values[k]; !ok {
				util.Warn("Could not find metric mysql(%s), did you spell it right?", k)
			}
		}
	}

	return values, nil
}
Exemple #17
0
func (rs *mysqlSource) Prepare() error {
	if !rs.metrics["Seconds_Behind_Master"] {
		return nil
	}
	args := rs.buildArgs()
	args = append(args, "-e")
	args = append(args, "show status like 'Slave_running'")
	sout, err := rs.exec("mysql", args, nil)
	if err != nil {
		return err
	}
	lines, err := util.ReadLines(sout)
	if err != nil {
		return err
	}

	parts := strings.Fields(lines[1])
	if parts[1] != "ON" {
		return errors.New("Cannot monitor mysql replication, slave not running")
	}
	delete(rs.metrics, "Seconds_Behind_Master")
	rs.captureRepl = true
	return nil
}
Exemple #18
0
func (hs *hostStorage) collectMemory() error {
	ok, err := util.FileExists(hs.path + "/meminfo")
	if err != nil {
		return err
	}

	if ok {
		contentBytes, err := ioutil.ReadFile(hs.path + "/meminfo")
		if err != nil {
			return err
		}
		lines := strings.Split(string(contentBytes), "\n")

		memMetrics := make(map[string]float64)
		for _, line := range lines {
			if line == "" {
				continue
			}

			results := meminfoParser.FindStringSubmatch(line)
			if results == nil {
				util.Warn("Unknown input: " + line)
				continue
			}
			val, err := strconv.ParseInt(results[2], 10, 64)
			if err != nil {
				util.Warn("Unexpected input: " + results[2] + " in " + line)
				return err
			}
			memMetrics[results[1]] = float64(val)
		}

		free := memMetrics["SwapFree"]
		total := memMetrics["SwapTotal"]
		if free == 0 {
			hs.Save("swap", "", 100)
		} else if free == total {
			hs.Save("swap", "", 0)
		} else {
			hs.Save("swap", "", float64(100-int8(100*(float64(free)/float64(total)))))
		}
	} else {
		cmd := exec.Command("sysctl", "-n", "vm.swapusage")
		cmd.Env = []string{"LANG=C"}
		sout, err := util.SafeRun(cmd)
		if err != nil {
			return err
		}
		lines, err := util.ReadLines(sout)
		if err != nil {
			return err
		}

		rest := lines[0]
		matches := swapRegexp.FindStringSubmatch(rest)
		total := matches[1]
		rest = matches[2]

		matches = swapRegexp.FindStringSubmatch(rest)
		used := matches[1]

		tot, err := strconv.ParseFloat(total[0:len(total)-1], 64)
		if err != nil {
			return err
		}
		usd, err := strconv.ParseFloat(used[0:len(used)-1], 64)
		if err != nil {
			return err
		}

		t := normalizeSwap(tot, rune(total[len(total)-1]))
		u := normalizeSwap(usd, rune(used[len(used)-1]))
		if t == 0 {
			hs.Save("swap", "", 100)
		} else {
			hs.Save("swap", "", float64(100*(u/t)))
		}
	}

	return nil
}