youtubebeat/vendor/github.com/elastic/beats/metricbeat/module/docker/cpu/helper.go

145 lines
4.7 KiB
Go

// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package cpu
import (
"strconv"
"github.com/elastic/beats/libbeat/common"
"github.com/elastic/beats/libbeat/logp"
"github.com/elastic/beats/metricbeat/module/docker"
)
type CPUStats struct {
Time common.Time
Container *docker.Container
PerCpuUsage common.MapStr
TotalUsage float64
UsageInKernelmode uint64
UsageInKernelmodePercentage float64
UsageInUsermode uint64
UsageInUsermodePercentage float64
SystemUsage uint64
SystemUsagePercentage float64
}
type CPUService struct{}
func NewCpuService() *CPUService {
return &CPUService{}
}
func (c *CPUService) getCPUStatsList(rawStats []docker.Stat, dedot bool) []CPUStats {
formattedStats := []CPUStats{}
for _, stats := range rawStats {
formattedStats = append(formattedStats, c.getCPUStats(&stats, dedot))
}
return formattedStats
}
func (c *CPUService) getCPUStats(myRawStat *docker.Stat, dedot bool) CPUStats {
usage := cpuUsage{Stat: myRawStat}
return CPUStats{
Time: common.Time(myRawStat.Stats.Read),
Container: docker.NewContainer(myRawStat.Container, dedot),
PerCpuUsage: usage.PerCPU(),
TotalUsage: usage.Total(),
UsageInKernelmode: myRawStat.Stats.CPUStats.CPUUsage.UsageInKernelmode,
UsageInKernelmodePercentage: usage.InKernelMode(),
UsageInUsermode: myRawStat.Stats.CPUStats.CPUUsage.UsageInUsermode,
UsageInUsermodePercentage: usage.InUserMode(),
SystemUsage: myRawStat.Stats.CPUStats.SystemUsage,
SystemUsagePercentage: usage.System(),
}
}
// TODO: These helper should be merged with the cpu helper in system/cpu
type cpuUsage struct {
*docker.Stat
cpus int
systemDelta uint64
}
func (u *cpuUsage) CPUs() int {
if u.cpus == 0 {
u.cpus = len(u.Stats.CPUStats.CPUUsage.PercpuUsage)
}
return u.cpus
}
func (u *cpuUsage) SystemDelta() uint64 {
if u.systemDelta == 0 {
u.systemDelta = u.Stats.CPUStats.SystemUsage - u.Stats.PreCPUStats.SystemUsage
}
return u.systemDelta
}
func (u *cpuUsage) PerCPU() common.MapStr {
var output common.MapStr
if len(u.Stats.CPUStats.CPUUsage.PercpuUsage) == len(u.Stats.PreCPUStats.CPUUsage.PercpuUsage) {
output = common.MapStr{}
for index := range u.Stats.CPUStats.CPUUsage.PercpuUsage {
cpu := common.MapStr{}
cpu["pct"] = u.calculatePercentage(
u.Stats.CPUStats.CPUUsage.PercpuUsage[index],
u.Stats.PreCPUStats.CPUUsage.PercpuUsage[index])
cpu["ticks"] = u.Stats.CPUStats.CPUUsage.PercpuUsage[index]
output[strconv.Itoa(index)] = cpu
}
}
return output
}
func (u *cpuUsage) Total() float64 {
return u.calculatePercentage(u.Stats.CPUStats.CPUUsage.TotalUsage, u.Stats.PreCPUStats.CPUUsage.TotalUsage)
}
func (u *cpuUsage) InKernelMode() float64 {
return u.calculatePercentage(u.Stats.CPUStats.CPUUsage.UsageInKernelmode, u.Stats.PreCPUStats.CPUUsage.UsageInKernelmode)
}
func (u *cpuUsage) InUserMode() float64 {
return u.calculatePercentage(u.Stats.CPUStats.CPUUsage.UsageInUsermode, u.Stats.PreCPUStats.CPUUsage.UsageInUsermode)
}
func (u *cpuUsage) System() float64 {
return u.calculatePercentage(u.Stats.CPUStats.SystemUsage, u.Stats.PreCPUStats.SystemUsage)
}
// This function is meant to calculate the % CPU time change between two successive readings.
// The "oldValue" refers to the CPU statistics of the last read.
// Time here is expressed by second and not by nanoseconde.
// The main goal is to expose the %, in the same way, it's displayed by docker Client.
func (u *cpuUsage) calculatePercentage(newValue uint64, oldValue uint64) float64 {
if newValue < oldValue {
logp.Err("Error calculating CPU time change for docker module: new stats value (%v) is lower than the old one(%v)", newValue, oldValue)
return -1
}
value := newValue - oldValue
if value == 0 || u.SystemDelta() == 0 {
return 0
}
return float64(uint64(u.CPUs())*value) / float64(u.SystemDelta())
}