Пример #1
0
// Generate XXX
func (g *InterfaceGenerator) Generate() (metrics.Values, error) {
	prevValues, err := g.collectIntarfacesValues()
	if err != nil {
		return nil, err
	}

	time.Sleep(g.Interval)

	currValues, err := g.collectIntarfacesValues()
	if err != nil {
		return nil, err
	}

	ret := make(map[string]float64)
	for name, value := range prevValues {
		if !postInterfaceMetricsRegexp.MatchString(name) {
			continue
		}
		currValue, ok := currValues[name]
		if ok {
			ret[name+".delta"] = (currValue - value) / g.Interval.Seconds()
		}
	}

	return metrics.Values(ret), nil
}
Пример #2
0
// Generate XXX
func (g *FilesystemGenerator) Generate() (metrics.Values, error) {
	filesystems, err := util.CollectDfValues(dfColumnSpecs)
	if err != nil {
		return nil, err
	}

	ret := make(map[string]float64)
	for name, values := range filesystems {
		// https://github.com/docker/docker/blob/v1.5.0/daemon/graphdriver/devmapper/deviceset.go#L981
		if regexp.MustCompile(`^/dev/mapper/docker-`).FindStringSubmatch(name) != nil {
			continue
		}
		if matches := regexp.MustCompile(`^/dev/(.*)$`).FindStringSubmatch(name); matches != nil {
			device := regexp.MustCompile(`[^A-Za-z0-9_-]`).ReplaceAllString(matches[1], "_")
			for key, value := range values {
				intValue, valueTypeOk := value.(int64)
				if valueTypeOk {
					// kilo bytes -> bytes
					ret["filesystem."+device+"."+key] = float64(intValue) * 1024
				}
			}
		}
	}

	return metrics.Values(ret), nil
}
Пример #3
0
// Generate XXX
func (g *CPUUsageGenerator) Generate() (metrics.Values, error) {
	prevValues, prevTotal, _, err := g.collectProcStatValues()
	if err != nil {
		return nil, err
	}

	time.Sleep(g.Interval)

	currValues, currTotal, cpuCount, err := g.collectProcStatValues()
	if err != nil {
		return nil, err
	}

	ret := make(map[string]float64)
	for i, name := range cpuUsageMetricNames {
		// Values in /proc/stat differ in Linux kernel versions.
		// Not all metrics in cpuUsageMetricNames can be retrieved.
		// ref: `man 5 proc`
		if i >= len(currValues) || i >= len(prevValues) {
			break
		}

		// percentage of increased amount of CPU time
		ret[name+".percentage"] = (currValues[i] - prevValues[i]) * 100.0 * float64(cpuCount) / (currTotal - prevTotal)
	}

	return metrics.Values(ret), nil
}
Пример #4
0
// Generate XXX
func (g *UptimeGenerator) Generate() (metrics.Values, error) {
	if g == nil {
		return nil, errors.New("UptimeGenerator is not initialized")
	}
	r, _, err := windows.GetTickCount.Call()
	if r == 0 {
		return nil, err
	}

	return metrics.Values(map[string]float64{"uptime": float64(r) / 1000}), nil
}
Пример #5
0
func (g *InterfaceGenerator) collectIntarfacesValues() (metrics.Values, error) {
	out, err := exec.Command("netstat", "-bni").Output()
	if err != nil {
		interfaceLogger.Errorf("Failed to invoke netstat: %s", err)
		return nil, err
	}

	lineScanner := bufio.NewScanner(bytes.NewReader(out))

	results := make(map[string]float64)
	hasNonZeroValue := false
	for lineScanner.Scan() {
		line := lineScanner.Text()
		fields := strings.Fields(line)
		name := regexp.MustCompile(`[^A-Za-z0-9_-]`).ReplaceAllString(regexp.MustCompile(`\*`).ReplaceAllString(fields[0], ""), "_")
		if match, _ := regexp.MatchString(`^lo\d+$`, name); match {
			continue
		}
		if match, _ := regexp.MatchString(`^<Link#\d+>$`, fields[2]); match {
			rxIndex, txIndex := getFieldIndex(fields)
			rxKey := fmt.Sprintf("interface.%s.rxBytes", name)
			rxValue, rxErr := strconv.ParseFloat(fields[rxIndex], 64)
			if rxErr != nil {
				interfaceLogger.Warningf("Failed to parse host interfaces: %s", err)
				break
			}
			results[rxKey] = rxValue
			if rxValue != 0 {
				hasNonZeroValue = true
			}
			txKey := fmt.Sprintf("interface.%s.txBytes", name)
			txValue, txErr := strconv.ParseFloat(fields[txIndex], 64)
			if txErr != nil {
				interfaceLogger.Warningf("Failed to parse host interfaces: %s", err)
				break
			}
			results[txKey] = txValue
			if txValue != 0 {
				hasNonZeroValue = true
			}
		}
	}
	// results (eth0) sample
	/** [%!s(*metrics.Value=&{interface.eth0.rxBytes 6.6074069281e+10})
	     %!s(*metrics.Value=&{interface.eth0.txBytes 9.180531994e+09})
	    ]
	**/
	if hasNonZeroValue {
		return metrics.Values(results), nil
	}
	return nil, nil
}
Пример #6
0
// Generate generate metrics values
func (g *MemoryGenerator) Generate() (metrics.Values, error) {
	file, err := os.Open("/proc/meminfo")
	if err != nil {
		memoryLogger.Errorf("Failed (skip these metrics): %s", err)
		return nil, err
	}
	scanner := bufio.NewScanner(file)

	ret := make(map[string]float64)
	used := float64(0)
	usedCnt := 0
	for scanner.Scan() {
		line := scanner.Text()
		for k, regexp := range memItems {
			if matches := regexp.FindStringSubmatch(line); matches != nil {
				// ex.) MemTotal:        3916792 kB
				// matches[1] = 3916792, matches[2] = kB
				if matches[2] != "kB" {
					memoryLogger.Warningf("/proc/meminfo contains an invalid unit: %s", k)
					break
				}
				value, err := strconv.ParseFloat(matches[1], 64)
				if err != nil {
					memoryLogger.Warningf("Failed to parse memory metrics: %s", err)
					break
				}
				ret["memory."+k] = value * 1024
				if k == "free" || k == "buffers" || k == "cached" {
					used -= value
					usedCnt++
				}
				if k == "total" {
					used += value
					usedCnt++
				}
				break
			}
		}
	}
	if err := scanner.Err(); err != nil {
		memoryLogger.Errorf("Failed (skip these metrics): %s", err)
		return nil, err
	}
	if usedCnt == 4 { // 4 is free, buffers, cached and total
		ret["memory.used"] = used * 1024
	}

	return metrics.Values(ret), nil
}
Пример #7
0
// Generate XXX
func (g *Loadavg5Generator) Generate() (metrics.Values, error) {
	contentbytes, err := ioutil.ReadFile("/proc/loadavg")
	if err != nil {
		loadavg5Logger.Errorf("Failed (skip these metrics): %s", err)
		return nil, err
	}
	content := string(contentbytes)
	cols := strings.Split(content, " ")

	f, err := strconv.ParseFloat(cols[1], 64)
	if err != nil {
		loadavg5Logger.Errorf("Failed to parse loadavg5 metrics (skip these metrics): %s", err)
		return nil, err
	}

	return metrics.Values(map[string]float64{"loadavg5": f}), nil
}
Пример #8
0
// Generate generate metrics values
func (g *UptimeGenerator) Generate() (metrics.Values, error) {
	contentbytes, err := ioutil.ReadFile("/proc/uptime")
	if err != nil {
		uptimeLogger.Errorf("Failed (skip these metrics): %s", err)
		return nil, err
	}
	content := string(contentbytes)
	cols := strings.Split(content, " ")

	f, err := strconv.ParseFloat(cols[0], 64)
	if err != nil {
		uptimeLogger.Errorf("Failed to parse values (skip these metrics): %s", err)
		return nil, err
	}

	return metrics.Values(map[string]float64{"uptime": f / 86400}), nil
}
Пример #9
0
// Generate XXX
func (g *FilesystemGenerator) Generate() (metrics.Values, error) {
	filesystems, err := windows.CollectFilesystemValues()
	if err != nil {
		return nil, err
	}

	ret := make(map[string]float64)
	for name, values := range filesystems {
		if matches := regexp.MustCompile(`^(.*):`).FindStringSubmatch(name); matches != nil {
			device := regexp.MustCompile(`[^A-Za-z0-9_-]`).ReplaceAllString(matches[1], "_")

			ret["filesystem."+device+".size"] = values.KbSize * 1024
			ret["filesystem."+device+".used"] = values.KbUsed * 1024
		}
	}

	logger.Debugf("%q", ret)

	return metrics.Values(ret), nil
}
Пример #10
0
// Generate returns current CPU usage of the host.
// Keys below are expected:
// - cpu.user.percentage
// - cpu.system.percentage
// - cpu.idle.percentage
func (g *CPUUsageGenerator) Generate() (metrics.Values, error) {

	// % iostat -c2 -C
	//             CPU
	// us ni sy in id
	//  0  0  0  0 100
	//  0  0  0  0 100

	iostatBytes, err := exec.Command("iostat", "-c2", "-d", "-C").Output()
	if err != nil {
		cpuUsageLogger.Errorf("Failed to invoke iostat: %s", err)
		return nil, err
	}

	iostat := string(iostatBytes)
	lines := strings.Split(iostat, "\n")
	if len(lines) != 5 {
		return nil, fmt.Errorf("iostat result malformed: [%q]", iostat)
	}

	fields := strings.Fields(lines[3])
	if len(fields) < len(iostatFieldToMetricName) {
		return nil, fmt.Errorf("iostat result malformed: [%q]", iostat)
	}

	cpuUsage := make(map[string]float64, len(iostatFieldToMetricName))

	for i, n := range iostatFieldToMetricName {
		if i == 3 {
			continue
		}
		value, err := strconv.ParseFloat(fields[i], 64)
		if err != nil {
			return nil, err
		}

		cpuUsage["cpu."+n+".percentage"] = value
	}

	return metrics.Values(cpuUsage), nil
}
Пример #11
0
// Generate XXX
func (g *MemoryGenerator) Generate() (metrics.Values, error) {
	ret := make(map[string]float64)

	var memoryStatusEx windows.MEMORY_STATUS_EX
	memoryStatusEx.Length = uint32(unsafe.Sizeof(memoryStatusEx))
	r, _, err := windows.GlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(&memoryStatusEx)))
	if r == 0 {
		return nil, err
	}

	free := float64(memoryStatusEx.AvailPhys)
	total := float64(memoryStatusEx.TotalPhys)
	ret["memory.free"] = free
	ret["memory.total"] = total
	ret["memory.used"] = total - free
	ret["memory.pagefile_total"] = float64(memoryStatusEx.TotalPageFile) / 1024
	ret["memory.pagefile_free"] = float64(memoryStatusEx.AvailPageFile) / 1024

	memoryLogger.Debugf("memory : %s", ret)
	return metrics.Values(ret), nil
}
Пример #12
0
func parseNetdev(out []byte) (metrics.Values, error) {
	lineScanner := bufio.NewScanner(bytes.NewReader(out))
	results := make(map[string]float64)
	for lineScanner.Scan() {
		line := lineScanner.Text()
		if kv := strings.SplitN(line, ":", 2); len(kv) == 2 {
			name := sanitizerReg.ReplaceAllString(strings.TrimSpace(kv[0]), "_")
			if name == "lo" {
				continue
			}

			cols := strings.Fields(kv[1])
			if len(cols) < len(interfaceMetrics) {
				continue
			}

			interfaceResult := make(map[string]float64)
			hasNonZeroValue := false
			for i, metricName := range interfaceMetrics {
				key := fmt.Sprintf("interface.%s.%s", name, metricName)
				value, err := strconv.ParseFloat(cols[i], 64)
				if err != nil {
					interfaceLogger.Warningf("Failed to parse host interfaces: %s", err)
					break
				}
				if value != 0 {
					hasNonZeroValue = true
				}
				interfaceResult[key] = value
			}
			if hasNonZeroValue {
				for k, v := range interfaceResult {
					results[k] = v
				}
			}
		}
	}

	return metrics.Values(results), nil
}
Пример #13
0
// Generate generate metrics values
func (g *MemoryGenerator) Generate() (metrics.Values, error) {
	outBytes, err := exec.Command("vm_stat").Output()
	if err != nil {
		memoryLogger.Errorf("Failed (skip these metrics): %s", err)
		return nil, err
	}
	out := string(outBytes)
	lines := strings.Split(out, "\n")

	stats := map[string]int64{}
	for _, line := range lines {
		if matches := statReg.FindStringSubmatch(line); matches != nil {
			v, _ := strconv.ParseInt(matches[2], 0, 64)
			// `vm_stat` returns the page sise of 4096 bytes
			stats[matches[1]] = v * 4096
		}
	}

	wired := stats["Pages wired down"]
	compressed := stats["Pages occupied by compressor"]

	cached := stats["Pages purgeable"] + stats["File-backed pages"]
	active := stats["Pages active"]
	inactive := stats["Pages inactive"]
	used := wired + compressed + active + inactive + stats["Pages speculative"] - cached
	free := stats["Pages free"]
	total := used + cached + free

	ret := map[string]float64{
		"memory.total":    float64(total),
		"memory.used":     float64(used),
		"memory.cached":   float64(cached),
		"memory.free":     float64(free),
		"memory.active":   float64(active),
		"memory.inactive": float64(inactive),
	}

	return metrics.Values(ret), nil
}
Пример #14
0
func generateValues(generators []metrics.Generator) chan metrics.Values {
	processed := make(chan metrics.Values)
	finish := make(chan bool)
	result := make(chan metrics.Values)

	go func() {
		allValues := metrics.Values(make(map[string]float64))
		for {
			select {
			case values := <-processed:
				allValues.Merge(values)
			case <-finish:
				result <- allValues
				return
			}
		}
	}()

	go func() {
		var wg sync.WaitGroup
		for _, g := range generators {
			wg.Add(1)
			go func(g metrics.Generator) {
				defer wg.Done()

				values, err := g.Generate()
				if err != nil {
					logger.Errorf("Failed to generate value in %T (skip this metric): %s", g, err.Error())
					return
				}
				processed <- values
			}(g)
		}
		wg.Wait()
		finish <- true // processed all jobs
	}()

	return result
}
Пример #15
0
// Generate XXX
func (g *FilesystemGenerator) Generate() (metrics.Values, error) {
	filesystems, err := util.CollectDfValues(dfColumnSpecs)
	if err != nil {
		return nil, err
	}

	ret := make(map[string]float64)
	for name, values := range filesystems {
		if matches := regexp.MustCompile(`^/dev/(.*)$`).FindStringSubmatch(name); matches != nil {
			device := regexp.MustCompile(`[^A-Za-z0-9_-]`).ReplaceAllString(matches[1], "_")
			for key, value := range values {
				intValue, valueTypeOk := value.(int64)
				if valueTypeOk {
					// kilo bytes -> bytes
					ret["filesystem."+device+"."+key] = float64(intValue) * 1024
				}
			}
		}
	}

	return metrics.Values(ret), nil
}
Пример #16
0
// Generate generate swap values
func (g *SwapGenerator) Generate() (metrics.Values, error) {
	outBytes, err := exec.Command("sysctl", "vm.swapusage").Output()
	if err != nil {
		swapLogger.Errorf("Failed (skip these metrics): %s", err)
		return nil, err
	}

	out := string(outBytes)
	matches := swapReg.FindStringSubmatch(out)
	if matches == nil || len(matches) != 4 {
		return nil, fmt.Errorf("faild to parse vm.swapusage result: [%q]", out)
	}
	t, _ := strconv.ParseFloat(matches[1], 64)
	// swap_used are calculated at server, so don't send it
	// u, _ := strconv.ParseFloat(matches[2], 64)
	f, _ := strconv.ParseFloat(matches[3], 64)

	const mb = 1024.0 * 1024.0
	return metrics.Values(map[string]float64{
		"memory.swap_total": t * mb,
		"memory.swap_free":  f * mb,
	}), nil
}
Пример #17
0
// Generate returns current CPU usage of the host.
// Keys below are expected:
// - cpu.user.percentage
// - cpu.system.percentage
// - cpu.idle.percentage
func (g *CPUUsageGenerator) Generate() (metrics.Values, error) {

	// $ iostat -n0 -c2
	//         cpu     load average
	//    us sy id   1m   5m   15m
	//    13  7 81  1.93 2.23 2.65
	//    13  7 81  1.93 2.23 2.65
	iostatBytes, err := exec.Command("iostat", "-n0", "-c2").Output()
	if err != nil {
		cpuUsageLogger.Errorf("Failed to invoke iostat: %s", err)
		return nil, err
	}

	iostat := string(iostatBytes)
	lines := strings.Split(iostat, "\n")
	if len(lines) != 5 {
		return nil, fmt.Errorf("iostat result malformed: [%q]", iostat)
	}

	fields := strings.Fields(lines[3])
	if len(fields) < len(iostatFieldToMetricName) {
		return nil, fmt.Errorf("iostat result malformed: [%q]", iostat)
	}

	cpuUsage := make(map[string]float64, len(iostatFieldToMetricName))

	for i, n := range iostatFieldToMetricName {
		value, err := strconv.ParseFloat(fields[i], 64)
		if err != nil {
			return nil, err
		}

		cpuUsage["cpu."+n+".percentage"] = value
	}

	return metrics.Values(cpuUsage), nil
}
Пример #18
0
// Generate generate metrics values
func (g *MemoryGenerator) Generate() (metrics.Values, error) {
	var errRet error
	outBytes, err := exec.Command("top", "-bn", "1").Output()
	if err != nil {
		logger.Warningf("'top -bn 1' command exited with a non-zero status: '%s'", err)
		errRet = err
	}
	ret := make(map[string]float64)

	out := string(outBytes)
	lines := strings.Split(out, "\n")

	for _, line := range lines {
		fields := strings.Fields(line)
		if len(fields) < 1 {
			continue
		}

		if fields[0] == "Memory:" {
			for i := 1; i < len(fields); i += 2 {
				v, err := getValue(fields[i])
				if err == nil {
					k := fields[i+1]
					if strings.HasSuffix(k, ",") {
						k = k[0 : len(k)-1]
					}
					switch k {
					case "Act":
						ret["memory.act"] = v
					case "Wired":
						ret["memory.wired"] = v
					case "Exec":
						ret["memory.exec"] = v
					case "File":
						ret["memory.file"] = v
					case "Free":
						ret["memory.free"] = v
					}
				} else {
					errRet = err
				}
			}
		}
		if fields[0] == "Swap:" {
			if v, err := getValue(fields[1]); err == nil {
				ret["memory.swap_total"] = v
			} else {
				errRet = err
			}
			swapFreeIndex := 5
			if len(fields) == 5 {
				swapFreeIndex = 3
			}
			if v, err := getValue(fields[swapFreeIndex]); err == nil {
				ret["memory.swap_free"] = v
			} else {
				errRet = err
			}
		}
	}

	v, err := getTotalMem()
	if err != nil {
		return nil, err
	}
	ret["memory.total"] = v

	if errRet == nil {
		return metrics.Values(ret), nil
	}
	return nil, errRet
}
Пример #19
0
func (g *InterfaceGenerator) collectIntarfacesValues() (metrics.Values, error) {
	file, err := os.Open("/proc/net/dev")
	if err != nil {
		interfaceLogger.Errorf("Failed (skip these metrics): %s", err)
		return nil, err
	}

	lineScanner := bufio.NewScanner(bufio.NewReader(file))
	results := make(map[string]float64)
	for lineScanner.Scan() {
		line := lineScanner.Text()
		if matches := regexp.MustCompile(`^\s*([^:]+):\s*(.*)$`).FindStringSubmatch(line); matches != nil {
			name := regexp.MustCompile(`[^A-Za-z0-9_-]`).ReplaceAllString(matches[1], "_")
			if name == "lo" {
				continue
			}

			cols := regexp.MustCompile(`\s+`).Split(matches[2], len(interfaceMetrics))
			if len(cols) < len(interfaceMetrics) {
				continue
			}

			interfaceResult := make(map[string]float64)
			hasNonZeroValue := false
			for i := range interfaceMetrics {
				key := fmt.Sprintf("interface.%s.%s", name, interfaceMetrics[i])
				value, err := strconv.ParseFloat(cols[i], 64)
				if err != nil {
					interfaceLogger.Warningf("Failed to parse host interfaces: %s", err)
					break
				}
				if value != 0 {
					hasNonZeroValue = true
				}
				interfaceResult[key] = value
			}
			if hasNonZeroValue {
				for k, v := range interfaceResult {
					results[k] = v
				}
			}
		}
	}

	// results (eth0) sample
	/** [%!s(*metrics.Value=&{interface.eth0.rxBytes 6.6074069281e+10})
	     %!s(*metrics.Value=&{interface.eth0.rxPackets 1.0483646e+08})
	     %!s(*metrics.Value=&{interface.eth0.rxErrors 0})
	     %!s(*metrics.Value=&{interface.eth0.rxDrops 1})
	     %!s(*metrics.Value=&{interface.eth0.rxFifo 0})
	     %!s(*metrics.Value=&{interface.eth0.rxFrame 0})
	     %!s(*metrics.Value=&{interface.eth0.rxCompressed 0})
	     %!s(*metrics.Value=&{interface.eth0.rxMulticast 0})
	     %!s(*metrics.Value=&{interface.eth0.txBytes 9.180531994e+09})
	     %!s(*metrics.Value=&{interface.eth0.txPackets 5.3107958e+07})
	     %!s(*metrics.Value=&{interface.eth0.txErrors 0})
	     %!s(*metrics.Value=&{interface.eth0.txDrops 0})
	     %!s(*metrics.Value=&{interface.eth0.txFifo 0})
	     %!s(*metrics.Value=&{interface.eth0.txColls 0})
	     %!s(*metrics.Value=&{interface.eth0.txCarrier 0})
	     %!s(*metrics.Value=&{interface.eth0.txCompressed 0})
	    ]
	**/

	return metrics.Values(results), nil
}