예제 #1
0
// buildMetrics creates the actual metrics for the given container.
func (d DockerStats) buildMetrics(container *docker.Container, containerStats *docker.Stats, cpuPercentage float64) []metric.Metric {
	ret := []metric.Metric{
		buildDockerMetric("DockerMemoryUsed", metric.Gauge, float64(containerStats.MemoryStats.Usage)),
		buildDockerMetric("DockerMemoryLimit", metric.Gauge, float64(containerStats.MemoryStats.Limit)),
		buildDockerMetric("DockerCpuPercentage", metric.Gauge, cpuPercentage),
		buildDockerMetric("DockerCpuThrottledPeriods", metric.CumulativeCounter, float64(containerStats.CPUStats.ThrottlingData.ThrottledPeriods)),
		buildDockerMetric("DockerCpuThrottledNanoseconds", metric.CumulativeCounter, float64(containerStats.CPUStats.ThrottlingData.ThrottledTime)),
	}
	for netiface := range containerStats.Networks {
		// legacy format
		txb := buildDockerMetric("DockerTxBytes", metric.CumulativeCounter, float64(containerStats.Networks[netiface].TxBytes))
		txb.AddDimension("iface", netiface)
		ret = append(ret, txb)
		rxb := buildDockerMetric("DockerRxBytes", metric.CumulativeCounter, float64(containerStats.Networks[netiface].RxBytes))
		rxb.AddDimension("iface", netiface)
		ret = append(ret, rxb)
	}
	additionalDimensions := map[string]string{
		"container_id":   container.ID,
		"container_name": strings.TrimPrefix(container.Name, "/"),
	}
	metric.AddToAll(&ret, additionalDimensions)
	ret = append(ret, buildDockerMetric("DockerContainerCount", metric.Counter, 1))
	metric.AddToAll(&ret, d.extractDimensions(container))

	return ret
}
예제 #2
0
// parseUWSGIMetrics11 will parse UWSGI metrics under the assumption of
// the response header containing a Metrics-Schema version 'uwsgi.1.1'.
func parseUWSGIMetrics11(raw *[]byte) ([]metric.Metric, error) {
	parsed := new(uwsgiJSONFormat1X)

	err := json.Unmarshal(*raw, parsed)
	if err != nil {
		return []metric.Metric{}, err
	}

	results := []metric.Metric{}
	appendIt := func(metrics []metric.Metric, typeDimVal string) {
		metric.AddToAll(&metrics, map[string]string{"type": typeDimVal})
		results = append(results, metrics...)
	}

	appendIt(convertToMetrics(&parsed.Gauges, metric.Gauge), "gauge")
	appendIt(convertToMetrics(&parsed.Meters, metric.Gauge), "meter")
	appendIt(convertToMetrics(&parsed.Counters, metric.Counter), "counter")
	appendIt(convertToMetrics(&parsed.Histograms, metric.Gauge), "histogram")
	appendIt(convertToMetrics(&parsed.Timers, metric.Gauge), "timer")

	// This is necessary as Go doesn't allow us to type assert
	// map[string]interface{} as map[string]string.
	// Basically go doesn't allow type assertions for interface{}'s nested
	// inside data structures across the entire structure since it is a linearly
	// complex action
	for k, v := range parsed.ServiceDims {
		metric.AddToAll(&results, map[string]string{k: v.(string)})
	}
	return results, nil
}
예제 #3
0
// buildMetrics creates the actual metrics for the given container.
func (d DockerStats) buildMetrics(container *docker.Container, memUsed, memLimit, cpuPercentage float64) []metric.Metric {
	ret := []metric.Metric{
		buildDockerMetric("DockerMemoryUsed", memUsed),
		buildDockerMetric("DockerMemoryLimit", memLimit),
		buildDockerMetric("DockerCpuPercentage", cpuPercentage),
	}
	additionalDimensions := map[string]string{
		"container_id":   container.ID,
		"container_name": strings.TrimPrefix(container.Name, "/"),
	}
	metric.AddToAll(&ret, additionalDimensions)
	metric.AddToAll(&ret, getServiceDimensions(container))

	return ret
}
예제 #4
0
// parseUWSGIMetrics takes the json returned from the endpoint and converts
// it into raw metrics. We first check that the metrics returned have a float value
// otherwise we skip the metric.
func parseUWSGIMetrics(raw *[]byte) ([]metric.Metric, error) {
	parsed := new(uwsgiJSONFormat)

	err := json.Unmarshal(*raw, parsed)
	if err != nil {
		return []metric.Metric{}, err
	}

	results := []metric.Metric{}
	appendIt := func(metrics []metric.Metric, typeDimVal string) {
		metric.AddToAll(&metrics, map[string]string{"type": typeDimVal})
		results = append(results, metrics...)
	}

	appendIt(convertToMetrics(&parsed.Gauges, metric.Gauge), "gauge")
	appendIt(convertToMetrics(&parsed.Meters, metric.Gauge), "meter")
	appendIt(convertToMetrics(&parsed.Counters, metric.Counter), "counter")
	appendIt(convertToMetrics(&parsed.Histograms, metric.Gauge), "histogram")
	appendIt(convertToMetrics(&parsed.Timers, metric.Gauge), "timer")

	if len(results) == 0 {
		// If parsing using UWSGI format did not work, the output is probably
		// in Dropwizard format and should be handled as such.
		return parseDropwizardMetric(raw)
	}
	return results, nil
}
예제 #5
0
func (n *nerveUWSGICollector) queryService(serviceName string, port int) {
	serviceLog := n.log.WithField("service", serviceName)

	endpoint := fmt.Sprintf("http://localhost:%d/%s", port, n.queryPath)
	serviceLog.Debug("making GET request to ", endpoint)

	rawResponse, err := queryEndpoint(endpoint, n.timeout)
	if err != nil {
		serviceLog.Warn("Failed to query endpoint ", endpoint, ": ", err)
		return
	}

	metrics, err := parseUWSGIMetrics(&rawResponse)
	if err != nil {
		serviceLog.Warn("Failed to parse response into metrics: ", err)
		return
	}

	metric.AddToAll(&metrics, map[string]string{
		"collector": n.Name(),
		"service":   serviceName,
		"port":      strconv.Itoa(port),
	})

	serviceLog.Debug("Sending ", len(metrics), " to channel")
	for _, m := range metrics {
		n.Channel() <- m
	}
}
예제 #6
0
func (ps ProcStatus) getMetrics(proc procfs.Proc, cmdOutput []string) []metric.Metric {
	stat, err := proc.NewStat()
	if err != nil {
		ps.log.Warn("Error getting stats: ", err)
		return nil
	}

	pid := strconv.Itoa(stat.PID)

	dim := map[string]string{
		"processName": stat.Comm,
		"pid":         pid,
	}

	ret := []metric.Metric{
		procStatusPoint("VirtualMemory", float64(stat.VirtualMemory()), dim),
		procStatusPoint("ResidentMemory", float64(stat.ResidentMemory()), dim),
		procStatusPoint("CPUTime", float64(stat.CPUTime()), dim),
	}

	if len(cmdOutput) > 0 {
		generatedDimensions := ps.extractDimensions(cmdOutput[0])
		metric.AddToAll(&ret, generatedDimensions)
	}

	return ret
}
예제 #7
0
// parseMetrics parse all the metrics according to the schemaVer.
// Always it tries to parse the metric with a base JSON format
// if it doesnt succed it will try with different parsing functions
func parseMetrics(raw *[]byte, schemaVer string, cumulCounterEnabled bool) ([]metric.Metric, error) {
	parsed := new(uwsgiJSONFormat1X)

	err := json.Unmarshal(*raw, &parsed)
	if err != nil {
		return []metric.Metric{}, err
	}

	results, err := parseUWSGIMetrics(parsed, cumulCounterEnabled)
	if err != nil {
		return results, err
	}

	if schemaVer == "uwsgi.1.1" {
		// This is necessary as Go doesn't allow us to type assert
		// map[string]interface{} as map[string]string.
		// Basically go doesn't allow type assertions for interface{}'s nested
		// inside data structures across the entire structure since it is a linearly
		// complex action
		for k, v := range parsed.ServiceDims {
			metric.AddToAll(&results, map[string]string{k: v.(string)})
		}
	} else if schemaVer == "default" && len(results) == 0 {
		return parseDropwizardMetrics(raw)
	}

	return results, nil
}
예제 #8
0
// buildMetrics creates the actual metrics for the given container.
func (d DockerStats) buildMetrics(container *docker.Container, containerStats *docker.Stats, cpuPercentage float64) []metric.Metric {
	ret := []metric.Metric{
		buildDockerMetric("DockerRxBytes", metric.CumulativeCounter, float64(containerStats.Network.RxBytes)),
		buildDockerMetric("DockerTxBytes", metric.CumulativeCounter, float64(containerStats.Network.TxBytes)),
		buildDockerMetric("DockerMemoryUsed", metric.Gauge, float64(containerStats.MemoryStats.Usage)),
		buildDockerMetric("DockerMemoryLimit", metric.Gauge, float64(containerStats.MemoryStats.Limit)),
		buildDockerMetric("DockerCpuPercentage", metric.Gauge, cpuPercentage),
	}
	additionalDimensions := map[string]string{
		"container_id":   container.ID,
		"container_name": strings.TrimPrefix(container.Name, "/"),
	}
	metric.AddToAll(&ret, additionalDimensions)
	metric.AddToAll(&ret, d.extractDimensions(container))

	return ret
}
예제 #9
0
// parseUWSGIMetrics takes the json returned from the endpoint and converts
// it into raw metrics. We first check that the metrics returned have a float value
// otherwise we skip the metric.
//
// @cumulCounterEnabled: if true it enables to create meter and timer counters as
// Cumultative Counters instead of Gauges
func parseUWSGIMetrics(parsed *uwsgiJSONFormat1X, cumulCounterEnabled bool) ([]metric.Metric, error) {
	results := []metric.Metric{}
	appendIt := func(metrics []metric.Metric, typeDimVal string) {
		metric.AddToAll(&metrics, map[string]string{"type": typeDimVal})
		results = append(results, metrics...)
	}

	appendIt(convertToMetrics(&parsed.Gauges, metric.Gauge, false), "gauge")
	appendIt(convertToMetrics(&parsed.Counters, metric.Counter, false), "counter")
	appendIt(convertToMetrics(&parsed.Histograms, metric.Gauge, false), "histogram")
	appendIt(convertToMetrics(&parsed.Meters, metric.Gauge, cumulCounterEnabled), "meter")
	appendIt(convertToMetrics(&parsed.Timers, metric.Gauge, cumulCounterEnabled), "timer")

	return results, nil
}
예제 #10
0
func extractParsedMetric(parser Parser, parsed *Format) []metric.Metric {
	results := []metric.Metric{}
	appendIt := func(metrics []metric.Metric, typeDimVal string) {
		if !parser.isCCEnabled() {
			metric.AddToAll(&metrics, map[string]string{"type": typeDimVal})
		}
		results = append(results, metrics...)
	}

	appendIt(parser.parseMapOfMap(parsed.Gauges, metric.Gauge), "gauge")
	appendIt(parser.parseMapOfMap(parsed.Counters, metric.Counter), "counter")
	appendIt(parser.parseMapOfMap(parsed.Histograms, metric.Gauge), "histogram")
	appendIt(parser.parseMapOfMap(parsed.Meters, metric.Gauge), "meter")
	appendIt(parser.parseMapOfMap(parsed.Timers, metric.Gauge), "timer")

	return results
}
예제 #11
0
// parseUWSGIMetrics11 will parse UWSGI metrics under the assumption of
// the response header containing a Metrics-Schema version 'uwsgi.1.1'.
func (parser *UWSGIMetric) parseUWSGIMetrics11() ([]metric.Metric, error) {
	parsed := new(Format)

	err := json.Unmarshal(parser.data, parsed)
	if err != nil {
		return []metric.Metric{}, err
	}

	results := extractParsedMetric(parser, parsed)

	// This is necessary as Go doesn't allow us to type assert
	// map[string]interface{} as map[string]string.
	// Basically go doesn't allow type assertions for interface{}'s nested
	// inside data structures across the entire structure since it is a linearly
	// complex action
	for k, v := range parsed.ServiceDims {
		metric.AddToAll(&results, map[string]string{k: v.(string)})
	}
	return results, nil
}
예제 #12
0
// metricFromMap takes in flattened maps formatted like this::
// {
//    "count":      3443,
//    "mean_rate": 100
// }
// and metricname and metrictype and returns metrics for each name:rollup pair
func (parser *BaseParser) metricFromMap(metricMap map[string]interface{},
	metricName string,
	metricType string) []metric.Metric {
	results := []metric.Metric{}
	dims := make(map[string]string)

	for rollup, value := range metricMap {
		// First check for dimension set if present
		// See uwsgi_metric.go:68 for explanation on the range over value
		if rollup == "dimensions" {
			for dimName, dimVal := range value.(map[string]interface{}) {
				dims[dimName] = dimVal.(string)
			}
			continue
		}

		mName := metricName
		mType := metricType
		matched, _ := regexp.MatchString("m[0-9]+_rate", rollup)

		// If cumulCounterEnabled is true:
		//		1. change metric type meter.count and timer.count moving them to cumulative counter
		//		2. don't send back metered metrics (rollup == 'mXX_rate')
		if parser.ccEnabled && matched {
			continue
		}
		if parser.ccEnabled && rollup != "value" {
			mName = metricName + "." + rollup
			if rollup == "count" {
				mType = metric.CumulativeCounter
			}
		}
		tempMetric, ok := parser.createMetricFromDatam(rollup, value, mName, mType)
		if ok {
			results = append(results, tempMetric)
		}
	}

	metric.AddToAll(&results, dims)
	return results
}
예제 #13
0
func (c *NerveHTTPD) getMetrics(serviceName string, port int) []metric.Metric {
	results := []metric.Metric{}
	serviceLog := c.log.WithField("service", serviceName)

	endpoint := fmt.Sprintf("http://%s:%d/%s", c.host, port, c.queryPath)
	serviceLog.Debug("making GET request to ", endpoint)

	httpResponse := fetchApacheMetrics(endpoint, port)

	if httpResponse.status != 200 {
		c.updateFailedStatus(serviceName, port, httpResponse.status)
		serviceLog.Warn("Failed to query endpoint ", endpoint, ": ", httpResponse.err)
		return results
	}
	apacheMetrics := extractApacheMetrics(httpResponse.data)
	metric.AddToAll(&apacheMetrics, map[string]string{
		"service": serviceName,
		"port":    strconv.Itoa(port),
	})
	return apacheMetrics
}
예제 #14
0
// parseUWSGIMetrics10 takes the json returned from the endpoint and converts
// it into raw metrics. We first check that the metrics returned have a float value
// otherwise we skip the metric.
func parseUWSGIMetrics10(raw *[]byte) ([]metric.Metric, error) {
	parsed := new(uwsgiJSONFormat1X)

	err := json.Unmarshal(*raw, parsed)
	if err != nil {
		return []metric.Metric{}, err
	}

	results := []metric.Metric{}
	appendIt := func(metrics []metric.Metric, typeDimVal string) {
		metric.AddToAll(&metrics, map[string]string{"type": typeDimVal})
		results = append(results, metrics...)
	}

	appendIt(convertToMetrics(&parsed.Gauges, metric.Gauge), "gauge")
	appendIt(convertToMetrics(&parsed.Meters, metric.Gauge), "meter")
	appendIt(convertToMetrics(&parsed.Counters, metric.Counter), "counter")
	appendIt(convertToMetrics(&parsed.Histograms, metric.Gauge), "histogram")
	appendIt(convertToMetrics(&parsed.Timers, metric.Gauge), "timer")

	return results, nil
}