Skip to content

Commit

Permalink
feat(inputs.system): collect unique user count logged in (#12147)
Browse files Browse the repository at this point in the history
  • Loading branch information
powersj authored Nov 2, 2022
1 parent 9155ae7 commit 8221ece
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 0 deletions.
5 changes: 5 additions & 0 deletions plugins/inputs/system/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ The `n_users` field requires read access to `/var/run/utmp`, and may require the
`telegraf` user to be added to the `utmp` group on some systems. If this file
does not exist `n_users` will be skipped.

The `n_unique_users` shows the count of unique usernames logged in. This way if
a user has multiple sessions open/started they would only get counted once. The
same requirements for `n_users` apply.

## Metrics

- system
Expand All @@ -36,6 +40,7 @@ does not exist `n_users` will be skipped.
- load15 (float)
- load5 (float)
- n_users (integer)
- n_unique_users (integer)
- n_cpus (integer)
- uptime (integer, seconds)
- uptime_format (string, deprecated in 1.10, use `uptime` field)
Expand Down
12 changes: 12 additions & 0 deletions plugins/inputs/system/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ func (s *SystemStats) Gather(acc telegraf.Accumulator) error {
users, err := host.Users()
if err == nil {
fields["n_users"] = len(users)
fields["n_unique_users"] = findUniqueUsers(users)
} else if os.IsNotExist(err) {
s.Log.Debugf("Reading users: %s", err.Error())
} else if os.IsPermission(err) {
Expand All @@ -74,6 +75,17 @@ func (s *SystemStats) Gather(acc telegraf.Accumulator) error {
return nil
}

func findUniqueUsers(userStats []host.UserStat) int {
uniqueUsers := make(map[string]bool)
for _, userstat := range userStats {
if _, ok := uniqueUsers[userstat.User]; !ok {
uniqueUsers[userstat.User] = true
}
}

return len(uniqueUsers)
}

func formatUptime(uptime uint64) string {
buf := new(bytes.Buffer)
w := bufio.NewWriter(buf)
Expand Down
65 changes: 65 additions & 0 deletions plugins/inputs/system/system_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package system

import (
"testing"

"github.com/shirou/gopsutil/v3/host"
"github.com/stretchr/testify/require"
)

func TestUniqueUsers(t *testing.T) {
tests := []struct {
name string
expected int
data []host.UserStat
}{
{
name: "single entry",
expected: 1,
data: []host.UserStat{
{User: "root"},
},
},
{
name: "emptry entry",
expected: 0,
data: []host.UserStat{},
},
{
name: "all duplicates",
expected: 1,
data: []host.UserStat{
{User: "root"},
{User: "root"},
{User: "root"},
},
},
{
name: "all unique",
expected: 3,
data: []host.UserStat{
{User: "root"},
{User: "ubuntu"},
{User: "ec2-user"},
},
},
{
name: "mix of dups",
expected: 3,
data: []host.UserStat{
{User: "root"},
{User: "ubuntu"},
{User: "ubuntu"},
{User: "ubuntu"},
{User: "ec2-user"},
{User: "ec2-user"},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
actual := findUniqueUsers(tt.data)
require.Equal(t, tt.expected, actual, tt.name)
})
}
}

0 comments on commit 8221ece

Please sign in to comment.