feat(inputs.system): collect unique user count logged in (#12147)
This commit is contained in:
parent
9155ae718d
commit
8221ece4ca
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue