Beispiel #1
0
func (i *Inspeqtor) Parse() error {
	i.ServiceManagers = services.Detect()

	config, err := ParseGlobal(i.RootDir)
	if err != nil {
		return err
	}
	util.DebugDebug("Global config: %+v", config)
	i.GlobalConfig = config

	host, err := ParseHost(i.GlobalConfig, i.RootDir+"/host.inq")
	if err != nil {
		return err
	}
	i.Host = host

	services, err := ParseServices(i.GlobalConfig, i.RootDir+"/services.d")
	if err != nil {
		return err
	}
	i.Services = services

	util.DebugDebug("Config: %+v", config)
	util.DebugDebug("Host: %+v", host)
	for _, val := range services {
		util.DebugDebug("Service: %+v", val)
	}

	return nil
}
Beispiel #2
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
}
Beispiel #3
0
func easyMemstatsClient(url string, msp func(*http.Response) (int64, error)) (int64, error) {
	util.DebugDebug("Fetching memstats from %s", url)
	resp, err := http.Get(url)
	if err != nil {
		return 0, err
	}
	defer resp.Body.Close()
	return msp(resp)
}
Beispiel #4
0
func (svc *Service) Reload() error {
	go func() {
		util.Debug("Reloading %s", svc.Name())
		err := svc.Manager.Reload(svc.Name())
		if err != nil {
			util.Warn(err.Error())
		} else {
			util.DebugDebug("Reloaded %s", svc.Name())
		}
	}()
	return nil
}
Beispiel #5
0
/*
Parses the service-specific rules in /etc/inspeqtor/services.d/*.inq
*/
func ParseServices(global *ConfigFile, confDir string) ([]Checkable, error) {
	util.Debug("Parsing config in " + confDir)
	files, err := filepath.Glob(confDir + "/*.inq")
	if err != nil {
		return nil, err
	}

	var checks []Checkable

	for _, filename := range files {
		util.DebugDebug("Parsing " + filename)
		data, err := ioutil.ReadFile(filename)
		if err != nil {
			return nil, err
		}

		s := lexer.NewLexer([]byte(data))
		p := parser.NewParser()
		obj, err := p.Parse(s)
		if err != nil {
			util.Warn("Unable to parse " + filename + ": " + err.Error())
			continue
		}

		switch x := obj.(type) {
		case *ast.ProcessCheck:
			svc, err := BuildService(global, x)
			if err != nil {
				return nil, err
			}
			util.DebugDebug("Service: %+v", *svc)
			checks = append(checks, svc)
		default:
			return nil, fmt.Errorf("Invalid configuration file: %s", filename)
		}
	}

	return checks, nil
}
Beispiel #6
0
func parseJobs(global *inspeqtor.ConfigFile, confDir string) (map[string]*Job, error) {
	util.Debug("Parsing jobs in " + confDir)
	files, err := filepath.Glob(confDir + "/jobs.d/*.inq")
	if err != nil {
		return nil, err
	}

	jobs := map[string]*Job{}

	for _, filename := range files {
		util.DebugDebug("Parsing " + filename)
		data, err := ioutil.ReadFile(filename)
		if err != nil {
			return nil, err
		}

		s := lexer.NewLexer([]byte(data))
		p := parser.NewParser()
		obj, err := p.Parse(s)
		if err != nil {
			util.Warn("Unable to parse " + filename + ": " + err.Error())
			continue
		}

		astcontent := obj.(*ast.Content)
		for _, astjob := range astcontent.Jobs {
			if _, ok := jobs[astjob.Name]; ok {
				return nil, fmt.Errorf("Duplicate job %s", astjob.Name)
			}

			j := New(astjob.Name, astjob.Interval, astcontent.Parameters)

			owner := j.Parameters["owner"]
			route := global.AlertRoutes[owner]
			if owner == "" && route == nil {
				return nil, fmt.Errorf("No default alert route configured!")
			}
			if route == nil {
				return nil, fmt.Errorf("No such alert route: %s", owner)
			}
			alert, err := inspeqtor.Actions["alert"](j, route)
			if err != nil {
				return nil, err
			}
			j.alerter = alert
			jobs[astjob.Name] = j
		}
	}

	return jobs, nil
}
Beispiel #7
0
func (svc *Service) Restart() error {
	svc.Process.Pid = 0
	svc.Process.Status = services.Starting
	go func() {
		util.Debug("Restarting %s", svc.Name())
		err := svc.Manager.Restart(svc.Name())
		if err != nil {
			util.Warn(err.Error())
		} else {
			util.DebugDebug("Restarted %s", svc.Name())
		}
	}()
	return nil
}
Beispiel #8
0
/*
Parses the host-specific rules in /etc/inspeqtor/host.inq
*/
func ParseHost(global *ConfigFile, hostInq string) (*Host, error) {
	var host *Host

	result, err := util.FileExists(hostInq)
	if err != nil {
		return nil, err
	}
	if !result {
		return nil, fmt.Errorf("Missing required file: %s", hostInq)
	}

	util.DebugDebug("Parsing " + hostInq)
	data, err := ioutil.ReadFile(hostInq)
	if err != nil {
		return nil, err
	}

	s := lexer.NewLexer([]byte(data))
	p := parser.NewParser()
	obj, err := p.Parse(s)
	if err != nil {
		return nil, err
	}

	switch x := obj.(type) {
	case *ast.HostCheck:
		host, err = BuildHost(global, x)
		if err != nil {
			return nil, err
		}
		util.DebugDebug("Host: %+v", *host)
	default:
		return nil, fmt.Errorf("Invalid host.inq configuration file")
	}

	return host, nil
}
Beispiel #9
0
func convertService(global *ConfigFile, inqsvc *ast.ProcessCheck) (*Service, error) {
	rules := make([]*Rule, len(inqsvc.Rules))
	storage := metrics.NewProcessStore("/proc", global.CycleTime)

	svc := &Service{&Entity{inqsvc.Name, nil, storage, inqsvc.Parameters}, nil, services.NewStatus(), nil}

	action, err := BuildAction(global, svc, &ast.SimpleAction{ActionName: "alert"})
	if err != nil {
		return nil, err
	}
	svc.EventHandler = action

	for idx, rule := range inqsvc.Rules {
		rule, err := convertRule(global, svc, rule)
		if err != nil {
			return nil, err
		}
		util.DebugDebug("Rule: %+v", *rule)
		rules[idx] = rule
	}
	svc.rules = rules

	for _, r := range rules {
		_, err := storage.AddSource(r.MetricFamily, svc.Parameters())
		if err != nil {
			return nil, err
		}

		err = storage.Watch(r.MetricFamily, r.MetricName)
		if err != nil {
			return nil, err
		}
		util.Debug("Watching %s:%s", r.MetricFamily, r.MetricName)
	}

	if len(inqsvc.Exposed) > 0 {
		err := BuildExpose(global, svc, inqsvc.Exposed, inqsvc.Parameters)
		if err != nil {
			return nil, err
		}
	}

	err = storage.Prepare()
	if err != nil {
		return nil, err
	}
	return svc, nil
}
Beispiel #10
0
// this method never returns.
//
// since we can't test this method in an automated fashion, it should
// contain as little logic as possible.
func (i *Inspeqtor) runLoop() {
	util.DebugDebug("Resolving services")
	for _, svc := range i.Services {
		err := svc.Resolve(i.ServiceManagers)
		if err != nil {
			util.Warn(err.Error())
		}
	}

	i.scanSystem()

	for {
		select {
		case <-time.After(time.Duration(i.GlobalConfig.CycleTime) * time.Second):
			i.scanSystem()
		case <-i.Stopping:
			util.Debug("Shutting down main run loop")
			return
		}
	}
}
Beispiel #11
0
// GACK, so ugly
func convertHost(global *ConfigFile, inqhost *ast.HostCheck) (*Host, error) {
	hostname, err := os.Hostname()
	if err != nil {
		return nil, err
	}

	storage := metrics.NewHostStore("/proc", global.CycleTime)
	h := &Host{&Entity{hostname, nil, storage, inqhost.Parameters}}
	rules := make([]*Rule, len(inqhost.Rules))
	for idx, rule := range inqhost.Rules {
		rule, err := BuildRule(global, h, rule)
		util.DebugDebug("Rule: %+v", rule)
		if err != nil {
			return nil, err
		}
		err = storage.Watch(rule.MetricFamily, rule.MetricName)
		if err != nil {
			return nil, err
		}
		rules[idx] = rule
	}
	h.rules = rules
	return h, nil
}