[MM-23882] Include database server version in telemetry (#14258)

* Add database server version to telemetry

Also added a new query in the store to retrieve the database version

* Add test for the GetDbVersion function

* More drivers in the tests

Co-authored-by: mattermod <mattermod@users.noreply.github.com>
This commit is contained in:
Mario de Frutos Dieguez
2020-04-09 11:08:15 +02:00
committed by GitHub
parent f6f025aeaa
commit 698b4b6934
8 changed files with 132 additions and 37 deletions

View File

@@ -802,6 +802,10 @@ func (a *App) trackServer() {
data["system_admins"] = scr
}
if scr, err := a.Srv().Store.GetDbVersion(); err == nil {
data["database_version"] = scr
}
a.SendDiagnostic(TRACK_SERVER, data)
}

View File

@@ -45,6 +45,7 @@ type SqlStore interface {
GetMaster() *gorp.DbMap
GetSearchReplica() *gorp.DbMap
GetReplica() *gorp.DbMap
GetDbVersion() (string, error)
TotalMasterDbConnections() int
TotalReadDbConnections() int
TotalSearchDbConnections() int

View File

@@ -301,6 +301,27 @@ func (ss *SqlSupplier) GetCurrentSchemaVersion() string {
return version
}
func (ss *SqlSupplier) GetDbVersion() (string, error) {
var sqlVersion string
if ss.DriverName() == model.DATABASE_DRIVER_POSTGRES {
sqlVersion = `SHOW server_version`
} else if ss.DriverName() == model.DATABASE_DRIVER_MYSQL {
sqlVersion = `SELECT version()`
} else if ss.DriverName() == model.DATABASE_DRIVER_SQLITE {
sqlVersion = `SELECT sqlite_version()`
} else {
return "", errors.New("Not supported driver")
}
version, err := ss.GetReplica().SelectStr(sqlVersion)
if err != nil {
return "", err
}
return version, nil
}
func (ss *SqlSupplier) GetMaster() *gorp.DbMap {
return ss.master
}

View File

@@ -4,14 +4,17 @@
package sqlstore_test
import (
"regexp"
"testing"
"github.com/mattermost/gorp"
_ "github.com/mattn/go-sqlite3"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/store/sqlstore"
"github.com/mattermost/mattermost-server/v5/store/storetest"
)
func TestGetReplica(t *testing.T) {
@@ -73,24 +76,10 @@ func TestGetReplica(t *testing.T) {
t.Run(testCase.Description, func(t *testing.T) {
t.Parallel()
driverName := model.DATABASE_DRIVER_SQLITE
dataSource := ":memory:"
maxIdleConns := 1
connMaxLifetimeMilliseconds := 3600000
maxOpenConns := 1
queryTimeout := 5
settings := model.SqlSettings{
DriverName: &driverName,
DataSource: &dataSource,
MaxIdleConns: &maxIdleConns,
ConnMaxLifetimeMilliseconds: &connMaxLifetimeMilliseconds,
MaxOpenConns: &maxOpenConns,
QueryTimeout: &queryTimeout,
DataSourceReplicas: testCase.DataSourceReplicas,
DataSourceSearchReplicas: testCase.DataSourceSearchReplicas,
}
supplier := sqlstore.NewSqlSupplier(settings, nil)
settings := makeSqlSettings(model.DATABASE_DRIVER_SQLITE)
settings.DataSourceReplicas = testCase.DataSourceReplicas
settings.DataSourceSearchReplicas = testCase.DataSourceSearchReplicas
supplier := sqlstore.NewSqlSupplier(*settings, nil)
replicas := make(map[*gorp.DbMap]bool)
for i := 0; i < 5; i++ {
@@ -142,6 +131,26 @@ func TestGetReplica(t *testing.T) {
}
}
func TestGetDbVersion(t *testing.T) {
testDrivers := []string{
model.DATABASE_DRIVER_POSTGRES,
model.DATABASE_DRIVER_MYSQL,
model.DATABASE_DRIVER_SQLITE,
}
for _, driver := range testDrivers {
t.Run("Should return db version for "+driver, func(t *testing.T) {
t.Parallel()
settings := makeSqlSettings(driver)
supplier := sqlstore.NewSqlSupplier(*settings, nil)
version, err := supplier.GetDbVersion()
require.Nil(t, err)
require.Regexp(t, regexp.MustCompile(`\d+\.\d+(\.\d+)?`), version)
})
}
}
func TestGetAllConns(t *testing.T) {
t.Parallel()
testCases := []struct {
@@ -210,27 +219,43 @@ func TestGetAllConns(t *testing.T) {
testCase := testCase
t.Run(testCase.Description, func(t *testing.T) {
t.Parallel()
driverName := model.DATABASE_DRIVER_SQLITE
dataSource := ":memory:"
maxIdleConns := 1
connMaxLifetimeMilliseconds := 3600000
maxOpenConns := 1
queryTimeout := 5
settings := model.SqlSettings{
DriverName: &driverName,
DataSource: &dataSource,
MaxIdleConns: &maxIdleConns,
ConnMaxLifetimeMilliseconds: &connMaxLifetimeMilliseconds,
MaxOpenConns: &maxOpenConns,
QueryTimeout: &queryTimeout,
DataSourceReplicas: testCase.DataSourceReplicas,
DataSourceSearchReplicas: testCase.DataSourceSearchReplicas,
}
supplier := sqlstore.NewSqlSupplier(settings, nil)
settings := makeSqlSettings(model.DATABASE_DRIVER_SQLITE)
settings.DataSourceReplicas = testCase.DataSourceReplicas
settings.DataSourceSearchReplicas = testCase.DataSourceSearchReplicas
supplier := sqlstore.NewSqlSupplier(*settings, nil)
assert.Len(t, supplier.GetAllConns(), testCase.ExpectedNumConnections)
})
}
}
func makeSqlSettings(driver string) *model.SqlSettings {
switch driver {
case model.DATABASE_DRIVER_POSTGRES:
return storetest.MakeSqlSettings(driver)
case model.DATABASE_DRIVER_MYSQL:
return storetest.MakeSqlSettings(driver)
case model.DATABASE_DRIVER_SQLITE:
return makeSqliteSettings()
}
return nil
}
func makeSqliteSettings() *model.SqlSettings {
driverName := model.DATABASE_DRIVER_SQLITE
dataSource := ":memory:"
maxIdleConns := 1
connMaxLifetimeMilliseconds := 3600000
maxOpenConns := 1
queryTimeout := 5
return &model.SqlSettings{
DriverName: &driverName,
DataSource: &dataSource,
MaxIdleConns: &maxIdleConns,
ConnMaxLifetimeMilliseconds: &connMaxLifetimeMilliseconds,
MaxOpenConns: &maxOpenConns,
QueryTimeout: &queryTimeout,
}
}

View File

@@ -54,6 +54,7 @@ type Store interface {
UnlockFromMaster()
DropAllTables()
GetCurrentSchemaVersion() string
GetDbVersion() (string, error)
TotalMasterDbConnections() int
TotalReadDbConnections() int
TotalSearchDbConnections() int

View File

@@ -379,6 +379,27 @@ func (_m *SqlStore) GetCurrentSchemaVersion() string {
return r0
}
// GetDbVersion provides a mock function with given fields:
func (_m *SqlStore) GetDbVersion() (string, error) {
ret := _m.Called()
var r0 string
if rf, ok := ret.Get(0).(func() string); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(string)
}
var r1 error
if rf, ok := ret.Get(1).(func() error); ok {
r1 = rf()
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetMaster provides a mock function with given fields:
func (_m *SqlStore) GetMaster() *gorp.DbMap {
ret := _m.Called()

View File

@@ -232,6 +232,27 @@ func (_m *Store) GetCurrentSchemaVersion() string {
return r0
}
// GetDbVersion provides a mock function with given fields:
func (_m *Store) GetDbVersion() (string, error) {
ret := _m.Called()
var r0 string
if rf, ok := ret.Get(0).(func() string); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(string)
}
var r1 error
if rf, ok := ret.Get(1).(func() error); ok {
r1 = rf()
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Group provides a mock function with given fields:
func (_m *Store) Group() store.GroupStore {
ret := _m.Called()

View File

@@ -87,6 +87,7 @@ func (s *Store) Close() { /* do nothing */ }
func (s *Store) LockToMaster() { /* do nothing */ }
func (s *Store) UnlockFromMaster() { /* do nothing */ }
func (s *Store) DropAllTables() { /* do nothing */ }
func (s *Store) GetDbVersion() (string, error) { return "", nil }
func (s *Store) TotalMasterDbConnections() int { return 1 }
func (s *Store) TotalReadDbConnections() int { return 1 }
func (s *Store) TotalSearchDbConnections() int { return 1 }