adds file descriptors metrics, (#19)

* adds file descriptors metrics,
for linux based systems,
https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1037

* small fix
This commit is contained in:
Nikolay 2021-02-04 17:10:10 +03:00 committed by GitHub
parent be819551e3
commit 2a12f948a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 132 additions and 0 deletions

View File

@ -1,11 +1,16 @@
package metrics
import (
"bufio"
"bytes"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"regexp"
"strconv"
"strings"
"time"
)
@ -81,3 +86,75 @@ func writeProcessMetrics(w io.Writer) {
}
var startTimeSeconds = time.Now().Unix()
const fdReadChunkSize = 512
func WriteFDMetrics(w io.Writer){
totalOpenFDs, err := getOpenFDsCount("/proc/self/fd")
if err != nil {
log.Printf("ERROR: %v",err)
return
}
maxOpenFDs, err := getMaxFilesLimit("/proc/self/limits")
if err != nil {
log.Printf("ERROR: %v",err)
return
}
fmt.Fprintf(w,"process_max_fds %d\n",maxOpenFDs)
fmt.Fprintf(w,"process_open_fds %d\n",totalOpenFDs)
}
func getOpenFDsCount(path string)(uint64,error){
f, err := os.Open(path)
if err != nil {
return 0,fmt.Errorf("cannot open process fd path: %q, err: %v",path,err)
}
defer f.Close()
var totalOpenFDs uint64
for {
names, err := f.Readdirnames(fdReadChunkSize)
if err == io.EOF{
break
}
if err != nil {
return 0, fmt.Errorf("unexpected error at readdirnames: %v",err)
}
totalOpenFDs += uint64(len(names))
}
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){
f, err := os.Open(path)
if err != nil {
return 0,fmt.Errorf("cannot open path: %q for max files limit, err: %w",path,err)
}
defer f.Close()
scan := bufio.NewScanner(f)
// skip first line
scan.Scan()
for scan.Scan(){
text := scan.Text()
if !strings.HasPrefix(text,"Max open files"){
continue
}
items := limitsRe.FindStringSubmatch(text)
if len(items) != 4 {
return 0,fmt.Errorf("unxpected fields num for limits file, want: %d, got: %d, line: %q",4,len(items),text)
}
// use soft limit.
limit := items[2]
if limit == "unlimited"{
return 18446744073709551615,nil
}
limitUint, err := strconv.ParseUint(limit,10,64)
if err != nil {
return 0, fmt.Errorf("cannot parse limit: %q as uint64: %w",limit,err)
}
return limitUint,nil
}
return 0, fmt.Errorf("max open files limit wasn't found")
}

View File

@ -0,0 +1,37 @@
package metrics
import "testing"
func TestGetMaxFilesLimit(t *testing.T){
f := func(want uint64,path string, wantErr bool) {
t.Helper()
got, err := getMaxFilesLimit(path)
if err != nil && !wantErr {
t.Fatalf("unexpected error: %v",err)
}
if got != want{
t.Fatalf("unexpected result: %d, want: %d at getMaxFilesLimit",got,want)
}
}
f(1024,"testdata/limits",false)
f(0,"testdata/bad_path",true)
f(0,"testdata/limits_bad",true)
}
func TestGetOpenFDsCount(t *testing.T){
f := func(want uint64,path string, wantErr bool) {
t.Helper()
got, err := getOpenFDsCount(path)
if (err != nil && !wantErr)|| (err == nil && wantErr) {
t.Fatalf("unexpected error: %v",err)
}
if got != want{
t.Fatalf("unexpected result: %d, want: %d at getOpenFDsCount",got,want)
}
}
f(5,"testdata/fd/",false)
f(0,"testdata/fd/0",true)
f(0,"testdata/limits",true)
}

0
testdata/fd/0 vendored Normal file
View File

0
testdata/fd/10 vendored Normal file
View File

0
testdata/fd/2 vendored Normal file
View File

0
testdata/fd/3 vendored Normal file
View File

0
testdata/fd/5 vendored Normal file
View File

17
testdata/limits vendored Normal file
View File

@ -0,0 +1,17 @@
Limit Soft Limit Hard Limit Units
Max cpu time unlimited unlimited seconds
Max file size unlimited unlimited bytes
Max data size unlimited unlimited bytes
Max stack size 8388608 unlimited bytes
Max core file size 0 unlimited bytes
Max resident set unlimited unlimited bytes
Max processes 127458 127458 processes
Max open files 1024 1048576 files
Max locked memory 67108864 67108864 bytes
Max address space unlimited unlimited bytes
Max file locks unlimited unlimited locks
Max pending signals 127458 127458 signals
Max msgqueue size 819200 819200 bytes
Max nice priority 0 0
Max realtime priority 0 0
Max realtime timeout unlimited unlimited us

1
testdata/limits_bad vendored Normal file
View File

@ -0,0 +1 @@
Limit Soft Limit Hard Limit Units