metric/system/cgroup/cgcommon/metrics.go (45 lines of code) (raw):

// 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 cgcommon import ( "bufio" "fmt" "os" "github.com/elastic/elastic-agent-libs/opt" ) // CPUUsage wraps the CPU usage time values for the CPU controller metrics type CPUUsage struct { NS uint64 `json:"ns" struct:"ns"` Pct opt.Float `json:"pct,omitempty" struct:"pct,omitempty"` Norm opt.PctOpt `json:"norm,omitempty" struct:"norm,omitempty"` } // Pressure contains load metrics for a controller, // Broken apart into 10, 60, and 300 second samples, // as well as a total time in US type Pressure struct { Ten opt.Pct `json:"10,omitempty" struct:"10,omitempty"` Sixty opt.Pct `json:"60,omitempty" struct:"60,omitempty"` ThreeHundred opt.Pct `json:"300,omitempty" struct:"300,omitempty"` Total opt.Uint `json:"total,omitempty" struct:"total,omitempty"` } // IsZero implements the IsZero interface for Pressure // This is "all or nothing", as pressure stats don't exist on certain systems // If `total` doesn't exist, that means there's no pressure metrics. func (p Pressure) IsZero() bool { return p.Total.IsZero() } // GetPressure takes the path of a *.pressure file and returns a // map of the pressure (IO contention) stats for the cgroup // on CPU controllers, the only key will be "some" // on IO controllers, the keys will be "some" and "full" // See https://github.com/torvalds/linux/blob/master/Documentation/accounting/psi.rst func GetPressure(path string) (map[string]Pressure, error) { pressureData := make(map[string]Pressure) f, err := os.Open(path) // pass along any OS open errors directly if err != nil { return pressureData, err } defer f.Close() sc := bufio.NewScanner(f) for sc.Scan() { var stallTime string data := Pressure{} var total uint64 matched, err := fmt.Sscanf(sc.Text(), "%s avg10=%f avg60=%f avg300=%f total=%d", &stallTime, &data.Ten.Pct, &data.Sixty.Pct, &data.ThreeHundred.Pct, &total) if err != nil { return pressureData, fmt.Errorf("error scanning file: %s: %w", path, err) } // Assume that if we didn't match at least three numbers, something has gone wrong if matched < 3 { return pressureData, fmt.Errorf("only matched %d fields from file %s", matched, path) } data.Total = opt.UintWith(total) pressureData[stallTime] = data } return pressureData, nil }