Moving diagnostics into a service (#14832)

* Moving diagnostics into a service

* Fixing golint checks

* Fixing tests

* Renaming from diagnostics to telemetry

* Adding missing files

* Initializing telemetry earlier in the server startup

* Fixing tests

* Adding a log for the telemetryID initialization error

* Addressing PR review comments

* Fixing merge problem

* Removing some extra Diagnostics mentions

* Making tests pass
Этот коммит содержится в:
Jesús Espino
2020-09-08 20:30:54 +02:00
коммит произвёл GitHub
родитель f0eb67fa0d
Коммит 44079785eb
28 изменённых файлов: 1019 добавлений и 688 удалений

Просмотреть файл

@@ -26,7 +26,6 @@ import (
"github.com/gorilla/mux"
"github.com/pkg/errors"
"github.com/rs/cors"
rudder "github.com/rudderlabs/analytics-go"
"golang.org/x/crypto/acme/autocert"
@@ -44,6 +43,7 @@ import (
"github.com/mattermost/mattermost-server/v5/services/mailservice"
"github.com/mattermost/mattermost-server/v5/services/searchengine"
"github.com/mattermost/mattermost-server/v5/services/searchengine/bleveengine"
"github.com/mattermost/mattermost-server/v5/services/telemetry"
"github.com/mattermost/mattermost-server/v5/services/timezones"
"github.com/mattermost/mattermost-server/v5/services/tracing"
"github.com/mattermost/mattermost-server/v5/services/upgrader"
@@ -58,6 +58,9 @@ import (
var MaxNotificationsPerChannelDefault int64 = 1000000
// declaring this as var to allow overriding in tests
var SENTRY_DSN = "placeholder_sentry_dsn"
type Server struct {
sqlStore *sqlstore.SqlSupplier
Store store.Store
@@ -136,8 +139,7 @@ type Server struct {
clientConfigHash atomic.Value
limitedClientConfig atomic.Value
diagnosticId string
rudderClient rudder.Client
telemetryService *telemetry.TelemetryService
phase2PermissionsMigrationComplete bool
@@ -167,8 +169,7 @@ type Server struct {
CacheProvider cache.Provider
tracer *tracing.Tracer
timestampLastDiagnosticSent time.Time
tracer *tracing.Tracer
}
func NewServer(options ...Option) (*Server, error) {
@@ -331,6 +332,8 @@ func NewServer(options ...Option) (*Server, error) {
s.Store = s.newStore()
s.telemetryService = telemetry.New(s, s.Store, s.SearchEngine, s.Log)
emailService, err := NewEmailService(s)
if err != nil {
return nil, errors.Wrapf(err, "unable to initialize email service")
@@ -363,7 +366,6 @@ func NewServer(options ...Option) (*Server, error) {
return nil, errors.Wrapf(err, "unable to ensure first run timestamp")
}
s.ensureDiagnosticId()
s.regenerateClientConfig()
s.clusterLeaderListenerId = s.AddClusterLeaderChangedListener(func() {
@@ -519,7 +521,13 @@ func (s *Server) RunJobs() {
runSecurityJob(s)
})
s.Go(func() {
runDiagnosticsJob(s)
firstRun, err := s.getFirstServerRunTimestamp()
if err != nil {
mlog.Warn("Fetching time of first server run failed. Setting to 'now'.")
s.ensureFirstServerRunTimestamp()
firstRun = utils.MillisFromTime(time.Now())
}
s.telemetryService.RunTelemetryJob(firstRun)
})
s.Go(func() {
runSessionCleanupJob(s)
@@ -676,9 +684,9 @@ func (s *Server) Shutdown() error {
}
}
err := s.shutdownDiagnostics()
err := s.telemetryService.Shutdown()
if err != nil {
mlog.Error("Unable to cleanly shutdown diagnostic client", mlog.Err(err))
mlog.Error("Unable to cleanly shutdown telemetry client", mlog.Err(err))
}
s.StopHTTPServer()
@@ -1105,34 +1113,6 @@ func runSecurityJob(s *Server) {
}, time.Hour*4)
}
func doDiagnosticsIfNeeded(s *Server, firstRun time.Time) {
hoursSinceFirstServerRun := time.Since(firstRun).Hours()
// Send once every 10 minutes for the first hour
// Send once every hour thereafter for the first 12 hours
// Send at the 24 hour mark and every 24 hours after
if hoursSinceFirstServerRun < 1 {
doDiagnostics(s)
} else if hoursSinceFirstServerRun <= 12 && time.Since(s.timestampLastDiagnosticSent) >= time.Hour {
doDiagnostics(s)
} else if hoursSinceFirstServerRun > 12 && time.Since(s.timestampLastDiagnosticSent) >= 24*time.Hour {
doDiagnostics(s)
}
}
func runDiagnosticsJob(s *Server) {
// Send on boot
doDiagnostics(s)
firstRun, err := s.getFirstServerRunTimestamp()
if err != nil {
mlog.Warn("Fetching time of first server run failed. Setting to 'now'.")
s.ensureFirstServerRunTimestamp()
firstRun = utils.MillisFromTime(time.Now())
}
model.CreateRecurringTask("Diagnostics", func() {
doDiagnosticsIfNeeded(s, utils.TimeFromMillis(firstRun))
}, time.Minute*10)
}
func runTokenCleanupJob(s *Server) {
doTokenCleanup(s)
model.CreateRecurringTask("Token Cleanup", func() {
@@ -1172,13 +1152,6 @@ func doSecurity(s *Server) {
s.DoSecurityUpdateCheck()
}
func doDiagnostics(s *Server) {
if *s.Config().LogSettings.EnableDiagnostics {
s.timestampLastDiagnosticSent = time.Now()
s.SendDailyDiagnostics()
}
}
func doTokenCleanup(s *Server) {
s.Store.Token().Cleanup()
}
@@ -1368,39 +1341,6 @@ func (s *Server) stopSearchEngine() {
}
}
// initDiagnostics initialises the Rudder client for the diagnostics system.
func (s *Server) initDiagnostics(endpoint string, rudderKey string) {
if s.rudderClient == nil {
config := rudder.Config{}
config.Logger = rudder.StdLogger(s.Log.StdLog(mlog.String("source", "rudder")))
config.Endpoint = endpoint
// For testing
if endpoint != RUDDER_DATAPLANE_URL {
config.Verbose = true
config.BatchSize = 1
}
client, err := rudder.NewWithConfig(rudderKey, endpoint, config)
if err != nil {
mlog.Error("Failed to create Rudder instance", mlog.Err(err))
return
}
client.Enqueue(rudder.Identify{
UserId: s.diagnosticId,
})
s.rudderClient = client
}
}
// shutdownDiagnostics closes the diagnostics system Rudder client.
func (s *Server) shutdownDiagnostics() error {
if s.rudderClient != nil {
return s.rudderClient.Close()
}
return nil
}
func (s *Server) FileBackend() (filesstore.FileBackend, *model.AppError) {
license := s.License()
return filesstore.NewFileBackend(&s.Config().FileSettings, license != nil && *license.Features.Compliance)
@@ -1421,25 +1361,6 @@ func (s *Server) ClusterHealthScore() int {
return s.Cluster.HealthScore()
}
func (s *Server) ensureDiagnosticId() {
if s.diagnosticId != "" {
return
}
props, err := s.Store.System().Get()
if err != nil {
return
}
id := props[model.SYSTEM_DIAGNOSTIC_ID]
if len(id) == 0 {
id = model.NewId()
systemID := &model.System{Name: model.SYSTEM_DIAGNOSTIC_ID, Value: id}
s.Store.System().Save(systemID)
}
s.diagnosticId = id
}
func (s *Server) configOrLicenseListener() {
s.regenerateClientConfig()
}
@@ -1469,3 +1390,14 @@ func (s *Server) initJobs() {
s.Jobs.Migrations = jobsMigrationsInterface(s)
}
}
func (s *Server) TelemetryId() string {
if s.telemetryService == nil {
return ""
}
return s.telemetryService.TelemetryID
}
func (s *Server) HttpService() httpservice.HTTPService {
return s.HTTPService
}