diff --git a/plugins/inputs/mongodb/mongostat.go b/plugins/inputs/mongodb/mongostat.go index dd22856f4..392d042fb 100644 --- a/plugins/inputs/mongodb/mongostat.go +++ b/plugins/inputs/mongodb/mongostat.go @@ -1222,16 +1222,18 @@ func NewStatLine(oldMongo, newMongo MongoStatus, key string, all bool, sampleSec oldStat.ExtraInfo.PageFaults != nil && newStat.ExtraInfo.PageFaults != nil { returnVal.Faults, returnVal.FaultsCnt = diff(*(newStat.ExtraInfo.PageFaults), *(oldStat.ExtraInfo.PageFaults), sampleSecs) } - if !returnVal.IsMongos && oldStat.Locks != nil { - globalCheck, hasGlobal := oldStat.Locks["Global"] - if hasGlobal && globalCheck.AcquireCount != nil { + if !returnVal.IsMongos && oldStat.Locks != nil && newStat.Locks != nil { + globalCheckOld, hasGlobalOld := oldStat.Locks["Global"] + globalCheckNew, hasGlobalNew := newStat.Locks["Global"] + if hasGlobalOld && globalCheckOld.AcquireCount != nil && hasGlobalNew && globalCheckNew.AcquireCount != nil { // This appears to be a 3.0+ server so the data in these fields do *not* refer to // actual namespaces and thus we can't compute lock %. returnVal.HighestLocked = nil // Check if it's a 3.0+ MMAP server so we can still compute collection locks - collectionCheck, hasCollection := oldStat.Locks["Collection"] - if hasCollection && collectionCheck.AcquireWaitCount != nil { + collectionCheckOld, hasCollectionOld := oldStat.Locks["Collection"] + collectionCheckNew, hasCollectionNew := newStat.Locks["Collection"] + if hasCollectionOld && collectionCheckOld.AcquireWaitCount != nil && hasCollectionNew && collectionCheckNew.AcquireWaitCount != nil { readWaitCountDiff := newStat.Locks["Collection"].AcquireWaitCount.Read - oldStat.Locks["Collection"].AcquireWaitCount.Read readTotalCountDiff := newStat.Locks["Collection"].AcquireCount.Read - oldStat.Locks["Collection"].AcquireCount.Read writeWaitCountDiff := newStat.Locks["Collection"].AcquireWaitCount.Write - oldStat.Locks["Collection"].AcquireWaitCount.Write diff --git a/plugins/inputs/mongodb/mongostat_test.go b/plugins/inputs/mongodb/mongostat_test.go index 908b82de1..47ba05884 100644 --- a/plugins/inputs/mongodb/mongostat_test.go +++ b/plugins/inputs/mongodb/mongostat_test.go @@ -198,3 +198,414 @@ func TestLatencyStatsDiff(t *testing.T) { require.Equal(t, sl.ReadOpsCnt, int64(4189049884)) require.Equal(t, sl.WriteOpsCnt, int64(1691021287)) } + +func TestLocksStatsNilWhenLocksMissingInOldStat(t *testing.T) { + sl := NewStatLine( + MongoStatus{ + ServerStatus: &ServerStatus{ + Connections: &ConnectionStats{}, + Mem: &MemStats{ + Supported: false, + }, + }, + }, + MongoStatus{ + ServerStatus: &ServerStatus{ + Connections: &ConnectionStats{}, + Mem: &MemStats{ + Supported: false, + }, + Locks: map[string]LockStats{ + "Global": { + AcquireCount: &ReadWriteLockTimes{}, + }, + }, + }, + }, + "foo", + true, + 60, + ) + + require.Nil(t, sl.CollectionLocks) +} + +func TestLocksStatsNilWhenGlobalLockStatsMissingInOldStat(t *testing.T) { + sl := NewStatLine( + MongoStatus{ + ServerStatus: &ServerStatus{ + Connections: &ConnectionStats{}, + Mem: &MemStats{ + Supported: false, + }, + Locks: map[string]LockStats{}, + }, + }, + MongoStatus{ + ServerStatus: &ServerStatus{ + Connections: &ConnectionStats{}, + Mem: &MemStats{ + Supported: false, + }, + Locks: map[string]LockStats{ + "Global": { + AcquireCount: &ReadWriteLockTimes{}, + }, + }, + }, + }, + "foo", + true, + 60, + ) + + require.Nil(t, sl.CollectionLocks) +} + +func TestLocksStatsNilWhenGlobalLockStatsEmptyInOldStat(t *testing.T) { + sl := NewStatLine( + MongoStatus{ + ServerStatus: &ServerStatus{ + Connections: &ConnectionStats{}, + Mem: &MemStats{ + Supported: false, + }, + Locks: map[string]LockStats{ + "Global": {}, + }, + }, + }, + MongoStatus{ + ServerStatus: &ServerStatus{ + Connections: &ConnectionStats{}, + Mem: &MemStats{ + Supported: false, + }, + Locks: map[string]LockStats{ + "Global": { + AcquireCount: &ReadWriteLockTimes{}, + }, + }, + }, + }, + "foo", + true, + 60, + ) + + require.Nil(t, sl.CollectionLocks) +} + +func TestLocksStatsNilWhenCollectionLockStatsMissingInOldStat(t *testing.T) { + sl := NewStatLine( + MongoStatus{ + ServerStatus: &ServerStatus{ + Connections: &ConnectionStats{}, + Mem: &MemStats{ + Supported: false, + }, + Locks: map[string]LockStats{ + "Global": { + AcquireCount: &ReadWriteLockTimes{}, + }, + }, + }, + }, + MongoStatus{ + ServerStatus: &ServerStatus{ + Connections: &ConnectionStats{}, + Mem: &MemStats{ + Supported: false, + }, + Locks: map[string]LockStats{ + "Global": { + AcquireCount: &ReadWriteLockTimes{}, + }, + }, + }, + }, + "foo", + true, + 60, + ) + + require.Nil(t, sl.CollectionLocks) +} + +func TestLocksStatsNilWhenCollectionLockStatsEmptyInOldStat(t *testing.T) { + sl := NewStatLine( + MongoStatus{ + ServerStatus: &ServerStatus{ + Connections: &ConnectionStats{}, + Mem: &MemStats{ + Supported: false, + }, + Locks: map[string]LockStats{ + "Global": { + AcquireCount: &ReadWriteLockTimes{}, + }, + "Collection": {}, + }, + }, + }, + MongoStatus{ + ServerStatus: &ServerStatus{ + Connections: &ConnectionStats{}, + Mem: &MemStats{ + Supported: false, + }, + Locks: map[string]LockStats{ + "Global": { + AcquireCount: &ReadWriteLockTimes{}, + }, + }, + }, + }, + "foo", + true, + 60, + ) + + require.Nil(t, sl.CollectionLocks) +} + +func TestLocksStatsNilWhenLocksMissingInNewStat(t *testing.T) { + sl := NewStatLine( + MongoStatus{ + ServerStatus: &ServerStatus{ + Connections: &ConnectionStats{}, + Mem: &MemStats{ + Supported: false, + }, + Locks: map[string]LockStats{ + "Global": { + AcquireCount: &ReadWriteLockTimes{}, + }, + }, + }, + }, + MongoStatus{ + ServerStatus: &ServerStatus{ + Connections: &ConnectionStats{}, + Mem: &MemStats{ + Supported: false, + }, + }, + }, + "foo", + true, + 60, + ) + + require.Nil(t, sl.CollectionLocks) +} + +func TestLocksStatsNilWhenGlobalLockStatsMissingInNewStat(t *testing.T) { + sl := NewStatLine( + MongoStatus{ + ServerStatus: &ServerStatus{ + Connections: &ConnectionStats{}, + Mem: &MemStats{ + Supported: false, + }, + Locks: map[string]LockStats{ + "Global": { + AcquireCount: &ReadWriteLockTimes{}, + }, + }, + }, + }, + MongoStatus{ + ServerStatus: &ServerStatus{ + Connections: &ConnectionStats{}, + Mem: &MemStats{ + Supported: false, + }, + Locks: map[string]LockStats{}, + }, + }, + "foo", + true, + 60, + ) + + require.Nil(t, sl.CollectionLocks) +} + +func TestLocksStatsNilWhenGlobalLockStatsEmptyInNewStat(t *testing.T) { + sl := NewStatLine( + MongoStatus{ + ServerStatus: &ServerStatus{ + Connections: &ConnectionStats{}, + Mem: &MemStats{ + Supported: false, + }, + Locks: map[string]LockStats{ + "Global": { + AcquireCount: &ReadWriteLockTimes{}, + }, + }, + }, + }, + MongoStatus{ + ServerStatus: &ServerStatus{ + Connections: &ConnectionStats{}, + Mem: &MemStats{ + Supported: false, + }, + Locks: map[string]LockStats{ + "Global": {}, + }, + }, + }, + "foo", + true, + 60, + ) + + require.Nil(t, sl.CollectionLocks) +} + +func TestLocksStatsNilWhenCollectionLockStatsMissingInNewStat(t *testing.T) { + sl := NewStatLine( + MongoStatus{ + ServerStatus: &ServerStatus{ + Connections: &ConnectionStats{}, + Mem: &MemStats{ + Supported: false, + }, + Locks: map[string]LockStats{ + "Global": { + AcquireCount: &ReadWriteLockTimes{}, + }, + }, + }, + }, + MongoStatus{ + ServerStatus: &ServerStatus{ + Connections: &ConnectionStats{}, + Mem: &MemStats{ + Supported: false, + }, + Locks: map[string]LockStats{ + "Global": { + AcquireCount: &ReadWriteLockTimes{}, + }, + }, + }, + }, + "foo", + true, + 60, + ) + + require.Nil(t, sl.CollectionLocks) +} + +func TestLocksStatsNilWhenCollectionLockStatsEmptyInNewStat(t *testing.T) { + sl := NewStatLine( + MongoStatus{ + ServerStatus: &ServerStatus{ + Connections: &ConnectionStats{}, + Mem: &MemStats{ + Supported: false, + }, + Locks: map[string]LockStats{ + "Global": { + AcquireCount: &ReadWriteLockTimes{}, + }, + }, + }, + }, + MongoStatus{ + ServerStatus: &ServerStatus{ + Connections: &ConnectionStats{}, + Mem: &MemStats{ + Supported: false, + }, + Locks: map[string]LockStats{ + "Global": { + AcquireCount: &ReadWriteLockTimes{}, + }, + "Collection": {}, + }, + }, + }, + "foo", + true, + 60, + ) + + require.Nil(t, sl.CollectionLocks) +} + +func TestLocksStatsPopulated(t *testing.T) { + sl := NewStatLine( + MongoStatus{ + ServerStatus: &ServerStatus{ + Connections: &ConnectionStats{}, + Mem: &MemStats{ + Supported: false, + }, + Locks: map[string]LockStats{ + "Global": { + AcquireCount: &ReadWriteLockTimes{}, + }, + "Collection": { + AcquireWaitCount: &ReadWriteLockTimes{ + Read: 1, + Write: 2, + }, + AcquireCount: &ReadWriteLockTimes{ + Read: 5, + Write: 10, + }, + TimeAcquiringMicros: ReadWriteLockTimes{ + Read: 100, + Write: 200, + }, + }, + }, + }, + }, + MongoStatus{ + ServerStatus: &ServerStatus{ + Connections: &ConnectionStats{}, + Mem: &MemStats{ + Supported: false, + }, + Locks: map[string]LockStats{ + "Global": { + AcquireCount: &ReadWriteLockTimes{}, + }, + "Collection": { + AcquireWaitCount: &ReadWriteLockTimes{ + Read: 2, + Write: 4, + }, + AcquireCount: &ReadWriteLockTimes{ + Read: 10, + Write: 30, + }, + TimeAcquiringMicros: ReadWriteLockTimes{ + Read: 250, + Write: 310, + }, + }, + }, + }, + }, + "foo", + true, + 60, + ) + + expected := &CollectionLockStatus{ + ReadAcquireWaitsPercentage: 20, + WriteAcquireWaitsPercentage: 10, + ReadAcquireTimeMicros: 150, + WriteAcquireTimeMicros: 55, + } + + require.Equal(t, expected, sl.CollectionLocks) +}