// Check invokes the command and transforms its result to a Report. func (c Checker) Check() (*Report, error) { now := time.Now() command := c.Config.Command logger.Debugf("Checker %q executing command %q", c.Name, command) // NOTE(motemen): Should we consider using stderr? message, _, exitCode, err := util.RunCommand(command) if err != nil { return nil, err } status := StatusUnknown if s, ok := exitCodeToStatus[exitCode]; ok { status = s } logger.Debugf("Checker %q status=%s message=%q", c.Name, status, message) return &Report{ Name: c.Name, Status: status, Message: message, OccurredAt: now, }, nil }
// Check invokes the command and transforms its result to a Report. func (c Checker) Check() (*Report, error) { now := time.Now() command := c.Config.Command logger.Debugf("Checker %q executing command %q", c.Name, command) message, stderr, exitCode, err := util.RunCommand(command, c.Config.User) if stderr != "" { logger.Warningf("Checker %q output stderr: %s", c.Name, stderr) } status := StatusUnknown if err != nil { message = err.Error() } else { if s, ok := exitCodeToStatus[exitCode]; ok { status = s } logger.Debugf("Checker %q status=%s message=%q", c.Name, status, message) } return &Report{ Name: c.Name, Status: status, Message: message, OccurredAt: now, NotificationInterval: c.Config.NotificationInterval, MaxCheckAttempts: c.Config.MaxCheckAttempts, }, nil }
func (g *pluginGenerator) collectValues() (Values, error) { command := g.Config.Command pluginLogger.Debugf("Executing plugin: command = \"%s\"", command) os.Setenv(pluginConfigurationEnvName, "") stdout, stderr, _, err := util.RunCommand(command) if err != nil { pluginLogger.Errorf("Failed to execute command \"%s\" (skip these metrics):\n%s", command, stderr) return nil, err } results := make(map[string]float64, 0) for _, line := range strings.Split(stdout, "\n") { // Key, value, timestamp // ex.) tcp.CLOSING 0 1397031808 items := delimReg.Split(line, 3) if len(items) != 3 { continue } value, err := strconv.ParseFloat(items[1], 64) if err != nil { pluginLogger.Warningf("Failed to parse values: %s", err) continue } key := items[0] results[pluginPrefix+key] = value } return results, nil }
// Check invokes the command and transforms its result to a Report. func (c Checker) Check() (*Report, error) { now := time.Now() command := c.Config.Command logger.Debugf("Checker %q executing command %q", c.Name, command) message, stderr, exitCode, err := util.RunCommand(command) if stderr != "" { logger.Warningf("Checker %q output stderr: %s", c.Name, stderr) } if err != nil { return nil, err } status := StatusUnknown if s, ok := exitCodeToStatus[exitCode]; ok { status = s } logger.Debugf("Checker %q status=%s message=%q", c.Name, status, message) return &Report{ Name: c.Name, Status: status, Message: message, OccurredAt: now, }, nil }
// loadPluginMeta obtains plugin information (e.g. graph visuals, metric // namespaces, etc) from the command specified. // mackerel-agent runs the command with MACKEREL_AGENT_PLUGIN_META // environment variable set. The command is supposed to output like below: // // # mackerel-agent-plugin // { // "graphs": { // GRAPH_NAME: { // "label": GRAPH_LABEL, // "unit": UNIT_TYPE // "metrics": [ // { // "name": METRIC_NAME, // "label": METRIC_LABEL // }, // ... // ] // }, // GRAPH_NAME: ... // } // } // // Valid UNIT_TYPEs are: "float", "integer", "percentage", "bytes", "bytes/sec", "iops" // // The output should start with a line beginning with '#', which contains // meta-info of the configuration. (eg. plugin schema version) // // Below is a working example where the plugin emits metrics named "dice.d6" and "dice.d20": // // { // "graphs": { // "dice": { // "metrics": [ // { // "name": "d6", // "label": "Die (d6)" // }, // { // "name": "d20", // "label": "Die (d20)" // } // ], // "unit": "integer", // "label": "My Dice" // } // } // } func (g *pluginGenerator) loadPluginMeta() error { command := g.Config.Command pluginLogger.Debugf("Obtaining plugin configuration: %q", command) // Set environment variable to make the plugin command generate its configuration os.Setenv(pluginConfigurationEnvName, "1") defer os.Setenv(pluginConfigurationEnvName, "") stdout, stderr, exitCode, err := util.RunCommand(command, g.Config.User) if err != nil { return fmt.Errorf("running %q failed: %s, exit=%d stderr=%q", command, err, exitCode, stderr) } outBuffer := bufio.NewReader(strings.NewReader(stdout)) // Read the plugin configuration meta (version etc) headerLine, err := outBuffer.ReadString('\n') if err != nil { return fmt.Errorf("while reading the first line of command %q: %s", command, err) } // Parse the header line of format: // # mackerel-agent-plugin [key=value]... pluginMetaHeader := map[string]string{} re := regexp.MustCompile(`^#\s*mackerel-agent-plugin\b(.*)`) m := re.FindStringSubmatch(headerLine) if m == nil { return fmt.Errorf("bad format of first line: %q", headerLine) } for _, field := range strings.Fields(m[1]) { keyValue := strings.Split(field, "=") var value string if len(keyValue) > 1 { value = keyValue[1] } else { value = "" } pluginMetaHeader[keyValue[0]] = value } // Check schema version version, ok := pluginMetaHeader["version"] if !ok { version = "1" } if version != "1" { return fmt.Errorf("unsupported plugin meta version: %q", version) } conf := &pluginMeta{} err = json.NewDecoder(outBuffer).Decode(conf) if err != nil { return fmt.Errorf("while reading plugin configuration: %s", err) } g.Meta = conf return nil }