Example #1
0
// 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
}
Example #2
0
// 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
}
Example #3
0
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
}
Example #4
0
// 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
}
Example #5
0
// 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
}