Skip to content

Commit 0a2f43b

Browse files
authored
Merge pull request #3 from groove-x/feature/fd-count
support file descriptor count
2 parents e63de4f + 56b03d6 commit 0a2f43b

File tree

4 files changed

+116
-9
lines changed

4 files changed

+116
-9
lines changed

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,24 @@ container_memory_rss{id="/system.slice/docker.service"} 24072192
3939
container_memory_rss{id="/system.slice/NetworkManager.service"} 5066752
4040
container_memory_rss{id="/docker/grafana"} 16224256
4141
:
42+
43+
# HELP container_open_fds Number of open file descriptors
44+
# TYPE container_open_fds gauge
45+
container_open_fds{id="/system.slice/wpa_supplicant.service"} 19
46+
container_open_fds{id="/system.slice/ssh.service"} 5
47+
container_open_fds{id="/system.slice/docker.service"} 29
48+
container_open_fds{id="/system.slice/NetworkManager.service"} 21
49+
container_open_fds{id="/docker/grafana"} 11
50+
:
51+
52+
# HELP container_open_sockets Number of open sockets
53+
# TYPE container_open_sockets gauge
54+
container_open_sockets{id="/system.slice/wpa_supplicant.service"} 16
55+
container_open_sockets{id="/system.slice/ssh.service"} 4
56+
container_open_sockets{id="/system.slice/docker.service"} 19
57+
container_open_sockets{id="/system.slice/NetworkManager.service"} 13
58+
container_open_sockets{id="/docker/grafana"} 3
59+
:
4260
```
4361

4462
## options

deb.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "prometheus-cgroup-exporter",
3-
"version": "0.1.3",
3+
"version": "0.1.4",
44
"maintainer": "GROOVE X Development Team <dev@groove-x.com>",
55
"description": "prometheus cgroup exporter",
66
"changelog-cmd": "git log --pretty='format:%cd %h %s %d [%an]' --date=iso --merges",

main.go

Lines changed: 95 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ import (
55
"encoding/json"
66
"flag"
77
"fmt"
8+
"io/ioutil"
89
"log"
910
"net/http"
1011
"os"
1112
"os/signal"
13+
"path"
1214
"strconv"
1315
"strings"
1416
"syscall"
@@ -72,6 +74,34 @@ func main() {
7274
}
7375
}
7476

77+
type ProcessStats struct {
78+
FdCount int `json:"fd_count"`
79+
SocketCount int `json:"socket_count"`
80+
}
81+
82+
func processStats(pid int) *ProcessStats {
83+
dir := fmt.Sprintf("/proc/%d/fd", pid)
84+
fds, err := ioutil.ReadDir(dir)
85+
if err != nil {
86+
return nil
87+
}
88+
var socketCount int
89+
for _, fd := range fds {
90+
fdPath := path.Join(dir, fd.Name())
91+
linkName, err := os.Readlink(fdPath)
92+
if err != nil {
93+
continue
94+
}
95+
if strings.HasPrefix(linkName, "socket") {
96+
socketCount++
97+
}
98+
}
99+
return &ProcessStats{
100+
FdCount: len(fds),
101+
SocketCount: socketCount,
102+
}
103+
}
104+
75105
func subsystem() ([]cgroups.Subsystem, error) {
76106
root := "/sys/fs/cgroup"
77107
s := []cgroups.Subsystem{
@@ -82,13 +112,18 @@ func subsystem() ([]cgroups.Subsystem, error) {
82112
return s, nil
83113
}
84114

85-
func statsCgroups(ctx context.Context, system cgroups.Cgroup) (map[string]*cgroups.Metrics, error) {
115+
type cgroupMetrics struct {
116+
*cgroups.Metrics
117+
Process *ProcessStats `json:"process_stats"`
118+
}
119+
120+
func statsCgroups(ctx context.Context, system cgroups.Cgroup) (map[string]*cgroupMetrics, error) {
86121
processes, err := system.Processes(cgroups.Devices, true)
87122
if err != nil {
88123
return nil, fmt.Errorf("cgroups load: %s", err)
89124
}
90125

91-
groups := make(map[string]*cgroups.Metrics, len(processes))
126+
groups := make(map[string]*cgroupMetrics, len(processes))
92127
for _, p := range processes {
93128
name := strings.TrimPrefix(p.Path, "/sys/fs/cgroup/devices")
94129
name = strings.TrimSuffix(name, "/")
@@ -108,15 +143,20 @@ func statsCgroups(ctx context.Context, system cgroups.Cgroup) (map[string]*cgrou
108143
log.Printf("control stat: %s", err)
109144
continue
110145
}
111-
groups[name] = stats
146+
ps := processStats(p.Pid)
147+
groups[name] = &cgroupMetrics{
148+
Metrics: stats,
149+
Process: ps,
150+
}
112151
}
113152
return groups, nil
114153
}
115154

116155
type dockerStats struct {
117-
CPU types.CPUStats `json:"cpu_stats,omitempty"`
118-
PreCPU types.CPUStats `json:"precpu_stats,omitempty"` // "Pre"="Previous"
119-
Memory types.MemoryStats `json:"memory_stats,omitempty"`
156+
CPU types.CPUStats `json:"cpu_stats,omitempty"`
157+
PreCPU types.CPUStats `json:"precpu_stats,omitempty"` // "Pre"="Previous"
158+
Memory types.MemoryStats `json:"memory_stats,omitempty"`
159+
Process *ProcessStats `json:"process_stats"`
120160
}
121161

122162
func statsDockerContainers(ctx context.Context, dockerClient *client.Client) (map[string]dockerStats, error) {
@@ -145,6 +185,12 @@ func statsDockerContainers(ctx context.Context, dockerClient *client.Client) (ma
145185
}
146186
res.Body.Close()
147187
name := fmt.Sprintf("/docker%s", strings.Join(container.Names, "/"))
188+
inspect, err := dockerClient.ContainerInspect(ctx, container.ID)
189+
if err == nil {
190+
if inspect.State != nil {
191+
stats.Process = processStats(inspect.State.Pid)
192+
}
193+
}
148194
dockerContainers[name] = stats
149195
}
150196

@@ -200,6 +246,49 @@ func exportMetrics(system cgroups.Cgroup, dockerClient *client.Client) func(w ht
200246
fmt.Fprintln(w)
201247
}
202248

249+
fmt.Fprintln(w, `# HELP container_open_fds Number of open file descriptors
250+
# TYPE container_open_fds gauge`)
251+
for name, stats := range groups {
252+
if stats.Process == nil {
253+
continue
254+
}
255+
fmt.Fprintf(w, `container_open_fds{id=%s} %d`, strconv.Quote(name), stats.Process.FdCount)
256+
fmt.Fprintln(w)
257+
}
258+
for name, stats := range dockerContainers {
259+
if stats.Process == nil {
260+
continue
261+
}
262+
fmt.Fprintf(w, `container_open_fds{id=%s} %d`, strconv.Quote(name), stats.Process.FdCount)
263+
fmt.Fprintln(w)
264+
}
265+
266+
fmt.Fprintln(w, `# HELP container_open_sockets Number of open sockets
267+
# TYPE container_open_sockets gauge`)
268+
for name, stats := range groups {
269+
if stats.Process == nil {
270+
continue
271+
}
272+
fmt.Fprintf(w, `container_open_sockets{id=%s} %d`, strconv.Quote(name), stats.Process.SocketCount)
273+
fmt.Fprintln(w)
274+
}
275+
for name, stats := range dockerContainers {
276+
if stats.Process == nil {
277+
continue
278+
}
279+
fmt.Fprintf(w, `container_open_sockets{id=%s} %d`, strconv.Quote(name), stats.Process.SocketCount)
280+
fmt.Fprintln(w)
281+
}
282+
283+
processStats := processStats(os.Getpid())
284+
if processStats != nil {
285+
fmt.Fprintln(w, `# HELP process_open_fds Number of open file descriptors
286+
# TYPE process_open_fds gauge`)
287+
fmt.Fprintf(w, `process_open_fds %d`, processStats.FdCount)
288+
fmt.Fprintln(w)
289+
}
290+
203291
return
204292
}
293+
205294
}

wercker.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ deploy:
4545

4646
- github-create-release:
4747
token: $GITHUB_TOKEN
48-
tag: $GITHUB_RELEASE_VERSION
49-
title: $GITHUB_RELEASE_VERSION
48+
tag: v$GITHUB_RELEASE_VERSION
49+
title: v$GITHUB_RELEASE_VERSION
5050
draft: true
5151

5252
- github-upload-asset:

0 commit comments

Comments
 (0)