145 lines
4.7 KiB
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())
|
|
}
|