feat(inputs.system): collect unique user count logged in (#12147)

This commit is contained in:
Joshua Powers 2022-11-02 09:04:34 -06:00 committed by GitHub
parent 9155ae718d
commit 8221ece4ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 82 additions and 0 deletions

View File

@ -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
@ -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)

View File

@ -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) {
@ -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)

View File

@ -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)
})
}
}