//CheckService accepts a command and returns a status code, output (stdout) and the reaction time func CheckService(timeout int, command string) (status int, output string, rtime int64) { // Initialization. now := time.Now() //Convert executable to Go's os/exec.Command commandSlice := str.ToArgv(configuration.C.Paths.Checks + "/" + command) status, output = Execute(timeout, commandSlice[0], commandSlice[1:len(commandSlice)]...) //TODO: implement error logging elapsedTime := time.Since(now) elapsedTimeHuman := elapsedTime.Nanoseconds() / 1000000 symbol := message.StatusColor("●", status) log.Debug(symbol + " (" + strconv.Itoa(status) + ") - " + command + " - " + output) return status, output, elapsedTimeHuman }
// parseStringEnv parse the package Env string and converts it into an // environment slice. func parseStringEnv(s string) []string { env := []string{} if s == "" { return env } s = str.Clean(s) argv := str.ToArgv(s) for _, kv := range argv { if !strings.Contains(kv, "=") { continue } env = append(env, kv) } return env }
func splitCommand(command string) (executable string, argv, env []string) { argv = str.ToArgv(command) for i, item := range argv { if strings.Contains(item, "=") { if env == nil { env = []string{item} continue } env = append(env, item) } else { executable = item argv = argv[i+1:] return } } executable = argv[0] argv = argv[1:] return }
// PartitionKV parses a reader for sections reder for lines containing a prefix and assingment. func PartitionKV(r io.Reader, prefix string, assignment string) ([]map[string]string, error) { scanner := bufio.NewScanner(r) var buf bytes.Buffer var kv string var text string var result []map[string]string collect := false parseKV := func(kv string) { argv := str.ToArgv(kv) body := buf.String() for i, arg := range argv { m := map[string]string{} var key string var value string if strings.Contains(arg, assignment) { parts := strings.Split(arg, assignment) key = parts[0] value = parts[1] } else { key = arg value = "" } m[key] = value m["_body"] = body if i == 0 { m["_kind"] = key } result = append(result, m) } } for scanner.Scan() { text = scanner.Text() if strings.HasPrefix(text, prefix) { if kv != "" { parseKV(kv) } kv = text[len(prefix):] collect = true buf.Reset() continue } if collect { buf.WriteString(text) buf.WriteRune('\n') } } if err := scanner.Err(); err != nil { return nil, err } if kv != "" && buf.Len() > 0 { parseKV(kv) } if collect { return result, nil } return nil, nil }
func (nagiosCheck *NagiosCheck) Check() (events []common.MapStr, err error) { startTime := time.Now() startMs := startTime.UnixNano() / int64(time.Millisecond) check_event := common.MapStr{ "@timestamp": common.Time(startTime), "type": "nagioscheck", "name": nagiosCheck.name, "cmd": nagiosCheck.cmd, "args": nagiosCheck.args, } logp.Debug("nagioscheck", "Running Command: %q", nagiosCheck.cmd) arg_fields := str.ToArgv(nagiosCheck.args) cmd := exec.Command(nagiosCheck.cmd, arg_fields...) var waitStatus syscall.WaitStatus /* Go will return 'err' if the command exits abnormally (non-zero return code). Nagios commands always will exit abnormally when a check fails, so from a funcational perspective, this doesn't help us. Instead, if the ProcessState is nil, that tells us that the command coulnd't run for some reason, which does help. */ output, err := cmd.CombinedOutput() if cmd.ProcessState == nil { return } waitStatus = cmd.ProcessState.Sys().(syscall.WaitStatus) logp.Debug("nagioscheck", "Command Returned: %q, exit code %d", output, waitStatus.ExitStatus()) parts := strings.Split(string(output), "|") check_event["message"] = parts[0] check_event["status"] = nagiosperf.NiceStatus(waitStatus.ExitStatus()) check_event["took_ms"] = time.Now().UnixNano()/int64(time.Millisecond) - startMs // publish the check result, even if there is no perf data events = append(events, check_event) if len(parts) > 1 { logp.Debug("nagioscheck", "Parsing: %q", parts[1]) perfs, errors := nagiosperf.ParsePerfString(parts[1]) if len(errors) > 0 { for _, err := range errors { logp.Debug("parse_errors", "Parse Error: %v", err) } } logp.Debug("nagioscheck", "Command Returned '%d' Perf Metrics: %v", len(perfs), perfs) for _, perf := range perfs { metric_event := common.MapStr{ "@timestamp": common.Time(startTime), "type": "nagiosmetric", "name": nagiosCheck.name, "label": perf.Label, "uom": perf.Uom, "value": perf.Value, "min": perf.Min, "max": perf.Max, "warning": perf.Warning, "critical": perf.Critical, } events = append(events, metric_event) } } return }
/* Splits string by spaces, ignoring spaces between quotes */ func eachPerf(perfString string) []string { return str.ToArgv(perfString) }