follow-up for 2a12f948a9
This commit is contained in:
parent
2a12f948a9
commit
c070763356
@ -58,11 +58,17 @@ func WritePrometheus(w io.Writer, exposeProcessMetrics bool) {
|
|||||||
// metrics.WriteProcessMetrics(w)
|
// metrics.WriteProcessMetrics(w)
|
||||||
// })
|
// })
|
||||||
//
|
//
|
||||||
|
// See also WrteFDMetrics.
|
||||||
func WriteProcessMetrics(w io.Writer) {
|
func WriteProcessMetrics(w io.Writer) {
|
||||||
writeGoMetrics(w)
|
writeGoMetrics(w)
|
||||||
writeProcessMetrics(w)
|
writeProcessMetrics(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WriteFDMetrics writes `process_max_fds` and `process_open_fds` metrics to w.
|
||||||
|
func WriteFDMetrics(w io.Writer) {
|
||||||
|
writeFDMetrics(w)
|
||||||
|
}
|
||||||
|
|
||||||
// UnregisterMetric removes metric with the given name from default set.
|
// UnregisterMetric removes metric with the given name from default set.
|
||||||
func UnregisterMetric(name string) bool {
|
func UnregisterMetric(name string) bool {
|
||||||
return defaultSet.UnregisterMetric(name)
|
return defaultSet.UnregisterMetric(name)
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -87,74 +86,70 @@ func writeProcessMetrics(w io.Writer) {
|
|||||||
|
|
||||||
var startTimeSeconds = time.Now().Unix()
|
var startTimeSeconds = time.Now().Unix()
|
||||||
|
|
||||||
const fdReadChunkSize = 512
|
// WriteFDMetrics writes process_max_fds and process_open_fds metrics to w.
|
||||||
|
func writeFDMetrics(w io.Writer) {
|
||||||
func WriteFDMetrics(w io.Writer){
|
|
||||||
totalOpenFDs, err := getOpenFDsCount("/proc/self/fd")
|
totalOpenFDs, err := getOpenFDsCount("/proc/self/fd")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("ERROR: %v",err)
|
log.Printf("ERROR: cannot determine open file descriptors count: %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
maxOpenFDs, err := getMaxFilesLimit("/proc/self/limits")
|
maxOpenFDs, err := getMaxFilesLimit("/proc/self/limits")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("ERROR: %v",err)
|
log.Printf("ERROR: cannot determine the limit on open file descritors: %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.Fprintf(w,"process_max_fds %d\n",maxOpenFDs)
|
fmt.Fprintf(w, "process_max_fds %d\n", maxOpenFDs)
|
||||||
fmt.Fprintf(w,"process_open_fds %d\n",totalOpenFDs)
|
fmt.Fprintf(w, "process_open_fds %d\n", totalOpenFDs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getOpenFDsCount(path string) (uint64, error) {
|
||||||
func getOpenFDsCount(path string)(uint64,error){
|
|
||||||
f, err := os.Open(path)
|
f, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0,fmt.Errorf("cannot open process fd path: %q, err: %v",path,err)
|
return 0, err
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
var totalOpenFDs uint64
|
var totalOpenFDs uint64
|
||||||
for {
|
for {
|
||||||
names, err := f.Readdirnames(fdReadChunkSize)
|
names, err := f.Readdirnames(512)
|
||||||
if err == io.EOF{
|
if err == io.EOF {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("unexpected error at readdirnames: %v",err)
|
return 0, fmt.Errorf("unexpected error at Readdirnames: %s", err)
|
||||||
}
|
}
|
||||||
totalOpenFDs += uint64(len(names))
|
totalOpenFDs += uint64(len(names))
|
||||||
}
|
}
|
||||||
return totalOpenFDs, nil
|
return totalOpenFDs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var limitsRe = regexp.MustCompile(`(Max \w+\s{0,1}?\w*\s{0,1}\w*)\s{2,}(\w+)\s+(\w+)`)
|
func getMaxFilesLimit(path string) (uint64, error) {
|
||||||
|
|
||||||
func getMaxFilesLimit(path string)(uint64,error){
|
|
||||||
f, err := os.Open(path)
|
f, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0,fmt.Errorf("cannot open path: %q for max files limit, err: %w",path,err)
|
return 0, err
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
prefix := "Max open files"
|
||||||
scan := bufio.NewScanner(f)
|
scan := bufio.NewScanner(f)
|
||||||
// skip first line
|
for scan.Scan() {
|
||||||
scan.Scan()
|
s := scan.Text()
|
||||||
for scan.Scan(){
|
if !strings.HasPrefix(s, prefix) {
|
||||||
text := scan.Text()
|
|
||||||
if !strings.HasPrefix(text,"Max open files"){
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
items := limitsRe.FindStringSubmatch(text)
|
text := strings.TrimSpace(s[len(prefix):])
|
||||||
if len(items) != 4 {
|
// Extract soft limit.
|
||||||
return 0,fmt.Errorf("unxpected fields num for limits file, want: %d, got: %d, line: %q",4,len(items),text)
|
n := strings.IndexByte(text, ' ')
|
||||||
|
if n < 0 {
|
||||||
|
return 0, fmt.Errorf("cannot extract soft limit from %q", s)
|
||||||
}
|
}
|
||||||
// use soft limit.
|
text = text[:n]
|
||||||
limit := items[2]
|
if text == "unlimited" {
|
||||||
if limit == "unlimited"{
|
return 1<<64 - 1, nil
|
||||||
return 18446744073709551615,nil
|
|
||||||
}
|
}
|
||||||
limitUint, err := strconv.ParseUint(limit,10,64)
|
limit, err := strconv.ParseUint(text, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("cannot parse limit: %q as uint64: %w",limit,err)
|
return 0, fmt.Errorf("cannot parse soft limit from %q: %s", s, err)
|
||||||
}
|
}
|
||||||
return limitUint,nil
|
return limit, nil
|
||||||
}
|
}
|
||||||
return 0, fmt.Errorf("max open files limit wasn't found")
|
return 0, fmt.Errorf("cannot find max open files limit")
|
||||||
}
|
}
|
||||||
|
@ -2,36 +2,35 @@ package metrics
|
|||||||
|
|
||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
func TestGetMaxFilesLimit(t *testing.T){
|
func TestGetMaxFilesLimit(t *testing.T) {
|
||||||
f := func(want uint64,path string, wantErr bool) {
|
f := func(want uint64, path string, wantErr bool) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
got, err := getMaxFilesLimit(path)
|
got, err := getMaxFilesLimit(path)
|
||||||
if err != nil && !wantErr {
|
if err != nil && !wantErr {
|
||||||
t.Fatalf("unexpected error: %v",err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if got != want{
|
if got != want {
|
||||||
t.Fatalf("unexpected result: %d, want: %d at getMaxFilesLimit",got,want)
|
t.Fatalf("unexpected result: %d, want: %d at getMaxFilesLimit", got, want)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
f(1024,"testdata/limits",false)
|
f(1024, "testdata/limits", false)
|
||||||
f(0,"testdata/bad_path",true)
|
f(0, "testdata/bad_path", true)
|
||||||
f(0,"testdata/limits_bad",true)
|
f(0, "testdata/limits_bad", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetOpenFDsCount(t *testing.T) {
|
||||||
func TestGetOpenFDsCount(t *testing.T){
|
f := func(want uint64, path string, wantErr bool) {
|
||||||
f := func(want uint64,path string, wantErr bool) {
|
|
||||||
t.Helper()
|
t.Helper()
|
||||||
got, err := getOpenFDsCount(path)
|
got, err := getOpenFDsCount(path)
|
||||||
if (err != nil && !wantErr)|| (err == nil && wantErr) {
|
if (err != nil && !wantErr) || (err == nil && wantErr) {
|
||||||
t.Fatalf("unexpected error: %v",err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if got != want{
|
if got != want {
|
||||||
t.Fatalf("unexpected result: %d, want: %d at getOpenFDsCount",got,want)
|
t.Fatalf("unexpected result: %d, want: %d at getOpenFDsCount", got, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f(5,"testdata/fd/",false)
|
f(5, "testdata/fd/", false)
|
||||||
f(0,"testdata/fd/0",true)
|
f(0, "testdata/fd/0", true)
|
||||||
f(0,"testdata/limits",true)
|
f(0, "testdata/limits", true)
|
||||||
}
|
}
|
||||||
|
@ -9,3 +9,7 @@ import (
|
|||||||
func writeProcessMetrics(w io.Writer) {
|
func writeProcessMetrics(w io.Writer) {
|
||||||
// TODO: implement it
|
// TODO: implement it
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func writeFDMetrics(w io.Writer) {
|
||||||
|
// TODO: implement it.
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user