diff options
Diffstat (limited to '')
12 files changed, 1021 insertions, 0 deletions
diff --git a/src/go/collectors/go.d.plugin/modules/logind/README.md b/src/go/collectors/go.d.plugin/modules/logind/README.md new file mode 120000 index 000000000..22c20d705 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/logind/README.md @@ -0,0 +1 @@ +integrations/systemd-logind_users.md
\ No newline at end of file diff --git a/src/go/collectors/go.d.plugin/modules/logind/charts.go b/src/go/collectors/go.d.plugin/modules/logind/charts.go new file mode 100644 index 000000000..91bc0f202 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/logind/charts.go @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +//go:build linux +// +build linux + +package logind + +import "github.com/netdata/netdata/go/go.d.plugin/agent/module" + +const ( + prioSessions = module.Priority + iota + prioSessionsType + prioSessionsState + prioUsersState +) + +var charts = module.Charts{ + sessionsChart.Copy(), + sessionsTypeChart.Copy(), + sessionsStateChart.Copy(), + usersStateChart.Copy(), +} + +var sessionsChart = module.Chart{ + ID: "sessions", + Title: "Logind Sessions", + Units: "sessions", + Fam: "sessions", + Ctx: "logind.sessions", + Priority: prioSessions, + Type: module.Stacked, + Dims: module.Dims{ + {ID: "sessions_remote", Name: "remote"}, + {ID: "sessions_local", Name: "local"}, + }, +} + +var sessionsTypeChart = module.Chart{ + ID: "sessions_type", + Title: "Logind Sessions By Type", + Units: "sessions", + Fam: "sessions", + Ctx: "logind.sessions_type", + Priority: prioSessionsType, + Type: module.Stacked, + Dims: module.Dims{ + {ID: "sessions_type_console", Name: "console"}, + {ID: "sessions_type_graphical", Name: "graphical"}, + {ID: "sessions_type_other", Name: "other"}, + }, +} + +var sessionsStateChart = module.Chart{ + ID: "sessions_state", + Title: "Logind Sessions By State", + Units: "sessions", + Fam: "sessions", + Ctx: "logind.sessions_state", + Priority: prioSessionsState, + Type: module.Stacked, + Dims: module.Dims{ + {ID: "sessions_state_online", Name: "online"}, + {ID: "sessions_state_closing", Name: "closing"}, + {ID: "sessions_state_active", Name: "active"}, + }, +} + +var usersStateChart = module.Chart{ + ID: "users_state", + Title: "Logind Users By State", + Units: "users", + Fam: "users", + Ctx: "logind.users_state", + Priority: prioUsersState, + Type: module.Stacked, + Dims: module.Dims{ + {ID: "users_state_offline", Name: "offline"}, + {ID: "users_state_closing", Name: "closing"}, + {ID: "users_state_online", Name: "online"}, + {ID: "users_state_lingering", Name: "lingering"}, + {ID: "users_state_active", Name: "active"}, + }, +} diff --git a/src/go/collectors/go.d.plugin/modules/logind/collect.go b/src/go/collectors/go.d.plugin/modules/logind/collect.go new file mode 100644 index 000000000..1f22478b1 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/logind/collect.go @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +//go:build linux +// +build linux + +package logind + +import ( + "strings" +) + +func (l *Logind) collect() (map[string]int64, error) { + if l.conn == nil { + conn, err := l.newLogindConn(l.Config) + if err != nil { + return nil, err + } + l.conn = conn + } + + mx := make(map[string]int64) + + // https://www.freedesktop.org/wiki/Software/systemd/logind/ (Session Objects) + if err := l.collectSessions(mx); err != nil { + return nil, err + } + // https://www.freedesktop.org/wiki/Software/systemd/logind/ (User Objects) + if err := l.collectUsers(mx); err != nil { + return nil, err + } + + return mx, nil +} + +func (l *Logind) collectSessions(mx map[string]int64) error { + sessions, err := l.conn.ListSessions() + if err != nil { + return err + } + + mx["sessions_remote"] = 0 + mx["sessions_local"] = 0 + mx["sessions_type_graphical"] = 0 + mx["sessions_type_console"] = 0 + mx["sessions_type_other"] = 0 + mx["sessions_state_online"] = 0 + mx["sessions_state_active"] = 0 + mx["sessions_state_closing"] = 0 + + for _, session := range sessions { + props, err := l.conn.GetSessionProperties(session.Path) + if err != nil { + return err + } + + if v, ok := props["Remote"]; ok && v.String() == "true" { + mx["sessions_remote"]++ + } else { + mx["sessions_local"]++ + } + + if v, ok := props["Type"]; ok { + typ := strings.Trim(v.String(), "\"") + switch typ { + case "x11", "mir", "wayland": + mx["sessions_type_graphical"]++ + case "tty": + mx["sessions_type_console"]++ + case "unspecified": + mx["sessions_type_other"]++ + default: + l.Debugf("unknown session type '%s' for session '%s/%s'", typ, session.User, session.ID) + mx["sessions_type_other"]++ + } + } + + if v, ok := props["State"]; ok { + state := strings.Trim(v.String(), "\"") + switch state { + case "online": + mx["sessions_state_online"]++ + case "active": + mx["sessions_state_active"]++ + case "closing": + mx["sessions_state_closing"]++ + default: + l.Debugf("unknown session state '%s' for session '%s/%s'", state, session.User, session.ID) + } + } + } + return nil +} + +func (l *Logind) collectUsers(mx map[string]int64) error { + users, err := l.conn.ListUsers() + if err != nil { + return err + } + + // https://www.freedesktop.org/software/systemd/man/sd_uid_get_state.html + mx["users_state_offline"] = 0 + mx["users_state_lingering"] = 0 + mx["users_state_online"] = 0 + mx["users_state_active"] = 0 + mx["users_state_closing"] = 0 + + for _, user := range users { + v, err := l.conn.GetUserProperty(user.Path, "State") + if err != nil { + return err + } + + state := strings.Trim(v.String(), "\"") + switch state { + case "offline": + mx["users_state_offline"]++ + case "lingering": + mx["users_state_lingering"]++ + case "online": + mx["users_state_online"]++ + case "active": + mx["users_state_active"]++ + case "closing": + mx["users_state_closing"]++ + default: + l.Debugf("unknown user state '%s' for user '%s/%d'", state, user.Name, user.UID) + } + } + return nil +} diff --git a/src/go/collectors/go.d.plugin/modules/logind/config_schema.json b/src/go/collectors/go.d.plugin/modules/logind/config_schema.json new file mode 100644 index 000000000..0a8618538 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/logind/config_schema.json @@ -0,0 +1,35 @@ +{ + "jsonSchema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Logind collector configuration.", + "type": "object", + "properties": { + "update_every": { + "title": "Update every", + "description": "Data collection interval, measured in seconds.", + "type": "integer", + "minimum": 1, + "default": 1 + }, + "timeout": { + "title": "Timeout", + "description": "The timeout in seconds for a connection to systemds dbus endpoint.", + "type": "number", + "minimum": 0.5, + "default": 1 + } + }, + "additionalProperties": false, + "patternProperties": { + "^name$": {} + } + }, + "uiSchema": { + "uiOptions": { + "fullPage": true + }, + "timeout": { + "ui:help": "Accepts decimals for precise control (e.g., type 1.5 for 1.5 seconds)." + } + } +} diff --git a/src/go/collectors/go.d.plugin/modules/logind/connection.go b/src/go/collectors/go.d.plugin/modules/logind/connection.go new file mode 100644 index 000000000..b97387acf --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/logind/connection.go @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +//go:build linux +// +build linux + +package logind + +import ( + "context" + "time" + + "github.com/coreos/go-systemd/v22/login1" + "github.com/godbus/dbus/v5" +) + +type logindConnection interface { + Close() + + ListSessions() ([]login1.Session, error) + GetSessionProperties(dbus.ObjectPath) (map[string]dbus.Variant, error) + + ListUsers() ([]login1.User, error) + GetUserProperty(dbus.ObjectPath, string) (*dbus.Variant, error) +} + +func newLogindConnection(timeout time.Duration) (logindConnection, error) { + conn, err := login1.New() + if err != nil { + return nil, err + } + return &logindDBusConnection{ + conn: conn, + timeout: timeout, + }, nil +} + +type logindDBusConnection struct { + conn *login1.Conn + timeout time.Duration +} + +func (c *logindDBusConnection) Close() { + if c.conn != nil { + c.conn.Close() + c.conn = nil + } +} + +func (c *logindDBusConnection) ListSessions() ([]login1.Session, error) { + ctx, cancel := context.WithTimeout(context.Background(), c.timeout) + defer cancel() + + return c.conn.ListSessionsContext(ctx) +} + +func (c *logindDBusConnection) ListUsers() ([]login1.User, error) { + ctx, cancel := context.WithTimeout(context.Background(), c.timeout) + defer cancel() + + return c.conn.ListUsersContext(ctx) +} + +func (c *logindDBusConnection) GetSessionProperties(path dbus.ObjectPath) (map[string]dbus.Variant, error) { + ctx, cancel := context.WithTimeout(context.Background(), c.timeout) + defer cancel() + + return c.conn.GetSessionPropertiesContext(ctx, path) +} + +func (c *logindDBusConnection) GetUserProperty(path dbus.ObjectPath, property string) (*dbus.Variant, error) { + ctx, cancel := context.WithTimeout(context.Background(), c.timeout) + defer cancel() + + return c.conn.GetUserPropertyContext(ctx, path, property) +} diff --git a/src/go/collectors/go.d.plugin/modules/logind/doc.go b/src/go/collectors/go.d.plugin/modules/logind/doc.go new file mode 100644 index 000000000..90aa8b4ef --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/logind/doc.go @@ -0,0 +1,3 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package logind diff --git a/src/go/collectors/go.d.plugin/modules/logind/integrations/systemd-logind_users.md b/src/go/collectors/go.d.plugin/modules/logind/integrations/systemd-logind_users.md new file mode 100644 index 000000000..9f80e924c --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/logind/integrations/systemd-logind_users.md @@ -0,0 +1,135 @@ +<!--startmeta +custom_edit_url: "https://github.com/netdata/netdata/edit/master/src/go/collectors/go.d.plugin/modules/logind/README.md" +meta_yaml: "https://github.com/netdata/netdata/edit/master/src/go/collectors/go.d.plugin/modules/logind/metadata.yaml" +sidebar_label: "systemd-logind users" +learn_status: "Published" +learn_rel_path: "Collecting Metrics/Systemd" +most_popular: False +message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE COLLECTOR'S metadata.yaml FILE" +endmeta--> + +# systemd-logind users + + +<img src="https://netdata.cloud/img/users.svg" width="150"/> + + +Plugin: go.d.plugin +Module: logind + +<img src="https://img.shields.io/badge/maintained%20by-Netdata-%2300ab44" /> + +## Overview + +This collector monitors number of sessions and users as reported by the `org.freedesktop.login1` DBus API. + + + + +This collector is supported on all platforms. + +This collector supports collecting metrics from multiple instances of this integration, including remote instances. + + +### Default Behavior + +#### Auto-Detection + +This integration doesn't support auto-detection. + +#### Limits + +The default configuration for this integration does not impose any limits on data collection. + +#### Performance Impact + +The default configuration for this integration is not expected to impose a significant performance impact on the system. + + +## Metrics + +Metrics grouped by *scope*. + +The scope defines the instance that the metric belongs to. An instance is uniquely identified by a set of labels. + + + +### Per systemd-logind users instance + +These metrics refer to the entire monitored application. + +This scope has no labels. + +Metrics: + +| Metric | Dimensions | Unit | +|:------|:----------|:----| +| logind.sessions | remote, local | sessions | +| logind.sessions_type | console, graphical, other | sessions | +| logind.sessions_state | online, closing, active | sessions | +| logind.users_state | offline, closing, online, lingering, active | users | + + + +## Alerts + +There are no alerts configured by default for this integration. + + +## Setup + +### Prerequisites + +No action required. + +### Configuration + +#### File + +The configuration file name for this integration is `go.d/logind.conf`. + + +You can edit the configuration file using the `edit-config` script from the +Netdata [config directory](/docs/netdata-agent/configuration/README.md#the-netdata-config-directory). + +```bash +cd /etc/netdata 2>/dev/null || cd /opt/netdata/etc/netdata +sudo ./edit-config go.d/logind.conf +``` +#### Options + +The following options can be defined globally: update_every, autodetection_retry. + + +#### Examples +There are no configuration examples. + + + +## Troubleshooting + +### Debug Mode + +To troubleshoot issues with the `logind` collector, run the `go.d.plugin` with the debug option enabled. The output +should give you clues as to why the collector isn't working. + +- Navigate to the `plugins.d` directory, usually at `/usr/libexec/netdata/plugins.d/`. If that's not the case on + your system, open `netdata.conf` and look for the `plugins` setting under `[directories]`. + + ```bash + cd /usr/libexec/netdata/plugins.d/ + ``` + +- Switch to the `netdata` user. + + ```bash + sudo -u netdata -s + ``` + +- Run the `go.d.plugin` to debug the collector: + + ```bash + ./go.d.plugin -d -m logind + ``` + + diff --git a/src/go/collectors/go.d.plugin/modules/logind/logind.go b/src/go/collectors/go.d.plugin/modules/logind/logind.go new file mode 100644 index 000000000..97d2083a7 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/logind/logind.go @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +//go:build linux +// +build linux + +package logind + +import ( + _ "embed" + "errors" + "time" + + "github.com/netdata/netdata/go/go.d.plugin/agent/module" + "github.com/netdata/netdata/go/go.d.plugin/pkg/web" +) + +//go:embed "config_schema.json" +var configSchema string + +func init() { + module.Register("logind", module.Creator{ + JobConfigSchema: configSchema, + Defaults: module.Defaults{ + Priority: 59999, // copied from the python collector + }, + Create: func() module.Module { return New() }, + Config: func() any { return &Config{} }, + }) +} + +func New() *Logind { + return &Logind{ + Config: Config{ + Timeout: web.Duration(time.Second), + }, + newLogindConn: func(cfg Config) (logindConnection, error) { + return newLogindConnection(cfg.Timeout.Duration()) + }, + charts: charts.Copy(), + } +} + +type Config struct { + UpdateEvery int `yaml:"update_every,omitempty" json:"update_every"` + Timeout web.Duration `yaml:"timeout,omitempty" json:"timeout"` +} + +type Logind struct { + module.Base + Config `yaml:",inline" json:""` + + charts *module.Charts + + conn logindConnection + newLogindConn func(config Config) (logindConnection, error) +} + +func (l *Logind) Configuration() any { + return l.Config +} + +func (l *Logind) Init() error { + return nil +} + +func (l *Logind) Check() error { + mx, err := l.collect() + if err != nil { + l.Error(err) + return err + } + if len(mx) == 0 { + return errors.New("no metrics collected") + } + return nil +} + +func (l *Logind) Charts() *module.Charts { + return l.charts +} + +func (l *Logind) Collect() map[string]int64 { + mx, err := l.collect() + if err != nil { + l.Error(err) + } + + if len(mx) == 0 { + return nil + } + return mx +} + +func (l *Logind) Cleanup() { + if l.conn != nil { + l.conn.Close() + } +} diff --git a/src/go/collectors/go.d.plugin/modules/logind/logind_test.go b/src/go/collectors/go.d.plugin/modules/logind/logind_test.go new file mode 100644 index 000000000..7ba6b2258 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/logind/logind_test.go @@ -0,0 +1,350 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +//go:build linux +// +build linux + +package logind + +import ( + "errors" + "os" + "testing" + + "github.com/netdata/netdata/go/go.d.plugin/agent/module" + + "github.com/coreos/go-systemd/v22/login1" + "github.com/godbus/dbus/v5" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var ( + dataConfigJSON, _ = os.ReadFile("testdata/config.json") + dataConfigYAML, _ = os.ReadFile("testdata/config.yaml") +) + +func Test_testDataIsValid(t *testing.T) { + for name, data := range map[string][]byte{ + "dataConfigJSON": dataConfigJSON, + "dataConfigYAML": dataConfigYAML, + } { + require.NotNil(t, data, name) + } +} + +func TestLogind_ConfigurationSerialize(t *testing.T) { + module.TestConfigurationSerialize(t, &Logind{}, dataConfigJSON, dataConfigYAML) +} + +func TestLogind_Init(t *testing.T) { + tests := map[string]struct { + config Config + wantFail bool + }{ + "default config": { + wantFail: false, + config: New().Config, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + l := New() + l.Config = test.config + + if test.wantFail { + assert.Error(t, l.Init()) + } else { + assert.NoError(t, l.Init()) + } + }) + } +} + +func TestLogind_Charts(t *testing.T) { + assert.Equal(t, len(charts), len(*New().Charts())) +} + +func TestLogind_Cleanup(t *testing.T) { + tests := map[string]struct { + wantClose bool + prepare func(l *Logind) + }{ + "after New": { + wantClose: false, + prepare: func(l *Logind) {}, + }, + "after Init": { + wantClose: false, + prepare: func(l *Logind) { _ = l.Init() }, + }, + "after Check": { + wantClose: true, + prepare: func(l *Logind) { _ = l.Init(); _ = l.Check() }, + }, + "after Collect": { + wantClose: true, + prepare: func(l *Logind) { _ = l.Init(); l.Collect() }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + l := New() + m := prepareConnOK() + l.newLogindConn = func(Config) (logindConnection, error) { return m, nil } + test.prepare(l) + + require.NotPanics(t, l.Cleanup) + + if test.wantClose { + assert.True(t, m.closeCalled) + } else { + assert.False(t, m.closeCalled) + } + }) + } +} + +func TestLogind_Check(t *testing.T) { + tests := map[string]struct { + wantFail bool + prepare func() *mockConn + }{ + "success when response contains sessions and users": { + wantFail: false, + prepare: prepareConnOK, + }, + "success when response does not contain sessions and users": { + wantFail: false, + prepare: prepareConnOKNoSessionsNoUsers, + }, + "fail when error on list sessions": { + wantFail: true, + prepare: prepareConnErrOnListSessions, + }, + "fail when error on get session properties": { + wantFail: true, + prepare: prepareConnErrOnGetSessionProperties, + }, + "fail when error on list users": { + wantFail: true, + prepare: prepareConnErrOnListUsers, + }, + "fail when error on get user property": { + wantFail: true, + prepare: prepareConnErrOnGetUserProperty, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + l := New() + require.NoError(t, l.Init()) + l.conn = test.prepare() + + if test.wantFail { + assert.Error(t, l.Check()) + } else { + assert.NoError(t, l.Check()) + } + }) + } +} + +func TestLogind_Collect(t *testing.T) { + tests := map[string]struct { + prepare func() *mockConn + expected map[string]int64 + }{ + "success when response contains sessions and users": { + prepare: prepareConnOK, + expected: map[string]int64{ + "sessions_local": 3, + "sessions_remote": 0, + "sessions_state_active": 0, + "sessions_state_closing": 0, + "sessions_state_online": 3, + "sessions_type_console": 3, + "sessions_type_graphical": 0, + "sessions_type_other": 0, + "users_state_active": 3, + "users_state_closing": 0, + "users_state_lingering": 0, + "users_state_offline": 0, + "users_state_online": 0, + }, + }, + "success when response does not contain sessions and users": { + prepare: prepareConnOKNoSessionsNoUsers, + expected: map[string]int64{ + "sessions_local": 0, + "sessions_remote": 0, + "sessions_state_active": 0, + "sessions_state_closing": 0, + "sessions_state_online": 0, + "sessions_type_console": 0, + "sessions_type_graphical": 0, + "sessions_type_other": 0, + "users_state_active": 0, + "users_state_closing": 0, + "users_state_lingering": 0, + "users_state_offline": 0, + "users_state_online": 0, + }, + }, + "fail when error on list sessions": { + prepare: prepareConnErrOnListSessions, + expected: map[string]int64(nil), + }, + "fail when error on get session properties": { + prepare: prepareConnErrOnGetSessionProperties, + expected: map[string]int64(nil), + }, + "fail when error on list users": { + prepare: prepareConnErrOnListUsers, + expected: map[string]int64(nil), + }, + "fail when error on get user property": { + prepare: prepareConnErrOnGetUserProperty, + expected: map[string]int64(nil), + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + l := New() + require.NoError(t, l.Init()) + l.conn = test.prepare() + + mx := l.Collect() + + assert.Equal(t, test.expected, mx) + }) + } +} + +func prepareConnOK() *mockConn { + return &mockConn{ + sessions: []login1.Session{ + {Path: "/org/freedesktop/login1/session/_3156", User: "user1", ID: "123"}, + {Path: "/org/freedesktop/login1/session/_3157", User: "user2", ID: "124"}, + {Path: "/org/freedesktop/login1/session/_3158", User: "user3", ID: "125"}, + }, + users: []login1.User{ + {Path: "/org/freedesktop/login1/user/_1000", Name: "user1", UID: 123}, + {Path: "/org/freedesktop/login1/user/_1001", Name: "user2", UID: 124}, + {Path: "/org/freedesktop/login1/user/_1002", Name: "user3", UID: 125}, + }, + errOnListSessions: false, + errOnGetSessionProperties: false, + errOnListUsers: false, + errOnGetUserProperty: false, + closeCalled: false, + } +} + +func prepareConnOKNoSessionsNoUsers() *mockConn { + conn := prepareConnOK() + conn.sessions = nil + conn.users = nil + return conn +} + +func prepareConnErrOnListSessions() *mockConn { + conn := prepareConnOK() + conn.errOnListSessions = true + return conn +} + +func prepareConnErrOnGetSessionProperties() *mockConn { + conn := prepareConnOK() + conn.errOnGetSessionProperties = true + return conn +} + +func prepareConnErrOnListUsers() *mockConn { + conn := prepareConnOK() + conn.errOnListUsers = true + return conn +} + +func prepareConnErrOnGetUserProperty() *mockConn { + conn := prepareConnOK() + conn.errOnGetUserProperty = true + return conn +} + +type mockConn struct { + sessions []login1.Session + users []login1.User + + errOnListSessions bool + errOnGetSessionProperties bool + errOnListUsers bool + errOnGetUserProperty bool + closeCalled bool +} + +func (m *mockConn) Close() { + m.closeCalled = true +} + +func (m *mockConn) ListSessions() ([]login1.Session, error) { + if m.errOnListSessions { + return nil, errors.New("mock.ListSessions() error") + } + return m.sessions, nil +} + +func (m *mockConn) GetSessionProperties(path dbus.ObjectPath) (map[string]dbus.Variant, error) { + if m.errOnGetSessionProperties { + return nil, errors.New("mock.GetSessionProperties() error") + } + + var found bool + for _, s := range m.sessions { + if s.Path == path { + found = true + break + } + } + + if !found { + return nil, errors.New("mock.GetUserProperty(): session is not found") + } + + return map[string]dbus.Variant{ + "Remote": dbus.MakeVariant("true"), + "Type": dbus.MakeVariant("tty"), + "State": dbus.MakeVariant("online"), + }, nil +} + +func (m *mockConn) ListUsers() ([]login1.User, error) { + if m.errOnListUsers { + return nil, errors.New("mock.ListUsers() error") + } + return m.users, nil +} + +func (m *mockConn) GetUserProperty(path dbus.ObjectPath, _ string) (*dbus.Variant, error) { + if m.errOnGetUserProperty { + return nil, errors.New("mock.GetUserProperty() error") + } + + var found bool + for _, u := range m.users { + if u.Path == path { + found = true + break + } + } + + if !found { + return nil, errors.New("mock.GetUserProperty(): user is not found") + } + + v := dbus.MakeVariant("active") + return &v, nil +} diff --git a/src/go/collectors/go.d.plugin/modules/logind/metadata.yaml b/src/go/collectors/go.d.plugin/modules/logind/metadata.yaml new file mode 100644 index 000000000..792a515fe --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/logind/metadata.yaml @@ -0,0 +1,105 @@ +plugin_name: go.d.plugin +modules: + - meta: + id: collector-go.d.plugin-logind + plugin_name: go.d.plugin + module_name: logind + monitored_instance: + name: systemd-logind users + link: https://www.freedesktop.org/software/systemd/man/systemd-logind.service.html + icon_filename: users.svg + categories: + - data-collection.systemd + keywords: + - logind + - systemd + related_resources: + integrations: + list: [] + info_provided_to_referring_integrations: + description: "" + most_popular: false + overview: + data_collection: + metrics_description: | + This collector monitors number of sessions and users as reported by the `org.freedesktop.login1` DBus API. + method_description: "" + supported_platforms: + include: [] + exclude: [] + multi_instance: true + additional_permissions: + description: "" + default_behavior: + auto_detection: + description: "" + limits: + description: "" + performance_impact: + description: "" + setup: + prerequisites: + list: [] + configuration: + file: + name: go.d/logind.conf + options: + description: | + The following options can be defined globally: update_every, autodetection_retry. + folding: + title: Config options + enabled: true + list: [] + examples: + folding: + title: Config + enabled: true + list: [] + troubleshooting: + problems: + list: [] + alerts: [] + metrics: + folding: + title: Metrics + enabled: false + description: "" + availability: [] + scopes: + - name: global + description: These metrics refer to the entire monitored application. + labels: [] + metrics: + - name: logind.sessions + description: Logind Sessions + unit: sessions + chart_type: stacked + dimensions: + - name: remote + - name: local + - name: logind.sessions_type + description: Logind Sessions By Type + unit: sessions + chart_type: stacked + dimensions: + - name: console + - name: graphical + - name: other + - name: logind.sessions_state + description: Logind Sessions By State + unit: sessions + chart_type: stacked + dimensions: + - name: online + - name: closing + - name: active + - name: logind.users_state + description: Logind Users By State + unit: users + chart_type: stacked + dimensions: + - name: offline + - name: closing + - name: online + - name: lingering + - name: active diff --git a/src/go/collectors/go.d.plugin/modules/logind/testdata/config.json b/src/go/collectors/go.d.plugin/modules/logind/testdata/config.json new file mode 100644 index 000000000..291ecee3d --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/logind/testdata/config.json @@ -0,0 +1,4 @@ +{ + "update_every": 123, + "timeout": 123.123 +} diff --git a/src/go/collectors/go.d.plugin/modules/logind/testdata/config.yaml b/src/go/collectors/go.d.plugin/modules/logind/testdata/config.yaml new file mode 100644 index 000000000..25b0b4c78 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/logind/testdata/config.yaml @@ -0,0 +1,2 @@ +update_every: 123 +timeout: 123.123 |