diff --git a/libbeat/cmd/instance/metrics/metrics.go b/libbeat/cmd/instance/metrics/metrics.go index f47bf59a335..9960db99e9f 100644 --- a/libbeat/cmd/instance/metrics/metrics.go +++ b/libbeat/cmd/instance/metrics/metrics.go @@ -59,7 +59,7 @@ func SetupMetrics(name string) error { beatProcessStats = &process.Stats{ Procs: []string{name}, EnvWhitelist: nil, - CpuTicks: true, + CPUTicks: true, CacheCmdLine: true, IncludeTop: process.IncludeTopConfig{}, } diff --git a/metricbeat/module/system/process/cgroup.go b/libbeat/metric/system/process/cgroup.go similarity index 79% rename from metricbeat/module/system/process/cgroup.go rename to libbeat/metric/system/process/cgroup.go index c71dc7fe34d..db4f768f38b 100644 --- a/metricbeat/module/system/process/cgroup.go +++ b/libbeat/metric/system/process/cgroup.go @@ -26,31 +26,31 @@ import ( // cgroupStatsToMap returns a MapStr containing the data from the stats object. // If stats is nil then nil is returned. -func cgroupStatsToMap(stats *cgroup.Stats, perCPU bool) common.MapStr { - if stats == nil { +func cgroupStatsToMap(stats *Process) common.MapStr { + if stats == nil || stats.RawStats == nil { return nil } cgroup := common.MapStr{} // id and path are only available when all subsystems share a common path. - if stats.ID != "" { - cgroup["id"] = stats.ID + if stats.RawStats.ID != "" { + cgroup["id"] = stats.RawStats.ID } - if stats.Path != "" { - cgroup["path"] = stats.Path + if stats.RawStats.Path != "" { + cgroup["path"] = stats.RawStats.Path } - if cpu := cgroupCPUToMapStr(stats.CPU); cpu != nil { + if cpu := cgroupCPUToMapStr(stats.RawStats.CPU); cpu != nil { cgroup["cpu"] = cpu } - if cpuacct := cgroupCPUAccountingToMapStr(stats.CPUAccounting, perCPU); cpuacct != nil { + if cpuacct := cgroupCPUAccountingToMapStr(stats); cpuacct != nil { cgroup["cpuacct"] = cpuacct } - if memory := cgroupMemoryToMapStr(stats.Memory); memory != nil { + if memory := cgroupMemoryToMapStr(stats.RawStats.Memory); memory != nil { cgroup["memory"] = memory } - if blkio := cgroupBlockIOToMapStr(stats.BlockIO); blkio != nil { + if blkio := cgroupBlockIOToMapStr(stats.RawStats.BlockIO); blkio != nil { cgroup["blkio"] = blkio } @@ -97,7 +97,8 @@ func cgroupCPUToMapStr(cpu *cgroup.CPUSubsystem) common.MapStr { // cgroupCPUAccountingToMapStr returns a MapStr containing // CPUAccountingSubsystem data. If the cpuacct parameter is nil then nil is // returned. -func cgroupCPUAccountingToMapStr(cpuacct *cgroup.CPUAccountingSubsystem, perCPU bool) common.MapStr { +func cgroupCPUAccountingToMapStr(process *Process) common.MapStr { + cpuacct := process.RawStats.CPUAccounting if cpuacct == nil { return nil } @@ -106,25 +107,35 @@ func cgroupCPUAccountingToMapStr(cpuacct *cgroup.CPUAccountingSubsystem, perCPU "id": cpuacct.ID, "path": cpuacct.Path, "total": common.MapStr{ - "ns": cpuacct.TotalNanos, + "ns": cpuacct.TotalNanos, + "pct": process.PctStats.CPUTotalPct, + "norm": common.MapStr{ + "pct": process.PctStats.CPUTotalPctNorm, + }, }, "stats": common.MapStr{ "system": common.MapStr{ - "ns": cpuacct.Stats.SystemNanos, + "ns": cpuacct.Stats.SystemNanos, + "pct": process.PctStats.CPUSystemPct, + "norm": common.MapStr{ + "pct": process.PctStats.CPUSystemPctNorm, + }, }, "user": common.MapStr{ - "ns": cpuacct.Stats.UserNanos, + "ns": cpuacct.Stats.UserNanos, + "pct": process.PctStats.CPUUserPct, + "norm": common.MapStr{ + "pct": process.PctStats.CPUUserPctNorm, + }, }, }, } - if perCPU { - perCPUUsage := common.MapStr{} - for i, usage := range cpuacct.UsagePerCPU { - perCPUUsage[strconv.Itoa(i+1)] = usage - } - event["percpu"] = perCPUUsage + perCPUUsage := common.MapStr{} + for i, usage := range cpuacct.UsagePerCPU { + perCPUUsage[strconv.Itoa(i+1)] = usage } + event["percpu"] = perCPUUsage return event } diff --git a/libbeat/metric/system/process/process.go b/libbeat/metric/system/process/process.go index 76098a43f19..9e7eb5ac932 100644 --- a/libbeat/metric/system/process/process.go +++ b/libbeat/metric/system/process/process.go @@ -34,6 +34,7 @@ import ( "github.com/elastic/beats/v7/libbeat/logp" "github.com/elastic/beats/v7/libbeat/metric/system/memory" sigar "github.com/elastic/gosigar" + "github.com/elastic/gosigar/cgroup" ) // ProcsMap is a map where the keys are the names of processes and the value is the Process with that name @@ -42,39 +43,57 @@ type ProcsMap map[int]*Process // Process is the structure which holds the information of a process running on the host. // It includes pid, gid and it interacts with gosigar to fetch process data from the host. type Process struct { - Pid int `json:"pid"` - Ppid int `json:"ppid"` - Pgid int `json:"pgid"` - Name string `json:"name"` - Username string `json:"username"` - State string `json:"state"` - Args []string `json:"args"` - CmdLine string `json:"cmdline"` - Cwd string `json:"cwd"` - Executable string `json:"executable"` - Mem sigar.ProcMem - Cpu sigar.ProcTime - SampleTime time.Time - FD sigar.ProcFDUsage - Env common.MapStr + Pid int `json:"pid"` + Ppid int `json:"ppid"` + Pgid int `json:"pgid"` + Name string `json:"name"` + Username string `json:"username"` + State string `json:"state"` + Args []string `json:"args"` + CmdLine string `json:"cmdline"` + Cwd string `json:"cwd"` + Executable string `json:"executable"` + Mem sigar.ProcMem + CPU sigar.ProcTime + SampleTime time.Time + FD sigar.ProcFDUsage + Env common.MapStr + + //cpu stats cpuSinceStart float64 cpuTotalPct float64 cpuTotalPctNorm float64 + + // cgroup stats + RawStats *cgroup.Stats + PctStats CgroupPctStats +} + +// CgroupPctStats stores rendered percent values from cgroup CPU data +type CgroupPctStats struct { + CPUTotalPct float64 + CPUTotalPctNorm float64 + CPUUserPct float64 + CPUUserPctNorm float64 + CPUSystemPct float64 + CPUSystemPctNorm float64 } // Stats stores the stats of processes on the host. type Stats struct { - Procs []string - ProcsMap ProcsMap - CpuTicks bool - EnvWhitelist []string - CacheCmdLine bool - IncludeTop IncludeTopConfig + Procs []string + ProcsMap ProcsMap + CPUTicks bool + EnvWhitelist []string + CacheCmdLine bool + IncludeTop IncludeTopConfig + CgroupOpts cgroup.ReaderOptions + EnableCgroups bool procRegexps []match.Matcher // List of regular expressions used to whitelist processes. envRegexps []match.Matcher // List of regular expressions used to whitelist env vars. - - logger *logp.Logger + cgroups *cgroup.Reader + logger *logp.Logger } // Ticks of CPU for a process @@ -127,8 +146,8 @@ func (proc *Process) getDetails(envPredicate func(string) bool) error { return fmt.Errorf("error getting process mem for pid=%d: %v", proc.Pid, err) } - proc.Cpu = sigar.ProcTime{} - if err := proc.Cpu.Get(proc.Pid); err != nil { + proc.CPU = sigar.ProcTime{} + if err := proc.CPU.Get(proc.Pid); err != nil { return fmt.Errorf("error getting process cpu time for pid=%d: %v", proc.Pid, err) } @@ -322,13 +341,13 @@ func (procStats *Stats) getProcessEvent(process *Process) common.MapStr { "pct": process.cpuTotalPctNorm, }, }, - "start_time": unixTimeMsToTime(process.Cpu.StartTime), + "start_time": unixTimeMsToTime(process.CPU.StartTime), } - if procStats.CpuTicks { - proc.Put("cpu.user.ticks", process.Cpu.User) - proc.Put("cpu.system.ticks", process.Cpu.Sys) - proc.Put("cpu.total.ticks", process.Cpu.Total) + if procStats.CPUTicks { + proc.Put("cpu.user.ticks", process.CPU.User) + proc.Put("cpu.system.ticks", process.CPU.Sys) + proc.Put("cpu.total.ticks", process.CPU.Total) } if process.FD != (sigar.ProcFDUsage{}) { @@ -341,6 +360,12 @@ func (procStats *Stats) getProcessEvent(process *Process) common.MapStr { } } + if procStats.EnableCgroups { + if statsMap := cgroupStatsToMap(process); statsMap != nil { + proc["cgroup"] = statsMap + } + } + return proc } @@ -359,18 +384,63 @@ func GetProcCPUPercentage(s0, s1 *Process) (normalizedPct, pct, totalPct float64 if s0 != nil && s1 != nil { timeDelta := s1.SampleTime.Sub(s0.SampleTime) timeDeltaMillis := timeDelta / time.Millisecond - totalCPUDeltaMillis := int64(s1.Cpu.Total - s0.Cpu.Total) + totalCPUDeltaMillis := int64(s1.CPU.Total - s0.CPU.Total) pct := float64(totalCPUDeltaMillis) / float64(timeDeltaMillis) normalizedPct := pct / float64(runtime.NumCPU()) - return common.Round(normalizedPct, common.DefaultDecimalPlacesCount), common.Round(pct, common.DefaultDecimalPlacesCount), - common.Round(float64(s1.Cpu.Total), common.DefaultDecimalPlacesCount) + common.Round(float64(s1.CPU.Total), common.DefaultDecimalPlacesCount) } return 0, 0, 0 } +// GetCgroupPercentage returns CPU usage percentages for a given cgroup +// see GetProcCPUPercentage for implementation details, as the two are conceptually similar. +// Note that the cgroup controller reports system and user times in USER_HZ, while +// totals are reported in nanoseconds. Because of this, any math that mixes the two might be slightly off, +// as USER_HZ is less precise value that will get rounded up to nanseconds. +// Because of that, `user` and `system` metrics reflect a precentage of overall CPU time, but can't be compared to the total pct values. +func GetCgroupPercentage(s0, s1 *Process) CgroupPctStats { + if s0 == nil || s1 == nil || s0.RawStats == nil || s1.RawStats == nil || s0.RawStats.CPUAccounting == nil || s1.RawStats.CPUAccounting == nil { + return CgroupPctStats{} + } + timeDelta := s1.SampleTime.Sub(s0.SampleTime) + timeDeltaNanos := timeDelta / time.Nanosecond + totalCPUDeltaNanos := int64(s1.RawStats.CPUAccounting.TotalNanos - s0.RawStats.CPUAccounting.TotalNanos) + + pct := float64(totalCPUDeltaNanos) / float64(timeDeltaNanos) + // Avoid using NumCPU unless we need to; the values in UsagePerCPU are more likely to reflect the running conditions of the cgroup + // NumCPU can vary based on the conditions of the running metricbeat process, as it uses Affinity Masks, not hardware data. + var cpuCount int + if len(s1.RawStats.CPUAccounting.UsagePerCPU) > 0 { + cpuCount = len(s1.RawStats.CPUAccounting.UsagePerCPU) + } else { + cpuCount = runtime.NumCPU() + } + + // if you look at the raw cgroup stats, the following normalized value is literally an average of per-cpu numbers. + normalizedPct := pct / float64(cpuCount) + userCPUDeltaMillis := int64(s1.RawStats.CPUAccounting.Stats.UserNanos - s0.RawStats.CPUAccounting.Stats.UserNanos) + systemCPUDeltaMillis := int64(s1.RawStats.CPUAccounting.Stats.SystemNanos - s0.RawStats.CPUAccounting.Stats.SystemNanos) + + userPct := float64(userCPUDeltaMillis) / float64(timeDeltaNanos) + systemPct := float64(systemCPUDeltaMillis) / float64(timeDeltaNanos) + + normalizedUser := userPct / float64(cpuCount) + normalizedSystem := systemPct / float64(cpuCount) + + pctValues := CgroupPctStats{ + CPUTotalPct: common.Round(pct, common.DefaultDecimalPlacesCount), + CPUTotalPctNorm: common.Round(normalizedPct, common.DefaultDecimalPlacesCount), + CPUUserPct: common.Round(userPct, common.DefaultDecimalPlacesCount), + CPUUserPctNorm: common.Round(normalizedUser, common.DefaultDecimalPlacesCount), + CPUSystemPct: common.Round(systemPct, common.DefaultDecimalPlacesCount), + CPUSystemPctNorm: common.Round(normalizedSystem, common.DefaultDecimalPlacesCount), + } + return pctValues +} + // matchProcess checks if the provided process name matches any of the process regexes func (procStats *Stats) matchProcess(name string) bool { for _, reg := range procStats.procRegexps { @@ -409,6 +479,16 @@ func (procStats *Stats) Init() error { procStats.envRegexps = append(procStats.envRegexps, reg) } + if procStats.EnableCgroups { + cgReader, err := cgroup.NewReaderOptions(procStats.CgroupOpts) + if err == cgroup.ErrCgroupsMissing { + logp.Warn("cgroup data collection will be disabled: %v", err) + } else if err != nil { + return errors.Wrap(err, "error initializing cgroup reader") + } + procStats.cgroups = cgReader + } + return nil } @@ -492,6 +572,17 @@ func (procStats *Stats) getSingleProcess(pid int, newProcs ProcsMap) *Process { return nil } + if procStats.EnableCgroups { + cgStats, err := procStats.cgroups.GetStatsForProcess(pid) + if err != nil { + procStats.logger.Debug("Error fetching cgroup data for process %s with pid=%d: %v", process.Name, process.Pid, err) + return nil + } + process.RawStats = cgStats + last := procStats.ProcsMap[process.Pid] + process.PctStats = GetCgroupPercentage(last, process) + } + newProcs[process.Pid] = process last := procStats.ProcsMap[process.Pid] process.cpuTotalPctNorm, process.cpuTotalPct, process.cpuSinceStart = GetProcCPUPercentage(last, process) diff --git a/libbeat/metric/system/process/process_test.go b/libbeat/metric/system/process/process_test.go index 6bc6be447a5..712b7808547 100644 --- a/libbeat/metric/system/process/process_test.go +++ b/libbeat/metric/system/process/process_test.go @@ -68,10 +68,10 @@ func TestGetProcess(t *testing.T) { assert.True(t, (process.Mem.Share >= 0)) // CPU Checks - assert.True(t, (process.Cpu.StartTime > 0)) - assert.True(t, (process.Cpu.Total >= 0)) - assert.True(t, (process.Cpu.User >= 0)) - assert.True(t, (process.Cpu.Sys >= 0)) + assert.True(t, (process.CPU.StartTime > 0)) + assert.True(t, (process.CPU.Total >= 0)) + assert.True(t, (process.CPU.User >= 0)) + assert.True(t, (process.CPU.Sys >= 0)) assert.True(t, (process.SampleTime.Unix() <= time.Now().Unix())) @@ -143,7 +143,7 @@ func TestProcMemPercentage(t *testing.T) { func TestProcCpuPercentage(t *testing.T) { p1 := &Process{ - Cpu: gosigar.ProcTime{ + CPU: gosigar.ProcTime{ User: 11345, Sys: 37, Total: 11382, @@ -152,7 +152,7 @@ func TestProcCpuPercentage(t *testing.T) { } p2 := &Process{ - Cpu: gosigar.ProcTime{ + CPU: gosigar.ProcTime{ User: 14794, Sys: 47, Total: 14841, diff --git a/metricbeat/docs/fields.asciidoc b/metricbeat/docs/fields.asciidoc index a1a8913819b..4c2278437ab 100644 --- a/metricbeat/docs/fields.asciidoc +++ b/metricbeat/docs/fields.asciidoc @@ -44966,6 +44966,26 @@ type: long -- +*`system.process.cgroup.cpuacct.total.pct`*:: ++ +-- +CPU time of the cgroup as a percentage of overall CPU time. + + +type: scaled_float + +-- + +*`system.process.cgroup.cpuacct.total.norm.pct`*:: ++ +-- +CPU time of the cgroup as a percentage of overall CPU time, normalized by CPU count. This is functionally an average of time spent across individual CPUs. + + +type: scaled_float + +-- + *`system.process.cgroup.cpuacct.stats.user.ns`*:: + -- @@ -44975,6 +44995,24 @@ type: long -- +*`system.process.cgroup.cpuacct.stats.user.pct`*:: ++ +-- +time the cgroup spent in user space, as a percentage of total CPU time + +type: scaled_float + +-- + +*`system.process.cgroup.cpuacct.stats.user.norm.pct`*:: ++ +-- +time the cgroup spent in user space, as a percentage of total CPU time, normalized by CPU count. + +type: scaled_float + +-- + *`system.process.cgroup.cpuacct.stats.system.ns`*:: + -- @@ -44984,6 +45022,24 @@ type: long -- +*`system.process.cgroup.cpuacct.stats.system.pct`*:: ++ +-- +Time the cgroup spent in kernel space, as a percentage of total CPU time + +type: scaled_float + +-- + +*`system.process.cgroup.cpuacct.stats.system.norm.pct`*:: ++ +-- +Time the cgroup spent in kernel space, as a percentage of total CPU time, normalized by CPU count. + +type: scaled_float + +-- + *`system.process.cgroup.cpuacct.percpu`*:: + -- diff --git a/metricbeat/module/system/fields.go b/metricbeat/module/system/fields.go index 9c99bdfe5c8..d52d17d7276 100644 --- a/metricbeat/module/system/fields.go +++ b/metricbeat/module/system/fields.go @@ -32,5 +32,5 @@ func init() { // AssetSystem returns asset data. // This is the base64 encoded gzipped contents of module/system. func AssetSystem() string { - return "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" + return "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" } diff --git a/metricbeat/module/system/process/_meta/data.json b/metricbeat/module/system/process/_meta/data.json index 6577bb55b59..9d748e2f39c 100644 --- a/metricbeat/module/system/process/_meta/data.json +++ b/metricbeat/module/system/process/_meta/data.json @@ -11,16 +11,19 @@ }, "process": { "args": [ - "/sbin/init", - "splash" + "/usr/lib/systemd/systemd", + "--switched-root", + "--system", + "--deserialize", + "29" ], - "command_line": "/sbin/init splash", + "command_line": "/usr/lib/systemd/systemd --switched-root --system --deserialize 29", "cpu": { - "pct": 0, - "start_time": "2020-12-04T22:17:35.000Z" + "pct": 0.0029, + "start_time": "2021-03-29T04:24:52.000Z" }, "memory": { - "pct": 0.0004 + "pct": 0.0011 }, "name": "systemd", "pgid": 1, @@ -33,24 +36,191 @@ }, "system": { "process": { - "cmdline": "/sbin/init splash", + "cgroup": { + "blkio": { + "id": "init.scope", + "path": "/init.scope", + "total": { + "bytes": 3188736, + "ios": 238 + } + }, + "cpu": { + "cfs": { + "period": { + "us": 100000 + }, + "quota": { + "us": 0 + }, + "shares": 1024 + }, + "id": "init.scope", + "path": "/init.scope", + "rt": { + "period": { + "us": 0 + }, + "runtime": { + "us": 0 + } + }, + "stats": { + "periods": 0, + "throttled": { + "ns": 0, + "periods": 0 + } + } + }, + "cpuacct": { + "id": "init.scope", + "path": "/init.scope", + "percpu": { + "1": 7906237728724, + "2": 8055519955790, + "3": 7985757217648, + "4": 7270310725150 + }, + "stats": { + "system": { + "norm": { + "pct": 0.0015 + }, + "ns": 10276870000000, + "pct": 0.0058 + }, + "user": { + "norm": { + "pct": 0.0044 + }, + "ns": 20915760000000, + "pct": 0.0174 + } + }, + "total": { + "norm": { + "pct": 0.0047 + }, + "ns": 31217825627312, + "pct": 0.0188 + } + }, + "id": "init.scope", + "memory": { + "id": "init.scope", + "kmem": { + "failures": 0, + "limit": { + "bytes": 9223372036854771712 + }, + "usage": { + "bytes": 4755456, + "max": { + "bytes": 8380416 + } + } + }, + "kmem_tcp": { + "failures": 0, + "limit": { + "bytes": 9223372036854771712 + }, + "usage": { + "bytes": 0, + "max": { + "bytes": 0 + } + } + }, + "mem": { + "failures": 0, + "limit": { + "bytes": 9223372036854771712 + }, + "usage": { + "bytes": 31584256, + "max": { + "bytes": 53239808 + } + } + }, + "memsw": { + "failures": 0, + "limit": { + "bytes": 9223372036854771712 + }, + "usage": { + "bytes": 31821824, + "max": { + "bytes": 53239808 + } + } + }, + "path": "/init.scope", + "stats": { + "active_anon": { + "bytes": 0 + }, + "active_file": { + "bytes": 16642048 + }, + "cache": { + "bytes": 20140032 + }, + "hierarchical_memory_limit": { + "bytes": 9223372036854771712 + }, + "hierarchical_memsw_limit": { + "bytes": 9223372036854771712 + }, + "inactive_anon": { + "bytes": 7016448 + }, + "inactive_file": { + "bytes": 2977792 + }, + "major_page_faults": 165, + "mapped_file": { + "bytes": 15814656 + }, + "page_faults": 1288584, + "pages_in": 364353, + "pages_out": 357844, + "rss": { + "bytes": 6893568 + }, + "rss_huge": { + "bytes": 0 + }, + "swap": { + "bytes": 0 + }, + "unevictable": { + "bytes": 0 + } + } + }, + "path": "/init.scope" + }, + "cmdline": "/usr/lib/systemd/systemd --switched-root --system --deserialize 29", "cpu": { - "start_time": "2020-12-04T22:17:35.000Z", + "start_time": "2021-03-29T04:24:52.000Z", "total": { "norm": { - "pct": 0 + "pct": 0.0029 }, - "pct": 0, - "value": 1290 + "pct": 0.0116, + "value": 31214570 } }, "memory": { "rss": { - "bytes": 12173312, - "pct": 0.0004 + "bytes": 17108992, + "pct": 0.0011 }, - "share": 8679424, - "size": 172113920 + "share": 11341824, + "size": 178851840 }, "state": "sleeping" } diff --git a/metricbeat/module/system/process/_meta/fields.yml b/metricbeat/module/system/process/_meta/fields.yml index 51ab8b81e09..7c89b50f080 100644 --- a/metricbeat/module/system/process/_meta/fields.yml +++ b/metricbeat/module/system/process/_meta/fields.yml @@ -240,14 +240,40 @@ Total CPU time in nanoseconds consumed by all tasks in the cgroup. + - name: total.pct + type: scaled_float + description: > + CPU time of the cgroup as a percentage of overall CPU time. + + - name: total.norm.pct + type: scaled_float + description: > + CPU time of the cgroup as a percentage of overall CPU time, normalized by CPU count. This is functionally an average of time spent across individual CPUs. + - name: stats.user.ns type: long description: CPU time consumed by tasks in user mode. + - name: stats.user.pct + type: scaled_float + description: time the cgroup spent in user space, as a percentage of total CPU time + + - name: stats.user.norm.pct + type: scaled_float + description: time the cgroup spent in user space, as a percentage of total CPU time, normalized by CPU count. + - name: stats.system.ns type: long description: CPU time consumed by tasks in user (kernel) mode. + - name: stats.system.pct + type: scaled_float + description: Time the cgroup spent in kernel space, as a percentage of total CPU time + + - name: stats.system.norm.pct + type: scaled_float + description: Time the cgroup spent in kernel space, as a percentage of total CPU time, normalized by CPU count. + - name: percpu type: object object_type: long diff --git a/metricbeat/module/system/process/process.go b/metricbeat/module/system/process/process.go index 5b1bcee0b2e..1cb8723e919 100644 --- a/metricbeat/module/system/process/process.go +++ b/metricbeat/module/system/process/process.go @@ -65,14 +65,27 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) { return nil, fmt.Errorf("unexpected module type") } + enableCgroups := false + if runtime.GOOS == "linux" { + if config.Cgroups == nil || *config.Cgroups { + enableCgroups = true + debugf("process cgroup data collection is enabled, using hostfs='%v'", paths.Paths.Hostfs) + } + } + m := &MetricSet{ BaseMetricSet: base, stats: &process.Stats{ - Procs: config.Procs, - EnvWhitelist: config.EnvWhitelist, - CpuTicks: config.IncludeCPUTicks || (config.CPUTicks != nil && *config.CPUTicks), - CacheCmdLine: config.CacheCmdLine, - IncludeTop: config.IncludeTop, + Procs: config.Procs, + EnvWhitelist: config.EnvWhitelist, + CPUTicks: config.IncludeCPUTicks || (config.CPUTicks != nil && *config.CPUTicks), + CacheCmdLine: config.CacheCmdLine, + IncludeTop: config.IncludeTop, + EnableCgroups: enableCgroups, + CgroupOpts: cgroup.ReaderOptions{ + RootfsMountpoint: paths.Paths.Hostfs, + IgnoreRootCgroups: true, + }, }, perCPU: config.IncludePerCPU, IsAgent: systemModule.IsAgent, @@ -82,20 +95,6 @@ func New(base mb.BaseMetricSet) (mb.MetricSet, error) { return nil, err } - if runtime.GOOS == "linux" { - if config.Cgroups == nil || *config.Cgroups { - debugf("process cgroup data collection is enabled, using hostfs='%v'", paths.Paths.Hostfs) - m.cgroup, err = cgroup.NewReader(paths.Paths.Hostfs, true) - if err != nil { - if err == cgroup.ErrCgroupsMissing { - logp.Warn("cgroup data collection will be disabled: %v", err) - } else { - return nil, errors.Wrap(err, "error initializing cgroup reader") - } - } - } - } - return m, nil } @@ -107,25 +106,6 @@ func (m *MetricSet) Fetch(r mb.ReporterV2) error { return errors.Wrap(err, "process stats") } - if m.cgroup != nil { - for _, proc := range procs { - pid, ok := proc["pid"].(int) - if !ok { - debugf("error converting pid to int for proc %+v", proc) - continue - } - stats, err := m.cgroup.GetStatsForProcess(pid) - if err != nil { - debugf("error getting cgroups stats for pid=%d, %v", pid, err) - continue - } - - if statsMap := cgroupStatsToMap(stats, m.perCPU); statsMap != nil { - proc["cgroup"] = statsMap - } - } - } - for _, proc := range procs { rootFields := common.MapStr{ "process": common.MapStr{ @@ -139,6 +119,10 @@ func (m *MetricSet) Fetch(r mb.ReporterV2) error { }, } + if m.stats.EnableCgroups && !m.perCPU { + proc.Delete("cgroup.cpuacct.percpu") + } + // Duplicate system.process.cmdline with ECS name process.command_line rootFields = getAndCopy(proc, "cmdline", rootFields, "process.command_line")