in metric/system/process/process.go [241:329]
func (procStats *Stats) pidFill(pid int, filter bool) (ProcState, bool, error) {
// Fetch proc state so we can get the name for filtering based on user's filter.
var wrappedErr error
// OS-specific entrypoint, get basic info so we can at least run matchProcess
status, err := GetInfoForPid(procStats.Hostfs, pid)
if err != nil {
return status, true, fmt.Errorf("GetInfoForPid failed for pid %d: %w", pid, err)
}
if procStats.skipExtended {
return status, true, nil
}
// Some OSes use the cache to avoid expensive system calls,
// cacheCmdLine reads from the cache.
status = procStats.cacheCmdLine(status)
// Filter based on user-supplied func
if filter {
if !procStats.matchProcess(status.Name) {
return status, false, nil
}
}
// If we've passed the filter, continue to fill out the rest of the metrics
status, err = FillPidMetrics(procStats.Hostfs, pid, status, procStats.isWhitelistedEnvVar)
if err != nil {
if !errors.Is(err, NonFatalErr{}) {
return status, true, fmt.Errorf("FillPidMetrics failed for PID %d: %w", pid, err)
}
wrappedErr = errors.Join(wrappedErr, err)
procStats.logger.Debugf(wrappedErr.Error())
}
if status.CPU.Total.Ticks.Exists() {
status.CPU.Total.Value = opt.FloatWith(metric.Round(float64(status.CPU.Total.Ticks.ValueOr(0))))
}
// postprocess with cgroups and percentages
last, ok := procStats.ProcsMap.GetPid(status.Pid.ValueOr(0))
status.SampleTime = time.Now()
if ok {
status = GetProcCPUPercentage(last, status)
}
if procStats.EnableCgroups {
cgStats, err := procStats.cgroups.GetStatsForPid(status.Pid.ValueOr(0))
if err != nil {
procStats.logger.Debugf("Non-fatal error fetching cgroups metrics for pid %d, metrics are valid but partial: %s", pid, err)
} else {
status.Cgroup = cgStats
if ok {
status.Cgroup.FillPercentages(last.Cgroup, status.SampleTime, last.SampleTime)
}
}
} // end cgroups processor
if _, isExcluded := procStats.excludedPIDs[uint64(pid)]; !isExcluded {
status, err = FillMetricsRequiringMoreAccess(pid, status)
if err != nil {
procStats.logger.Debugf("error calling FillMetricsRequiringMoreAccess for pid %d: %w", pid, err)
}
// Generate `status.Cmdline` here for compatibility because on Windows
// `status.Args` is set by `FillMetricsRequiringMoreAccess`.
if len(status.Args) > 0 && status.Cmdline == "" {
status.Cmdline = strings.Join(status.Args, " ")
}
}
// network data
if procStats.EnableNetwork {
procHandle, err := sysinfo.Process(pid)
// treat this as a soft error
if err != nil {
procStats.logger.Debugf("error initializing process handler for pid %d while trying to fetch network data: %w", pid, err)
} else {
procNet, ok := procHandle.(sysinfotypes.NetworkCounters)
if ok {
status.Network, err = procNet.NetworkCounters()
if err != nil {
procStats.logger.Debugf("error fetching network counters for process %d: %w", pid, err)
}
}
}
}
return status, true, wrappedErr
}