github.com/haalcala/mattermost-server-change-repo/v5@v5.33.2/services/telemetry/telemetry.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package telemetry
     5  
     6  import (
     7  	"os"
     8  	"path/filepath"
     9  	"runtime"
    10  	"strings"
    11  	"time"
    12  
    13  	rudder "github.com/rudderlabs/analytics-go"
    14  
    15  	"github.com/mattermost/mattermost-server/v5/mlog"
    16  	"github.com/mattermost/mattermost-server/v5/model"
    17  	"github.com/mattermost/mattermost-server/v5/plugin"
    18  	"github.com/mattermost/mattermost-server/v5/services/httpservice"
    19  	"github.com/mattermost/mattermost-server/v5/services/marketplace"
    20  	"github.com/mattermost/mattermost-server/v5/services/searchengine"
    21  	"github.com/mattermost/mattermost-server/v5/store"
    22  	"github.com/mattermost/mattermost-server/v5/utils"
    23  )
    24  
    25  const (
    26  	DayMilliseconds   = 24 * 60 * 60 * 1000
    27  	MonthMilliseconds = 31 * DayMilliseconds
    28  
    29  	RudderKey          = "placeholder_rudder_key"
    30  	RudderDataplaneURL = "placeholder_rudder_dataplane_url"
    31  
    32  	EnvVarInstallType = "MM_INSTALL_TYPE"
    33  
    34  	TrackConfigService           = "config_service"
    35  	TrackConfigTeam              = "config_team"
    36  	TrackConfigClientReq         = "config_client_requirements"
    37  	TrackConfigSQL               = "config_sql"
    38  	TrackConfigLog               = "config_log"
    39  	TrackConfigAudit             = "config_audit"
    40  	TrackConfigNotificationLog   = "config_notifications_log"
    41  	TrackConfigFile              = "config_file"
    42  	TrackConfigRate              = "config_rate"
    43  	TrackConfigEmail             = "config_email"
    44  	TrackConfigPrivacy           = "config_privacy"
    45  	TrackConfigTheme             = "config_theme"
    46  	TrackConfigOauth             = "config_oauth"
    47  	TrackConfigLDAP              = "config_ldap"
    48  	TrackConfigCompliance        = "config_compliance"
    49  	TrackConfigLocalization      = "config_localization"
    50  	TrackConfigSAML              = "config_saml"
    51  	TrackConfigPassword          = "config_password"
    52  	TrackConfigCluster           = "config_cluster"
    53  	TrackConfigMetrics           = "config_metrics"
    54  	TrackConfigSupport           = "config_support"
    55  	TrackConfigNativeApp         = "config_nativeapp"
    56  	TrackConfigExperimental      = "config_experimental"
    57  	TrackConfigAnalytics         = "config_analytics"
    58  	TrackConfigAnnouncement      = "config_announcement"
    59  	TrackConfigElasticsearch     = "config_elasticsearch"
    60  	TrackConfigPlugin            = "config_plugin"
    61  	TrackConfigDataRetention     = "config_data_retention"
    62  	TrackConfigMessageExport     = "config_message_export"
    63  	TrackConfigDisplay           = "config_display"
    64  	TrackConfigGuestAccounts     = "config_guest_accounts"
    65  	TrackConfigImageProxy        = "config_image_proxy"
    66  	TrackConfigBleve             = "config_bleve"
    67  	TrackConfigExport            = "config_export"
    68  	TrackPermissionsGeneral      = "permissions_general"
    69  	TrackPermissionsSystemScheme = "permissions_system_scheme"
    70  	TrackPermissionsTeamSchemes  = "permissions_team_schemes"
    71  	TrackPermissionsSystemRoles  = "permissions_system_roles"
    72  	TrackElasticsearch           = "elasticsearch"
    73  	TrackGroups                  = "groups"
    74  	TrackChannelModeration       = "channel_moderation"
    75  	TrackWarnMetrics             = "warn_metrics"
    76  
    77  	TrackActivity = "activity"
    78  	TrackLicense  = "license"
    79  	TrackServer   = "server"
    80  	TrackPlugins  = "plugins"
    81  )
    82  
    83  type ServerIface interface {
    84  	Config() *model.Config
    85  	IsLeader() bool
    86  	HttpService() httpservice.HTTPService
    87  	GetPluginsEnvironment() *plugin.Environment
    88  	License() *model.License
    89  	GetRoleByName(string) (*model.Role, *model.AppError)
    90  	GetSchemes(string, int, int) ([]*model.Scheme, *model.AppError)
    91  }
    92  
    93  type TelemetryService struct {
    94  	srv                        ServerIface
    95  	dbStore                    store.Store
    96  	searchEngine               *searchengine.Broker
    97  	log                        *mlog.Logger
    98  	rudderClient               rudder.Client
    99  	TelemetryID                string
   100  	timestampLastTelemetrySent time.Time
   101  }
   102  
   103  type RudderConfig struct {
   104  	RudderKey    string
   105  	DataplaneUrl string
   106  }
   107  
   108  func New(srv ServerIface, dbStore store.Store, searchEngine *searchengine.Broker, log *mlog.Logger) *TelemetryService {
   109  	service := &TelemetryService{
   110  		srv:          srv,
   111  		dbStore:      dbStore,
   112  		searchEngine: searchEngine,
   113  		log:          log,
   114  	}
   115  	service.ensureTelemetryID()
   116  	return service
   117  }
   118  
   119  func (ts *TelemetryService) ensureTelemetryID() {
   120  	if ts.TelemetryID != "" {
   121  		return
   122  	}
   123  	props, err := ts.dbStore.System().Get()
   124  	if err != nil {
   125  		mlog.Error("unable to get the telemetry ID", mlog.Err(err))
   126  		return
   127  	}
   128  
   129  	id := props[model.SYSTEM_TELEMETRY_ID]
   130  	if id == "" {
   131  		id = model.NewId()
   132  		systemID := &model.System{Name: model.SYSTEM_TELEMETRY_ID, Value: id}
   133  		ts.dbStore.System().Save(systemID)
   134  	}
   135  
   136  	ts.TelemetryID = id
   137  }
   138  
   139  func (ts *TelemetryService) getRudderConfig() RudderConfig {
   140  	if !strings.Contains(RudderKey, "placeholder") && !strings.Contains(RudderDataplaneURL, "placeholder") {
   141  		return RudderConfig{RudderKey, RudderDataplaneURL}
   142  	} else if os.Getenv("RudderKey") != "" && os.Getenv("RudderDataplaneURL") != "" {
   143  		return RudderConfig{os.Getenv("RudderKey"), os.Getenv("RudderDataplaneURL")}
   144  	} else {
   145  		return RudderConfig{}
   146  	}
   147  }
   148  
   149  func (ts *TelemetryService) telemetryEnabled() bool {
   150  	return *ts.srv.Config().LogSettings.EnableDiagnostics && ts.srv.IsLeader()
   151  }
   152  
   153  func (ts *TelemetryService) sendDailyTelemetry(override bool) {
   154  	config := ts.getRudderConfig()
   155  	if ts.telemetryEnabled() && ((config.DataplaneUrl != "" && config.RudderKey != "") || override) {
   156  		ts.initRudder(config.DataplaneUrl, config.RudderKey)
   157  		ts.trackActivity()
   158  		ts.trackConfig()
   159  		ts.trackLicense()
   160  		ts.trackPlugins()
   161  		ts.trackServer()
   162  		ts.trackPermissions()
   163  		ts.trackElasticsearch()
   164  		ts.trackGroups()
   165  		ts.trackChannelModeration()
   166  		ts.trackWarnMetrics()
   167  	}
   168  }
   169  
   170  func (ts *TelemetryService) sendTelemetry(event string, properties map[string]interface{}) {
   171  	if ts.rudderClient != nil {
   172  		var context *rudder.Context
   173  		// if we are part of a cloud installation, add it's ID to the tracked event's context
   174  		if installationId := os.Getenv("MM_CLOUD_INSTALLATION_ID"); installationId != "" {
   175  			context = &rudder.Context{Traits: map[string]interface{}{"installationId": installationId}}
   176  		}
   177  		ts.rudderClient.Enqueue(rudder.Track{
   178  			Event:      event,
   179  			UserId:     ts.TelemetryID,
   180  			Properties: properties,
   181  			Context:    context,
   182  		})
   183  	}
   184  }
   185  
   186  func isDefaultArray(setting, defaultValue []string) bool {
   187  	if len(setting) != len(defaultValue) {
   188  		return false
   189  	}
   190  	for i := 0; i < len(setting); i++ {
   191  		if setting[i] != defaultValue[i] {
   192  			return false
   193  		}
   194  	}
   195  	return true
   196  }
   197  
   198  func isDefault(setting interface{}, defaultValue interface{}) bool {
   199  	return setting == defaultValue
   200  }
   201  
   202  func pluginSetting(pluginSettings *model.PluginSettings, plugin, key string, defaultValue interface{}) interface{} {
   203  	settings, ok := pluginSettings.Plugins[plugin]
   204  	if !ok {
   205  		return defaultValue
   206  	}
   207  	if value, ok := settings[key]; ok {
   208  		return value
   209  	}
   210  	return defaultValue
   211  }
   212  
   213  func pluginActivated(pluginStates map[string]*model.PluginState, pluginId string) bool {
   214  	state, ok := pluginStates[pluginId]
   215  	if !ok {
   216  		return false
   217  	}
   218  	return state.Enable
   219  }
   220  
   221  func pluginVersion(pluginsAvailable []*model.BundleInfo, pluginId string) string {
   222  	for _, plugin := range pluginsAvailable {
   223  		if plugin.Manifest != nil && plugin.Manifest.Id == pluginId {
   224  			return plugin.Manifest.Version
   225  		}
   226  	}
   227  	return ""
   228  }
   229  
   230  func (ts *TelemetryService) trackActivity() {
   231  	var userCount int64
   232  	var guestAccountsCount int64
   233  	var botAccountsCount int64
   234  	var inactiveUserCount int64
   235  	var publicChannelCount int64
   236  	var privateChannelCount int64
   237  	var directChannelCount int64
   238  	var deletedPublicChannelCount int64
   239  	var deletedPrivateChannelCount int64
   240  	var postsCount int64
   241  	var postsCountPreviousDay int64
   242  	var botPostsCountPreviousDay int64
   243  	var slashCommandsCount int64
   244  	var incomingWebhooksCount int64
   245  	var outgoingWebhooksCount int64
   246  
   247  	activeUsersDailyCountChan := make(chan store.StoreResult, 1)
   248  	go func() {
   249  		count, err := ts.dbStore.User().AnalyticsActiveCount(DayMilliseconds, model.UserCountOptions{IncludeBotAccounts: false, IncludeDeleted: false})
   250  		activeUsersDailyCountChan <- store.StoreResult{Data: count, NErr: err}
   251  		close(activeUsersDailyCountChan)
   252  	}()
   253  
   254  	activeUsersMonthlyCountChan := make(chan store.StoreResult, 1)
   255  	go func() {
   256  		count, err := ts.dbStore.User().AnalyticsActiveCount(MonthMilliseconds, model.UserCountOptions{IncludeBotAccounts: false, IncludeDeleted: false})
   257  		activeUsersMonthlyCountChan <- store.StoreResult{Data: count, NErr: err}
   258  		close(activeUsersMonthlyCountChan)
   259  	}()
   260  
   261  	if count, err := ts.dbStore.User().Count(model.UserCountOptions{IncludeDeleted: true}); err == nil {
   262  		userCount = count
   263  	}
   264  
   265  	if count, err := ts.dbStore.User().AnalyticsGetGuestCount(); err == nil {
   266  		guestAccountsCount = count
   267  	}
   268  
   269  	if count, err := ts.dbStore.User().Count(model.UserCountOptions{IncludeBotAccounts: true, ExcludeRegularUsers: true}); err == nil {
   270  		botAccountsCount = count
   271  	}
   272  
   273  	if iucr, err := ts.dbStore.User().AnalyticsGetInactiveUsersCount(); err == nil {
   274  		inactiveUserCount = iucr
   275  	}
   276  
   277  	teamCount, err := ts.dbStore.Team().AnalyticsTeamCount(false)
   278  	if err != nil {
   279  		mlog.Info("Could not get team count", mlog.Err(err))
   280  	}
   281  
   282  	if ucc, err := ts.dbStore.Channel().AnalyticsTypeCount("", "O"); err == nil {
   283  		publicChannelCount = ucc
   284  	}
   285  
   286  	if pcc, err := ts.dbStore.Channel().AnalyticsTypeCount("", "P"); err == nil {
   287  		privateChannelCount = pcc
   288  	}
   289  
   290  	if dcc, err := ts.dbStore.Channel().AnalyticsTypeCount("", "D"); err == nil {
   291  		directChannelCount = dcc
   292  	}
   293  
   294  	if duccr, err := ts.dbStore.Channel().AnalyticsDeletedTypeCount("", "O"); err == nil {
   295  		deletedPublicChannelCount = duccr
   296  	}
   297  
   298  	if dpccr, err := ts.dbStore.Channel().AnalyticsDeletedTypeCount("", "P"); err == nil {
   299  		deletedPrivateChannelCount = dpccr
   300  	}
   301  
   302  	postsCount, _ = ts.dbStore.Post().AnalyticsPostCount("", false, false)
   303  
   304  	postCountsOptions := &model.AnalyticsPostCountsOptions{TeamId: "", BotsOnly: false, YesterdayOnly: true}
   305  	postCountsYesterday, _ := ts.dbStore.Post().AnalyticsPostCountsByDay(postCountsOptions)
   306  	postsCountPreviousDay = 0
   307  	if len(postCountsYesterday) > 0 {
   308  		postsCountPreviousDay = int64(postCountsYesterday[0].Value)
   309  	}
   310  
   311  	postCountsOptions = &model.AnalyticsPostCountsOptions{TeamId: "", BotsOnly: true, YesterdayOnly: true}
   312  	botPostCountsYesterday, _ := ts.dbStore.Post().AnalyticsPostCountsByDay(postCountsOptions)
   313  	botPostsCountPreviousDay = 0
   314  	if len(botPostCountsYesterday) > 0 {
   315  		botPostsCountPreviousDay = int64(botPostCountsYesterday[0].Value)
   316  	}
   317  
   318  	slashCommandsCount, _ = ts.dbStore.Command().AnalyticsCommandCount("")
   319  
   320  	if c, err := ts.dbStore.Webhook().AnalyticsIncomingCount(""); err == nil {
   321  		incomingWebhooksCount = c
   322  	}
   323  
   324  	outgoingWebhooksCount, _ = ts.dbStore.Webhook().AnalyticsOutgoingCount("")
   325  
   326  	var activeUsersDailyCount int64
   327  	if r := <-activeUsersDailyCountChan; r.NErr == nil {
   328  		activeUsersDailyCount = r.Data.(int64)
   329  	}
   330  
   331  	var activeUsersMonthlyCount int64
   332  	if r := <-activeUsersMonthlyCountChan; r.NErr == nil {
   333  		activeUsersMonthlyCount = r.Data.(int64)
   334  	}
   335  
   336  	ts.sendTelemetry(TrackActivity, map[string]interface{}{
   337  		"registered_users":             userCount,
   338  		"bot_accounts":                 botAccountsCount,
   339  		"guest_accounts":               guestAccountsCount,
   340  		"active_users_daily":           activeUsersDailyCount,
   341  		"active_users_monthly":         activeUsersMonthlyCount,
   342  		"registered_deactivated_users": inactiveUserCount,
   343  		"teams":                        teamCount,
   344  		"public_channels":              publicChannelCount,
   345  		"private_channels":             privateChannelCount,
   346  		"direct_message_channels":      directChannelCount,
   347  		"public_channels_deleted":      deletedPublicChannelCount,
   348  		"private_channels_deleted":     deletedPrivateChannelCount,
   349  		"posts_previous_day":           postsCountPreviousDay,
   350  		"bot_posts_previous_day":       botPostsCountPreviousDay,
   351  		"posts":                        postsCount,
   352  		"slash_commands":               slashCommandsCount,
   353  		"incoming_webhooks":            incomingWebhooksCount,
   354  		"outgoing_webhooks":            outgoingWebhooksCount,
   355  	})
   356  }
   357  
   358  func (ts *TelemetryService) trackConfig() {
   359  	cfg := ts.srv.Config()
   360  	ts.sendTelemetry(TrackConfigService, map[string]interface{}{
   361  		"web_server_mode":                                         *cfg.ServiceSettings.WebserverMode,
   362  		"enable_security_fix_alert":                               *cfg.ServiceSettings.EnableSecurityFixAlert,
   363  		"enable_insecure_outgoing_connections":                    *cfg.ServiceSettings.EnableInsecureOutgoingConnections,
   364  		"enable_incoming_webhooks":                                cfg.ServiceSettings.EnableIncomingWebhooks,
   365  		"enable_outgoing_webhooks":                                cfg.ServiceSettings.EnableOutgoingWebhooks,
   366  		"enable_commands":                                         *cfg.ServiceSettings.EnableCommands,
   367  		"enable_only_admin_integrations":                          *cfg.ServiceSettings.DEPRECATED_DO_NOT_USE_EnableOnlyAdminIntegrations,
   368  		"enable_post_username_override":                           cfg.ServiceSettings.EnablePostUsernameOverride,
   369  		"enable_post_icon_override":                               cfg.ServiceSettings.EnablePostIconOverride,
   370  		"enable_user_access_tokens":                               *cfg.ServiceSettings.EnableUserAccessTokens,
   371  		"enable_custom_emoji":                                     *cfg.ServiceSettings.EnableCustomEmoji,
   372  		"enable_emoji_picker":                                     *cfg.ServiceSettings.EnableEmojiPicker,
   373  		"enable_gif_picker":                                       *cfg.ServiceSettings.EnableGifPicker,
   374  		"gfycat_api_key":                                          isDefault(*cfg.ServiceSettings.GfycatApiKey, model.SERVICE_SETTINGS_DEFAULT_GFYCAT_API_KEY),
   375  		"gfycat_api_secret":                                       isDefault(*cfg.ServiceSettings.GfycatApiSecret, model.SERVICE_SETTINGS_DEFAULT_GFYCAT_API_SECRET),
   376  		"experimental_enable_authentication_transfer":             *cfg.ServiceSettings.ExperimentalEnableAuthenticationTransfer,
   377  		"restrict_custom_emoji_creation":                          *cfg.ServiceSettings.DEPRECATED_DO_NOT_USE_RestrictCustomEmojiCreation,
   378  		"enable_testing":                                          cfg.ServiceSettings.EnableTesting,
   379  		"enable_developer":                                        *cfg.ServiceSettings.EnableDeveloper,
   380  		"enable_multifactor_authentication":                       *cfg.ServiceSettings.EnableMultifactorAuthentication,
   381  		"enforce_multifactor_authentication":                      *cfg.ServiceSettings.EnforceMultifactorAuthentication,
   382  		"enable_oauth_service_provider":                           cfg.ServiceSettings.EnableOAuthServiceProvider,
   383  		"connection_security":                                     *cfg.ServiceSettings.ConnectionSecurity,
   384  		"tls_strict_transport":                                    *cfg.ServiceSettings.TLSStrictTransport,
   385  		"uses_letsencrypt":                                        *cfg.ServiceSettings.UseLetsEncrypt,
   386  		"forward_80_to_443":                                       *cfg.ServiceSettings.Forward80To443,
   387  		"maximum_login_attempts":                                  *cfg.ServiceSettings.MaximumLoginAttempts,
   388  		"extend_session_length_with_activity":                     *cfg.ServiceSettings.ExtendSessionLengthWithActivity,
   389  		"session_length_web_in_days":                              *cfg.ServiceSettings.SessionLengthWebInDays,
   390  		"session_length_mobile_in_days":                           *cfg.ServiceSettings.SessionLengthMobileInDays,
   391  		"session_length_sso_in_days":                              *cfg.ServiceSettings.SessionLengthSSOInDays,
   392  		"session_cache_in_minutes":                                *cfg.ServiceSettings.SessionCacheInMinutes,
   393  		"session_idle_timeout_in_minutes":                         *cfg.ServiceSettings.SessionIdleTimeoutInMinutes,
   394  		"isdefault_site_url":                                      isDefault(*cfg.ServiceSettings.SiteURL, model.SERVICE_SETTINGS_DEFAULT_SITE_URL),
   395  		"isdefault_tls_cert_file":                                 isDefault(*cfg.ServiceSettings.TLSCertFile, model.SERVICE_SETTINGS_DEFAULT_TLS_CERT_FILE),
   396  		"isdefault_tls_key_file":                                  isDefault(*cfg.ServiceSettings.TLSKeyFile, model.SERVICE_SETTINGS_DEFAULT_TLS_KEY_FILE),
   397  		"isdefault_read_timeout":                                  isDefault(*cfg.ServiceSettings.ReadTimeout, model.SERVICE_SETTINGS_DEFAULT_READ_TIMEOUT),
   398  		"isdefault_write_timeout":                                 isDefault(*cfg.ServiceSettings.WriteTimeout, model.SERVICE_SETTINGS_DEFAULT_WRITE_TIMEOUT),
   399  		"isdefault_idle_timeout":                                  isDefault(*cfg.ServiceSettings.IdleTimeout, model.SERVICE_SETTINGS_DEFAULT_IDLE_TIMEOUT),
   400  		"isdefault_google_developer_key":                          isDefault(cfg.ServiceSettings.GoogleDeveloperKey, ""),
   401  		"isdefault_allow_cors_from":                               isDefault(*cfg.ServiceSettings.AllowCorsFrom, model.SERVICE_SETTINGS_DEFAULT_ALLOW_CORS_FROM),
   402  		"isdefault_cors_exposed_headers":                          isDefault(cfg.ServiceSettings.CorsExposedHeaders, ""),
   403  		"cors_allow_credentials":                                  *cfg.ServiceSettings.CorsAllowCredentials,
   404  		"cors_debug":                                              *cfg.ServiceSettings.CorsDebug,
   405  		"isdefault_allowed_untrusted_internal_connections":        isDefault(*cfg.ServiceSettings.AllowedUntrustedInternalConnections, ""),
   406  		"restrict_post_delete":                                    *cfg.ServiceSettings.DEPRECATED_DO_NOT_USE_RestrictPostDelete,
   407  		"allow_edit_post":                                         *cfg.ServiceSettings.DEPRECATED_DO_NOT_USE_AllowEditPost,
   408  		"post_edit_time_limit":                                    *cfg.ServiceSettings.PostEditTimeLimit,
   409  		"enable_user_typing_messages":                             *cfg.ServiceSettings.EnableUserTypingMessages,
   410  		"enable_channel_viewed_messages":                          *cfg.ServiceSettings.EnableChannelViewedMessages,
   411  		"time_between_user_typing_updates_milliseconds":           *cfg.ServiceSettings.TimeBetweenUserTypingUpdatesMilliseconds,
   412  		"cluster_log_timeout_milliseconds":                        *cfg.ServiceSettings.ClusterLogTimeoutMilliseconds,
   413  		"enable_post_search":                                      *cfg.ServiceSettings.EnablePostSearch,
   414  		"minimum_hashtag_length":                                  *cfg.ServiceSettings.MinimumHashtagLength,
   415  		"enable_user_statuses":                                    *cfg.ServiceSettings.EnableUserStatuses,
   416  		"close_unused_direct_messages":                            *cfg.ServiceSettings.CloseUnusedDirectMessages,
   417  		"enable_preview_features":                                 *cfg.ServiceSettings.EnablePreviewFeatures,
   418  		"enable_tutorial":                                         *cfg.ServiceSettings.EnableTutorial,
   419  		"experimental_enable_default_channel_leave_join_messages": *cfg.ServiceSettings.ExperimentalEnableDefaultChannelLeaveJoinMessages,
   420  		"experimental_group_unread_channels":                      *cfg.ServiceSettings.ExperimentalGroupUnreadChannels,
   421  		"collapsed_threads":                                       *cfg.ServiceSettings.CollapsedThreads,
   422  		"websocket_url":                                           isDefault(*cfg.ServiceSettings.WebsocketURL, ""),
   423  		"allow_cookies_for_subdomains":                            *cfg.ServiceSettings.AllowCookiesForSubdomains,
   424  		"enable_api_team_deletion":                                *cfg.ServiceSettings.EnableAPITeamDeletion,
   425  		"enable_api_user_deletion":                                *cfg.ServiceSettings.EnableAPIUserDeletion,
   426  		"enable_api_channel_deletion":                             *cfg.ServiceSettings.EnableAPIChannelDeletion,
   427  		"experimental_enable_hardened_mode":                       *cfg.ServiceSettings.ExperimentalEnableHardenedMode,
   428  		"disable_legacy_mfa":                                      *cfg.ServiceSettings.DisableLegacyMFA,
   429  		"experimental_strict_csrf_enforcement":                    *cfg.ServiceSettings.ExperimentalStrictCSRFEnforcement,
   430  		"enable_email_invitations":                                *cfg.ServiceSettings.EnableEmailInvitations,
   431  		"experimental_channel_organization":                       *cfg.ServiceSettings.ExperimentalChannelOrganization,
   432  		"disable_bots_when_owner_is_deactivated":                  *cfg.ServiceSettings.DisableBotsWhenOwnerIsDeactivated,
   433  		"enable_bot_account_creation":                             *cfg.ServiceSettings.EnableBotAccountCreation,
   434  		"enable_svgs":                                             *cfg.ServiceSettings.EnableSVGs,
   435  		"enable_latex":                                            *cfg.ServiceSettings.EnableLatex,
   436  		"enable_opentracing":                                      *cfg.ServiceSettings.EnableOpenTracing,
   437  		"enable_local_mode":                                       *cfg.ServiceSettings.EnableLocalMode,
   438  		"managed_resource_paths":                                  isDefault(*cfg.ServiceSettings.ManagedResourcePaths, ""),
   439  		"enable_legacy_sidebar":                                   *cfg.ServiceSettings.EnableLegacySidebar,
   440  		"thread_auto_follow":                                      *cfg.ServiceSettings.ThreadAutoFollow,
   441  		"enable_link_previews":                                    *cfg.ServiceSettings.EnableLinkPreviews,
   442  	})
   443  
   444  	ts.sendTelemetry(TrackConfigTeam, map[string]interface{}{
   445  		"enable_user_creation":                      cfg.TeamSettings.EnableUserCreation,
   446  		"enable_team_creation":                      *cfg.TeamSettings.DEPRECATED_DO_NOT_USE_EnableTeamCreation,
   447  		"restrict_team_invite":                      *cfg.TeamSettings.DEPRECATED_DO_NOT_USE_RestrictTeamInvite,
   448  		"restrict_public_channel_creation":          *cfg.TeamSettings.DEPRECATED_DO_NOT_USE_RestrictPublicChannelCreation,
   449  		"restrict_private_channel_creation":         *cfg.TeamSettings.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelCreation,
   450  		"restrict_public_channel_management":        *cfg.TeamSettings.DEPRECATED_DO_NOT_USE_RestrictPublicChannelManagement,
   451  		"restrict_private_channel_management":       *cfg.TeamSettings.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManagement,
   452  		"restrict_public_channel_deletion":          *cfg.TeamSettings.DEPRECATED_DO_NOT_USE_RestrictPublicChannelDeletion,
   453  		"restrict_private_channel_deletion":         *cfg.TeamSettings.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelDeletion,
   454  		"enable_open_server":                        *cfg.TeamSettings.EnableOpenServer,
   455  		"enable_user_deactivation":                  *cfg.TeamSettings.EnableUserDeactivation,
   456  		"enable_custom_user_statuses":               *cfg.TeamSettings.EnableCustomUserStatuses,
   457  		"enable_custom_brand":                       *cfg.TeamSettings.EnableCustomBrand,
   458  		"restrict_direct_message":                   *cfg.TeamSettings.RestrictDirectMessage,
   459  		"max_notifications_per_channel":             *cfg.TeamSettings.MaxNotificationsPerChannel,
   460  		"enable_confirm_notifications_to_channel":   *cfg.TeamSettings.EnableConfirmNotificationsToChannel,
   461  		"max_users_per_team":                        *cfg.TeamSettings.MaxUsersPerTeam,
   462  		"max_channels_per_team":                     *cfg.TeamSettings.MaxChannelsPerTeam,
   463  		"teammate_name_display":                     *cfg.TeamSettings.TeammateNameDisplay,
   464  		"experimental_view_archived_channels":       *cfg.TeamSettings.ExperimentalViewArchivedChannels,
   465  		"lock_teammate_name_display":                *cfg.TeamSettings.LockTeammateNameDisplay,
   466  		"isdefault_site_name":                       isDefault(cfg.TeamSettings.SiteName, "Mattermost"),
   467  		"isdefault_custom_brand_text":               isDefault(*cfg.TeamSettings.CustomBrandText, model.TEAM_SETTINGS_DEFAULT_CUSTOM_BRAND_TEXT),
   468  		"isdefault_custom_description_text":         isDefault(*cfg.TeamSettings.CustomDescriptionText, model.TEAM_SETTINGS_DEFAULT_CUSTOM_DESCRIPTION_TEXT),
   469  		"isdefault_user_status_away_timeout":        isDefault(*cfg.TeamSettings.UserStatusAwayTimeout, model.TEAM_SETTINGS_DEFAULT_USER_STATUS_AWAY_TIMEOUT),
   470  		"restrict_private_channel_manage_members":   *cfg.TeamSettings.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManageMembers,
   471  		"enable_X_to_leave_channels_from_LHS":       *cfg.TeamSettings.EnableXToLeaveChannelsFromLHS,
   472  		"experimental_enable_automatic_replies":     *cfg.TeamSettings.ExperimentalEnableAutomaticReplies,
   473  		"experimental_town_square_is_hidden_in_lhs": *cfg.TeamSettings.ExperimentalHideTownSquareinLHS,
   474  		"experimental_town_square_is_read_only":     *cfg.TeamSettings.ExperimentalTownSquareIsReadOnly,
   475  		"experimental_primary_team":                 isDefault(*cfg.TeamSettings.ExperimentalPrimaryTeam, ""),
   476  		"experimental_default_channels":             len(cfg.TeamSettings.ExperimentalDefaultChannels),
   477  	})
   478  
   479  	ts.sendTelemetry(TrackConfigClientReq, map[string]interface{}{
   480  		"android_latest_version": cfg.ClientRequirements.AndroidLatestVersion,
   481  		"android_min_version":    cfg.ClientRequirements.AndroidMinVersion,
   482  		"desktop_latest_version": cfg.ClientRequirements.DesktopLatestVersion,
   483  		"desktop_min_version":    cfg.ClientRequirements.DesktopMinVersion,
   484  		"ios_latest_version":     cfg.ClientRequirements.IosLatestVersion,
   485  		"ios_min_version":        cfg.ClientRequirements.IosMinVersion,
   486  	})
   487  
   488  	ts.sendTelemetry(TrackConfigSQL, map[string]interface{}{
   489  		"driver_name":                    *cfg.SqlSettings.DriverName,
   490  		"trace":                          cfg.SqlSettings.Trace,
   491  		"max_idle_conns":                 *cfg.SqlSettings.MaxIdleConns,
   492  		"conn_max_lifetime_milliseconds": *cfg.SqlSettings.ConnMaxLifetimeMilliseconds,
   493  		"conn_max_idletime_milliseconds": *cfg.SqlSettings.ConnMaxIdleTimeMilliseconds,
   494  		"max_open_conns":                 *cfg.SqlSettings.MaxOpenConns,
   495  		"data_source_replicas":           len(cfg.SqlSettings.DataSourceReplicas),
   496  		"data_source_search_replicas":    len(cfg.SqlSettings.DataSourceSearchReplicas),
   497  		"query_timeout":                  *cfg.SqlSettings.QueryTimeout,
   498  		"disable_database_search":        *cfg.SqlSettings.DisableDatabaseSearch,
   499  	})
   500  
   501  	ts.sendTelemetry(TrackConfigLog, map[string]interface{}{
   502  		"enable_console":           cfg.LogSettings.EnableConsole,
   503  		"console_level":            cfg.LogSettings.ConsoleLevel,
   504  		"console_json":             *cfg.LogSettings.ConsoleJson,
   505  		"enable_file":              cfg.LogSettings.EnableFile,
   506  		"file_level":               cfg.LogSettings.FileLevel,
   507  		"file_json":                cfg.LogSettings.FileJson,
   508  		"enable_webhook_debugging": cfg.LogSettings.EnableWebhookDebugging,
   509  		"isdefault_file_location":  isDefault(cfg.LogSettings.FileLocation, ""),
   510  		"advanced_logging_config":  *cfg.LogSettings.AdvancedLoggingConfig != "",
   511  	})
   512  
   513  	ts.sendTelemetry(TrackConfigAudit, map[string]interface{}{
   514  		"file_enabled":            *cfg.ExperimentalAuditSettings.FileEnabled,
   515  		"file_max_size_mb":        *cfg.ExperimentalAuditSettings.FileMaxSizeMB,
   516  		"file_max_age_days":       *cfg.ExperimentalAuditSettings.FileMaxAgeDays,
   517  		"file_max_backups":        *cfg.ExperimentalAuditSettings.FileMaxBackups,
   518  		"file_compress":           *cfg.ExperimentalAuditSettings.FileCompress,
   519  		"file_max_queue_size":     *cfg.ExperimentalAuditSettings.FileMaxQueueSize,
   520  		"advanced_logging_config": *cfg.ExperimentalAuditSettings.AdvancedLoggingConfig != "",
   521  	})
   522  
   523  	ts.sendTelemetry(TrackConfigNotificationLog, map[string]interface{}{
   524  		"enable_console":          *cfg.NotificationLogSettings.EnableConsole,
   525  		"console_level":           *cfg.NotificationLogSettings.ConsoleLevel,
   526  		"console_json":            *cfg.NotificationLogSettings.ConsoleJson,
   527  		"enable_file":             *cfg.NotificationLogSettings.EnableFile,
   528  		"file_level":              *cfg.NotificationLogSettings.FileLevel,
   529  		"file_json":               *cfg.NotificationLogSettings.FileJson,
   530  		"isdefault_file_location": isDefault(*cfg.NotificationLogSettings.FileLocation, ""),
   531  		"advanced_logging_config": *cfg.NotificationLogSettings.AdvancedLoggingConfig != "",
   532  	})
   533  
   534  	ts.sendTelemetry(TrackConfigPassword, map[string]interface{}{
   535  		"minimum_length": *cfg.PasswordSettings.MinimumLength,
   536  		"lowercase":      *cfg.PasswordSettings.Lowercase,
   537  		"number":         *cfg.PasswordSettings.Number,
   538  		"uppercase":      *cfg.PasswordSettings.Uppercase,
   539  		"symbol":         *cfg.PasswordSettings.Symbol,
   540  	})
   541  
   542  	ts.sendTelemetry(TrackConfigFile, map[string]interface{}{
   543  		"enable_public_links":     cfg.FileSettings.EnablePublicLink,
   544  		"driver_name":             *cfg.FileSettings.DriverName,
   545  		"isdefault_directory":     isDefault(*cfg.FileSettings.Directory, model.FILE_SETTINGS_DEFAULT_DIRECTORY),
   546  		"isabsolute_directory":    filepath.IsAbs(*cfg.FileSettings.Directory),
   547  		"amazon_s3_ssl":           *cfg.FileSettings.AmazonS3SSL,
   548  		"amazon_s3_sse":           *cfg.FileSettings.AmazonS3SSE,
   549  		"amazon_s3_signv2":        *cfg.FileSettings.AmazonS3SignV2,
   550  		"amazon_s3_trace":         *cfg.FileSettings.AmazonS3Trace,
   551  		"max_file_size":           *cfg.FileSettings.MaxFileSize,
   552  		"enable_file_attachments": *cfg.FileSettings.EnableFileAttachments,
   553  		"enable_mobile_upload":    *cfg.FileSettings.EnableMobileUpload,
   554  		"enable_mobile_download":  *cfg.FileSettings.EnableMobileDownload,
   555  	})
   556  
   557  	ts.sendTelemetry(TrackConfigEmail, map[string]interface{}{
   558  		"enable_sign_up_with_email":            cfg.EmailSettings.EnableSignUpWithEmail,
   559  		"enable_sign_in_with_email":            *cfg.EmailSettings.EnableSignInWithEmail,
   560  		"enable_sign_in_with_username":         *cfg.EmailSettings.EnableSignInWithUsername,
   561  		"require_email_verification":           cfg.EmailSettings.RequireEmailVerification,
   562  		"send_email_notifications":             cfg.EmailSettings.SendEmailNotifications,
   563  		"use_channel_in_email_notifications":   *cfg.EmailSettings.UseChannelInEmailNotifications,
   564  		"email_notification_contents_type":     *cfg.EmailSettings.EmailNotificationContentsType,
   565  		"enable_smtp_auth":                     *cfg.EmailSettings.EnableSMTPAuth,
   566  		"connection_security":                  cfg.EmailSettings.ConnectionSecurity,
   567  		"send_push_notifications":              *cfg.EmailSettings.SendPushNotifications,
   568  		"push_notification_contents":           *cfg.EmailSettings.PushNotificationContents,
   569  		"enable_email_batching":                *cfg.EmailSettings.EnableEmailBatching,
   570  		"email_batching_buffer_size":           *cfg.EmailSettings.EmailBatchingBufferSize,
   571  		"email_batching_interval":              *cfg.EmailSettings.EmailBatchingInterval,
   572  		"enable_preview_mode_banner":           *cfg.EmailSettings.EnablePreviewModeBanner,
   573  		"isdefault_feedback_name":              isDefault(cfg.EmailSettings.FeedbackName, ""),
   574  		"isdefault_feedback_email":             isDefault(cfg.EmailSettings.FeedbackEmail, ""),
   575  		"isdefault_reply_to_address":           isDefault(cfg.EmailSettings.ReplyToAddress, ""),
   576  		"isdefault_feedback_organization":      isDefault(*cfg.EmailSettings.FeedbackOrganization, model.EMAIL_SETTINGS_DEFAULT_FEEDBACK_ORGANIZATION),
   577  		"skip_server_certificate_verification": *cfg.EmailSettings.SkipServerCertificateVerification,
   578  		"isdefault_login_button_color":         isDefault(*cfg.EmailSettings.LoginButtonColor, ""),
   579  		"isdefault_login_button_border_color":  isDefault(*cfg.EmailSettings.LoginButtonBorderColor, ""),
   580  		"isdefault_login_button_text_color":    isDefault(*cfg.EmailSettings.LoginButtonTextColor, ""),
   581  		"smtp_server_timeout":                  *cfg.EmailSettings.SMTPServerTimeout,
   582  	})
   583  
   584  	ts.sendTelemetry(TrackConfigRate, map[string]interface{}{
   585  		"enable_rate_limiter":      *cfg.RateLimitSettings.Enable,
   586  		"vary_by_remote_address":   *cfg.RateLimitSettings.VaryByRemoteAddr,
   587  		"vary_by_user":             *cfg.RateLimitSettings.VaryByUser,
   588  		"per_sec":                  *cfg.RateLimitSettings.PerSec,
   589  		"max_burst":                *cfg.RateLimitSettings.MaxBurst,
   590  		"memory_store_size":        *cfg.RateLimitSettings.MemoryStoreSize,
   591  		"isdefault_vary_by_header": isDefault(cfg.RateLimitSettings.VaryByHeader, ""),
   592  	})
   593  
   594  	ts.sendTelemetry(TrackConfigPrivacy, map[string]interface{}{
   595  		"show_email_address": cfg.PrivacySettings.ShowEmailAddress,
   596  		"show_full_name":     cfg.PrivacySettings.ShowFullName,
   597  	})
   598  
   599  	ts.sendTelemetry(TrackConfigTheme, map[string]interface{}{
   600  		"enable_theme_selection":  *cfg.ThemeSettings.EnableThemeSelection,
   601  		"isdefault_default_theme": isDefault(*cfg.ThemeSettings.DefaultTheme, model.TEAM_SETTINGS_DEFAULT_TEAM_TEXT),
   602  		"allow_custom_themes":     *cfg.ThemeSettings.AllowCustomThemes,
   603  		"allowed_themes":          len(cfg.ThemeSettings.AllowedThemes),
   604  	})
   605  
   606  	ts.sendTelemetry(TrackConfigOauth, map[string]interface{}{
   607  		"enable_gitlab":    cfg.GitLabSettings.Enable,
   608  		"openid_gitlab":    *cfg.GitLabSettings.Enable && strings.Contains(*cfg.GitLabSettings.Scope, model.SERVICE_OPENID),
   609  		"enable_google":    cfg.GoogleSettings.Enable,
   610  		"openid_google":    *cfg.GoogleSettings.Enable && strings.Contains(*cfg.GoogleSettings.Scope, model.SERVICE_OPENID),
   611  		"enable_office365": cfg.Office365Settings.Enable,
   612  		"openid_office365": *cfg.Office365Settings.Enable && strings.Contains(*cfg.Office365Settings.Scope, model.SERVICE_OPENID),
   613  		"enable_openid":    cfg.OpenIdSettings.Enable,
   614  	})
   615  
   616  	ts.sendTelemetry(TrackConfigSupport, map[string]interface{}{
   617  		"isdefault_terms_of_service_link":              isDefault(*cfg.SupportSettings.TermsOfServiceLink, model.SUPPORT_SETTINGS_DEFAULT_TERMS_OF_SERVICE_LINK),
   618  		"isdefault_privacy_policy_link":                isDefault(*cfg.SupportSettings.PrivacyPolicyLink, model.SUPPORT_SETTINGS_DEFAULT_PRIVACY_POLICY_LINK),
   619  		"isdefault_about_link":                         isDefault(*cfg.SupportSettings.AboutLink, model.SUPPORT_SETTINGS_DEFAULT_ABOUT_LINK),
   620  		"isdefault_help_link":                          isDefault(*cfg.SupportSettings.HelpLink, model.SUPPORT_SETTINGS_DEFAULT_HELP_LINK),
   621  		"isdefault_report_a_problem_link":              isDefault(*cfg.SupportSettings.ReportAProblemLink, model.SUPPORT_SETTINGS_DEFAULT_REPORT_A_PROBLEM_LINK),
   622  		"isdefault_support_email":                      isDefault(*cfg.SupportSettings.SupportEmail, model.SUPPORT_SETTINGS_DEFAULT_SUPPORT_EMAIL),
   623  		"custom_terms_of_service_enabled":              *cfg.SupportSettings.CustomTermsOfServiceEnabled,
   624  		"custom_terms_of_service_re_acceptance_period": *cfg.SupportSettings.CustomTermsOfServiceReAcceptancePeriod,
   625  		"enable_ask_community_link":                    *cfg.SupportSettings.EnableAskCommunityLink,
   626  	})
   627  
   628  	ts.sendTelemetry(TrackConfigLDAP, map[string]interface{}{
   629  		"enable":                                 *cfg.LdapSettings.Enable,
   630  		"enable_sync":                            *cfg.LdapSettings.EnableSync,
   631  		"enable_admin_filter":                    *cfg.LdapSettings.EnableAdminFilter,
   632  		"connection_security":                    *cfg.LdapSettings.ConnectionSecurity,
   633  		"skip_certificate_verification":          *cfg.LdapSettings.SkipCertificateVerification,
   634  		"sync_interval_minutes":                  *cfg.LdapSettings.SyncIntervalMinutes,
   635  		"query_timeout":                          *cfg.LdapSettings.QueryTimeout,
   636  		"max_page_size":                          *cfg.LdapSettings.MaxPageSize,
   637  		"isdefault_first_name_attribute":         isDefault(*cfg.LdapSettings.FirstNameAttribute, model.LDAP_SETTINGS_DEFAULT_FIRST_NAME_ATTRIBUTE),
   638  		"isdefault_last_name_attribute":          isDefault(*cfg.LdapSettings.LastNameAttribute, model.LDAP_SETTINGS_DEFAULT_LAST_NAME_ATTRIBUTE),
   639  		"isdefault_email_attribute":              isDefault(*cfg.LdapSettings.EmailAttribute, model.LDAP_SETTINGS_DEFAULT_EMAIL_ATTRIBUTE),
   640  		"isdefault_username_attribute":           isDefault(*cfg.LdapSettings.UsernameAttribute, model.LDAP_SETTINGS_DEFAULT_USERNAME_ATTRIBUTE),
   641  		"isdefault_nickname_attribute":           isDefault(*cfg.LdapSettings.NicknameAttribute, model.LDAP_SETTINGS_DEFAULT_NICKNAME_ATTRIBUTE),
   642  		"isdefault_id_attribute":                 isDefault(*cfg.LdapSettings.IdAttribute, model.LDAP_SETTINGS_DEFAULT_ID_ATTRIBUTE),
   643  		"isdefault_position_attribute":           isDefault(*cfg.LdapSettings.PositionAttribute, model.LDAP_SETTINGS_DEFAULT_POSITION_ATTRIBUTE),
   644  		"isdefault_login_id_attribute":           isDefault(*cfg.LdapSettings.LoginIdAttribute, ""),
   645  		"isdefault_login_field_name":             isDefault(*cfg.LdapSettings.LoginFieldName, model.LDAP_SETTINGS_DEFAULT_LOGIN_FIELD_NAME),
   646  		"isdefault_login_button_color":           isDefault(*cfg.LdapSettings.LoginButtonColor, ""),
   647  		"isdefault_login_button_border_color":    isDefault(*cfg.LdapSettings.LoginButtonBorderColor, ""),
   648  		"isdefault_login_button_text_color":      isDefault(*cfg.LdapSettings.LoginButtonTextColor, ""),
   649  		"isempty_group_filter":                   isDefault(*cfg.LdapSettings.GroupFilter, ""),
   650  		"isdefault_group_display_name_attribute": isDefault(*cfg.LdapSettings.GroupDisplayNameAttribute, model.LDAP_SETTINGS_DEFAULT_GROUP_DISPLAY_NAME_ATTRIBUTE),
   651  		"isdefault_group_id_attribute":           isDefault(*cfg.LdapSettings.GroupIdAttribute, model.LDAP_SETTINGS_DEFAULT_GROUP_ID_ATTRIBUTE),
   652  		"isempty_guest_filter":                   isDefault(*cfg.LdapSettings.GuestFilter, ""),
   653  		"isempty_admin_filter":                   isDefault(*cfg.LdapSettings.AdminFilter, ""),
   654  		"isnotempty_picture_attribute":           !isDefault(*cfg.LdapSettings.PictureAttribute, ""),
   655  		"isnotempty_public_certificate":          !isDefault(*cfg.LdapSettings.PublicCertificateFile, ""),
   656  		"isnotempty_private_key":                 !isDefault(*cfg.LdapSettings.PrivateKeyFile, ""),
   657  	})
   658  
   659  	ts.sendTelemetry(TrackConfigCompliance, map[string]interface{}{
   660  		"enable":       *cfg.ComplianceSettings.Enable,
   661  		"enable_daily": *cfg.ComplianceSettings.EnableDaily,
   662  	})
   663  
   664  	ts.sendTelemetry(TrackConfigLocalization, map[string]interface{}{
   665  		"default_server_locale": *cfg.LocalizationSettings.DefaultServerLocale,
   666  		"default_client_locale": *cfg.LocalizationSettings.DefaultClientLocale,
   667  		"available_locales":     *cfg.LocalizationSettings.AvailableLocales,
   668  	})
   669  
   670  	ts.sendTelemetry(TrackConfigSAML, map[string]interface{}{
   671  		"enable":                              *cfg.SamlSettings.Enable,
   672  		"enable_sync_with_ldap":               *cfg.SamlSettings.EnableSyncWithLdap,
   673  		"enable_sync_with_ldap_include_auth":  *cfg.SamlSettings.EnableSyncWithLdapIncludeAuth,
   674  		"ignore_guests_ldap_sync":             *cfg.SamlSettings.IgnoreGuestsLdapSync,
   675  		"enable_admin_attribute":              *cfg.SamlSettings.EnableAdminAttribute,
   676  		"verify":                              *cfg.SamlSettings.Verify,
   677  		"encrypt":                             *cfg.SamlSettings.Encrypt,
   678  		"sign_request":                        *cfg.SamlSettings.SignRequest,
   679  		"isdefault_signature_algorithm":       isDefault(*cfg.SamlSettings.SignatureAlgorithm, ""),
   680  		"isdefault_canonical_algorithm":       isDefault(*cfg.SamlSettings.CanonicalAlgorithm, ""),
   681  		"isdefault_scoping_idp_provider_id":   isDefault(*cfg.SamlSettings.ScopingIDPProviderId, ""),
   682  		"isdefault_scoping_idp_name":          isDefault(*cfg.SamlSettings.ScopingIDPName, ""),
   683  		"isdefault_id_attribute":              isDefault(*cfg.SamlSettings.IdAttribute, model.SAML_SETTINGS_DEFAULT_ID_ATTRIBUTE),
   684  		"isdefault_guest_attribute":           isDefault(*cfg.SamlSettings.GuestAttribute, model.SAML_SETTINGS_DEFAULT_GUEST_ATTRIBUTE),
   685  		"isdefault_admin_attribute":           isDefault(*cfg.SamlSettings.AdminAttribute, model.SAML_SETTINGS_DEFAULT_ADMIN_ATTRIBUTE),
   686  		"isdefault_first_name_attribute":      isDefault(*cfg.SamlSettings.FirstNameAttribute, model.SAML_SETTINGS_DEFAULT_FIRST_NAME_ATTRIBUTE),
   687  		"isdefault_last_name_attribute":       isDefault(*cfg.SamlSettings.LastNameAttribute, model.SAML_SETTINGS_DEFAULT_LAST_NAME_ATTRIBUTE),
   688  		"isdefault_email_attribute":           isDefault(*cfg.SamlSettings.EmailAttribute, model.SAML_SETTINGS_DEFAULT_EMAIL_ATTRIBUTE),
   689  		"isdefault_username_attribute":        isDefault(*cfg.SamlSettings.UsernameAttribute, model.SAML_SETTINGS_DEFAULT_USERNAME_ATTRIBUTE),
   690  		"isdefault_nickname_attribute":        isDefault(*cfg.SamlSettings.NicknameAttribute, model.SAML_SETTINGS_DEFAULT_NICKNAME_ATTRIBUTE),
   691  		"isdefault_locale_attribute":          isDefault(*cfg.SamlSettings.LocaleAttribute, model.SAML_SETTINGS_DEFAULT_LOCALE_ATTRIBUTE),
   692  		"isdefault_position_attribute":        isDefault(*cfg.SamlSettings.PositionAttribute, model.SAML_SETTINGS_DEFAULT_POSITION_ATTRIBUTE),
   693  		"isdefault_login_button_text":         isDefault(*cfg.SamlSettings.LoginButtonText, model.USER_AUTH_SERVICE_SAML_TEXT),
   694  		"isdefault_login_button_color":        isDefault(*cfg.SamlSettings.LoginButtonColor, ""),
   695  		"isdefault_login_button_border_color": isDefault(*cfg.SamlSettings.LoginButtonBorderColor, ""),
   696  		"isdefault_login_button_text_color":   isDefault(*cfg.SamlSettings.LoginButtonTextColor, ""),
   697  	})
   698  
   699  	ts.sendTelemetry(TrackConfigCluster, map[string]interface{}{
   700  		"enable":                                *cfg.ClusterSettings.Enable,
   701  		"network_interface":                     isDefault(*cfg.ClusterSettings.NetworkInterface, ""),
   702  		"bind_address":                          isDefault(*cfg.ClusterSettings.BindAddress, ""),
   703  		"advertise_address":                     isDefault(*cfg.ClusterSettings.AdvertiseAddress, ""),
   704  		"use_ip_address":                        *cfg.ClusterSettings.UseIpAddress,
   705  		"use_experimental_gossip":               *cfg.ClusterSettings.UseExperimentalGossip,
   706  		"enable_experimental_gossip_encryption": *cfg.ClusterSettings.EnableExperimentalGossipEncryption,
   707  		"enable_gossip_compression":             *cfg.ClusterSettings.EnableGossipCompression,
   708  		"read_only_config":                      *cfg.ClusterSettings.ReadOnlyConfig,
   709  	})
   710  
   711  	ts.sendTelemetry(TrackConfigMetrics, map[string]interface{}{
   712  		"enable":             *cfg.MetricsSettings.Enable,
   713  		"block_profile_rate": *cfg.MetricsSettings.BlockProfileRate,
   714  	})
   715  
   716  	ts.sendTelemetry(TrackConfigNativeApp, map[string]interface{}{
   717  		"isdefault_app_custom_url_schemes":    isDefaultArray(cfg.NativeAppSettings.AppCustomURLSchemes, model.GetDefaultAppCustomURLSchemes()),
   718  		"isdefault_app_download_link":         isDefault(*cfg.NativeAppSettings.AppDownloadLink, model.NATIVEAPP_SETTINGS_DEFAULT_APP_DOWNLOAD_LINK),
   719  		"isdefault_android_app_download_link": isDefault(*cfg.NativeAppSettings.AndroidAppDownloadLink, model.NATIVEAPP_SETTINGS_DEFAULT_ANDROID_APP_DOWNLOAD_LINK),
   720  		"isdefault_iosapp_download_link":      isDefault(*cfg.NativeAppSettings.IosAppDownloadLink, model.NATIVEAPP_SETTINGS_DEFAULT_IOS_APP_DOWNLOAD_LINK),
   721  	})
   722  
   723  	ts.sendTelemetry(TrackConfigExperimental, map[string]interface{}{
   724  		"client_side_cert_enable":            *cfg.ExperimentalSettings.ClientSideCertEnable,
   725  		"isdefault_client_side_cert_check":   isDefault(*cfg.ExperimentalSettings.ClientSideCertCheck, model.CLIENT_SIDE_CERT_CHECK_PRIMARY_AUTH),
   726  		"link_metadata_timeout_milliseconds": *cfg.ExperimentalSettings.LinkMetadataTimeoutMilliseconds,
   727  		"enable_click_to_reply":              *cfg.ExperimentalSettings.EnableClickToReply,
   728  		"restrict_system_admin":              *cfg.ExperimentalSettings.RestrictSystemAdmin,
   729  		"use_new_saml_library":               *cfg.ExperimentalSettings.UseNewSAMLLibrary,
   730  		"cloud_billing":                      *cfg.ExperimentalSettings.CloudBilling,
   731  		"cloud_user_limit":                   *cfg.ExperimentalSettings.CloudUserLimit,
   732  		"enable_shared_channels":             *cfg.ExperimentalSettings.EnableSharedChannels,
   733  	})
   734  
   735  	ts.sendTelemetry(TrackConfigAnalytics, map[string]interface{}{
   736  		"isdefault_max_users_for_statistics": isDefault(*cfg.AnalyticsSettings.MaxUsersForStatistics, model.ANALYTICS_SETTINGS_DEFAULT_MAX_USERS_FOR_STATISTICS),
   737  	})
   738  
   739  	ts.sendTelemetry(TrackConfigAnnouncement, map[string]interface{}{
   740  		"enable_banner":               *cfg.AnnouncementSettings.EnableBanner,
   741  		"isdefault_banner_color":      isDefault(*cfg.AnnouncementSettings.BannerColor, model.ANNOUNCEMENT_SETTINGS_DEFAULT_BANNER_COLOR),
   742  		"isdefault_banner_text_color": isDefault(*cfg.AnnouncementSettings.BannerTextColor, model.ANNOUNCEMENT_SETTINGS_DEFAULT_BANNER_TEXT_COLOR),
   743  		"allow_banner_dismissal":      *cfg.AnnouncementSettings.AllowBannerDismissal,
   744  		"admin_notices_enabled":       *cfg.AnnouncementSettings.AdminNoticesEnabled,
   745  		"user_notices_enabled":        *cfg.AnnouncementSettings.UserNoticesEnabled,
   746  	})
   747  
   748  	ts.sendTelemetry(TrackConfigElasticsearch, map[string]interface{}{
   749  		"isdefault_connection_url":          isDefault(*cfg.ElasticsearchSettings.ConnectionUrl, model.ELASTICSEARCH_SETTINGS_DEFAULT_CONNECTION_URL),
   750  		"isdefault_username":                isDefault(*cfg.ElasticsearchSettings.Username, model.ELASTICSEARCH_SETTINGS_DEFAULT_USERNAME),
   751  		"isdefault_password":                isDefault(*cfg.ElasticsearchSettings.Password, model.ELASTICSEARCH_SETTINGS_DEFAULT_PASSWORD),
   752  		"enable_indexing":                   *cfg.ElasticsearchSettings.EnableIndexing,
   753  		"enable_searching":                  *cfg.ElasticsearchSettings.EnableSearching,
   754  		"enable_autocomplete":               *cfg.ElasticsearchSettings.EnableAutocomplete,
   755  		"sniff":                             *cfg.ElasticsearchSettings.Sniff,
   756  		"post_index_replicas":               *cfg.ElasticsearchSettings.PostIndexReplicas,
   757  		"post_index_shards":                 *cfg.ElasticsearchSettings.PostIndexShards,
   758  		"channel_index_replicas":            *cfg.ElasticsearchSettings.ChannelIndexReplicas,
   759  		"channel_index_shards":              *cfg.ElasticsearchSettings.ChannelIndexShards,
   760  		"user_index_replicas":               *cfg.ElasticsearchSettings.UserIndexReplicas,
   761  		"user_index_shards":                 *cfg.ElasticsearchSettings.UserIndexShards,
   762  		"isdefault_index_prefix":            isDefault(*cfg.ElasticsearchSettings.IndexPrefix, model.ELASTICSEARCH_SETTINGS_DEFAULT_INDEX_PREFIX),
   763  		"live_indexing_batch_size":          *cfg.ElasticsearchSettings.LiveIndexingBatchSize,
   764  		"bulk_indexing_time_window_seconds": *cfg.ElasticsearchSettings.BulkIndexingTimeWindowSeconds,
   765  		"request_timeout_seconds":           *cfg.ElasticsearchSettings.RequestTimeoutSeconds,
   766  		"skip_tls_verification":             *cfg.ElasticsearchSettings.SkipTLSVerification,
   767  		"trace":                             *cfg.ElasticsearchSettings.Trace,
   768  	})
   769  
   770  	ts.trackPluginConfig(cfg, model.PLUGIN_SETTINGS_DEFAULT_MARKETPLACE_URL)
   771  
   772  	ts.sendTelemetry(TrackConfigDataRetention, map[string]interface{}{
   773  		"enable_message_deletion": *cfg.DataRetentionSettings.EnableMessageDeletion,
   774  		"enable_file_deletion":    *cfg.DataRetentionSettings.EnableFileDeletion,
   775  		"message_retention_days":  *cfg.DataRetentionSettings.MessageRetentionDays,
   776  		"file_retention_days":     *cfg.DataRetentionSettings.FileRetentionDays,
   777  		"deletion_job_start_time": *cfg.DataRetentionSettings.DeletionJobStartTime,
   778  	})
   779  
   780  	ts.sendTelemetry(TrackConfigMessageExport, map[string]interface{}{
   781  		"enable_message_export":                 *cfg.MessageExportSettings.EnableExport,
   782  		"export_format":                         *cfg.MessageExportSettings.ExportFormat,
   783  		"daily_run_time":                        *cfg.MessageExportSettings.DailyRunTime,
   784  		"default_export_from_timestamp":         *cfg.MessageExportSettings.ExportFromTimestamp,
   785  		"batch_size":                            *cfg.MessageExportSettings.BatchSize,
   786  		"global_relay_customer_type":            *cfg.MessageExportSettings.GlobalRelaySettings.CustomerType,
   787  		"is_default_global_relay_smtp_username": isDefault(*cfg.MessageExportSettings.GlobalRelaySettings.SmtpUsername, ""),
   788  		"is_default_global_relay_smtp_password": isDefault(*cfg.MessageExportSettings.GlobalRelaySettings.SmtpPassword, ""),
   789  		"is_default_global_relay_email_address": isDefault(*cfg.MessageExportSettings.GlobalRelaySettings.EmailAddress, ""),
   790  		"global_relay_smtp_server_timeout":      *cfg.MessageExportSettings.GlobalRelaySettings.SMTPServerTimeout,
   791  		"download_export_results":               *cfg.MessageExportSettings.DownloadExportResults,
   792  	})
   793  
   794  	ts.sendTelemetry(TrackConfigDisplay, map[string]interface{}{
   795  		"experimental_timezone":        *cfg.DisplaySettings.ExperimentalTimezone,
   796  		"isdefault_custom_url_schemes": len(cfg.DisplaySettings.CustomUrlSchemes) != 0,
   797  	})
   798  
   799  	ts.sendTelemetry(TrackConfigGuestAccounts, map[string]interface{}{
   800  		"enable":                                 *cfg.GuestAccountsSettings.Enable,
   801  		"allow_email_accounts":                   *cfg.GuestAccountsSettings.AllowEmailAccounts,
   802  		"enforce_multifactor_authentication":     *cfg.GuestAccountsSettings.EnforceMultifactorAuthentication,
   803  		"isdefault_restrict_creation_to_domains": isDefault(*cfg.GuestAccountsSettings.RestrictCreationToDomains, ""),
   804  	})
   805  
   806  	ts.sendTelemetry(TrackConfigImageProxy, map[string]interface{}{
   807  		"enable":                               *cfg.ImageProxySettings.Enable,
   808  		"image_proxy_type":                     *cfg.ImageProxySettings.ImageProxyType,
   809  		"isdefault_remote_image_proxy_url":     isDefault(*cfg.ImageProxySettings.RemoteImageProxyURL, ""),
   810  		"isdefault_remote_image_proxy_options": isDefault(*cfg.ImageProxySettings.RemoteImageProxyOptions, ""),
   811  	})
   812  
   813  	ts.sendTelemetry(TrackConfigBleve, map[string]interface{}{
   814  		"enable_indexing":                   *cfg.BleveSettings.EnableIndexing,
   815  		"enable_searching":                  *cfg.BleveSettings.EnableSearching,
   816  		"enable_autocomplete":               *cfg.BleveSettings.EnableAutocomplete,
   817  		"bulk_indexing_time_window_seconds": *cfg.BleveSettings.BulkIndexingTimeWindowSeconds,
   818  	})
   819  
   820  	ts.sendTelemetry(TrackConfigExport, map[string]interface{}{
   821  		"retention_days": *cfg.ExportSettings.RetentionDays,
   822  	})
   823  }
   824  
   825  func (ts *TelemetryService) trackLicense() {
   826  	if license := ts.srv.License(); license != nil {
   827  		data := map[string]interface{}{
   828  			"customer_id": license.Customer.Id,
   829  			"license_id":  license.Id,
   830  			"issued":      license.IssuedAt,
   831  			"start":       license.StartsAt,
   832  			"expire":      license.ExpiresAt,
   833  			"users":       *license.Features.Users,
   834  			"edition":     license.SkuShortName,
   835  		}
   836  
   837  		features := license.Features.ToMap()
   838  		for featureName, featureValue := range features {
   839  			data["feature_"+featureName] = featureValue
   840  		}
   841  
   842  		ts.sendTelemetry(TrackLicense, data)
   843  	}
   844  }
   845  
   846  func (ts *TelemetryService) trackPlugins() {
   847  	pluginsEnvironment := ts.srv.GetPluginsEnvironment()
   848  	if pluginsEnvironment == nil {
   849  		return
   850  	}
   851  
   852  	totalEnabledCount := 0
   853  	webappEnabledCount := 0
   854  	backendEnabledCount := 0
   855  	totalDisabledCount := 0
   856  	webappDisabledCount := 0
   857  	backendDisabledCount := 0
   858  	brokenManifestCount := 0
   859  	settingsCount := 0
   860  
   861  	pluginStates := ts.srv.Config().PluginSettings.PluginStates
   862  	plugins, _ := pluginsEnvironment.Available()
   863  
   864  	if pluginStates != nil && plugins != nil {
   865  		for _, plugin := range plugins {
   866  			if plugin.Manifest == nil {
   867  				brokenManifestCount += 1
   868  				continue
   869  			}
   870  
   871  			if state, ok := pluginStates[plugin.Manifest.Id]; ok && state.Enable {
   872  				totalEnabledCount += 1
   873  				if plugin.Manifest.HasServer() {
   874  					backendEnabledCount += 1
   875  				}
   876  				if plugin.Manifest.HasWebapp() {
   877  					webappEnabledCount += 1
   878  				}
   879  			} else {
   880  				totalDisabledCount += 1
   881  				if plugin.Manifest.HasServer() {
   882  					backendDisabledCount += 1
   883  				}
   884  				if plugin.Manifest.HasWebapp() {
   885  					webappDisabledCount += 1
   886  				}
   887  			}
   888  			if plugin.Manifest.SettingsSchema != nil {
   889  				settingsCount += 1
   890  			}
   891  		}
   892  	} else {
   893  		totalEnabledCount = -1  // -1 to indicate disabled or error
   894  		totalDisabledCount = -1 // -1 to indicate disabled or error
   895  	}
   896  
   897  	ts.sendTelemetry(TrackPlugins, map[string]interface{}{
   898  		"enabled_plugins":               totalEnabledCount,
   899  		"enabled_webapp_plugins":        webappEnabledCount,
   900  		"enabled_backend_plugins":       backendEnabledCount,
   901  		"disabled_plugins":              totalDisabledCount,
   902  		"disabled_webapp_plugins":       webappDisabledCount,
   903  		"disabled_backend_plugins":      backendDisabledCount,
   904  		"plugins_with_settings":         settingsCount,
   905  		"plugins_with_broken_manifests": brokenManifestCount,
   906  	})
   907  }
   908  
   909  func (ts *TelemetryService) trackServer() {
   910  	data := map[string]interface{}{
   911  		"edition":           model.BuildEnterpriseReady,
   912  		"version":           model.CurrentVersion,
   913  		"database_type":     *ts.srv.Config().SqlSettings.DriverName,
   914  		"operating_system":  runtime.GOOS,
   915  		"installation_type": os.Getenv(EnvVarInstallType),
   916  	}
   917  
   918  	if scr, err := ts.dbStore.User().AnalyticsGetSystemAdminCount(); err == nil {
   919  		data["system_admins"] = scr
   920  	}
   921  
   922  	if scr, err := ts.dbStore.GetDbVersion(false); err == nil {
   923  		data["database_version"] = scr
   924  	}
   925  
   926  	ts.sendTelemetry(TrackServer, data)
   927  }
   928  
   929  func (ts *TelemetryService) trackPermissions() {
   930  	phase1Complete := false
   931  	if _, err := ts.dbStore.System().GetByName(model.ADVANCED_PERMISSIONS_MIGRATION_KEY); err == nil {
   932  		phase1Complete = true
   933  	}
   934  
   935  	phase2Complete := false
   936  	if _, err := ts.dbStore.System().GetByName(model.MIGRATION_KEY_ADVANCED_PERMISSIONS_PHASE_2); err == nil {
   937  		phase2Complete = true
   938  	}
   939  
   940  	ts.sendTelemetry(TrackPermissionsGeneral, map[string]interface{}{
   941  		"phase_1_migration_complete": phase1Complete,
   942  		"phase_2_migration_complete": phase2Complete,
   943  	})
   944  
   945  	systemAdminPermissions := ""
   946  	if role, err := ts.srv.GetRoleByName(model.SYSTEM_ADMIN_ROLE_ID); err == nil {
   947  		systemAdminPermissions = strings.Join(role.Permissions, " ")
   948  	}
   949  
   950  	systemUserPermissions := ""
   951  	if role, err := ts.srv.GetRoleByName(model.SYSTEM_USER_ROLE_ID); err == nil {
   952  		systemUserPermissions = strings.Join(role.Permissions, " ")
   953  	}
   954  
   955  	teamAdminPermissions := ""
   956  	if role, err := ts.srv.GetRoleByName(model.TEAM_ADMIN_ROLE_ID); err == nil {
   957  		teamAdminPermissions = strings.Join(role.Permissions, " ")
   958  	}
   959  
   960  	teamUserPermissions := ""
   961  	if role, err := ts.srv.GetRoleByName(model.TEAM_USER_ROLE_ID); err == nil {
   962  		teamUserPermissions = strings.Join(role.Permissions, " ")
   963  	}
   964  
   965  	teamGuestPermissions := ""
   966  	if role, err := ts.srv.GetRoleByName(model.TEAM_GUEST_ROLE_ID); err == nil {
   967  		teamGuestPermissions = strings.Join(role.Permissions, " ")
   968  	}
   969  
   970  	channelAdminPermissions := ""
   971  	if role, err := ts.srv.GetRoleByName(model.CHANNEL_ADMIN_ROLE_ID); err == nil {
   972  		channelAdminPermissions = strings.Join(role.Permissions, " ")
   973  	}
   974  
   975  	channelUserPermissions := ""
   976  	if role, err := ts.srv.GetRoleByName(model.CHANNEL_USER_ROLE_ID); err == nil {
   977  		channelUserPermissions = strings.Join(role.Permissions, " ")
   978  	}
   979  
   980  	channelGuestPermissions := ""
   981  	if role, err := ts.srv.GetRoleByName(model.CHANNEL_GUEST_ROLE_ID); err == nil {
   982  		channelGuestPermissions = strings.Join(role.Permissions, " ")
   983  	}
   984  
   985  	systemManagerPermissions := ""
   986  	systemManagerPermissionsModified := false
   987  	if role, err := ts.srv.GetRoleByName(model.SYSTEM_MANAGER_ROLE_ID); err == nil {
   988  		systemManagerPermissionsModified = len(model.PermissionsChangedByPatch(role, &model.RolePatch{Permissions: &model.SystemManagerDefaultPermissions})) > 0
   989  		systemManagerPermissions = strings.Join(role.Permissions, " ")
   990  	}
   991  	systemManagerCount, countErr := ts.dbStore.User().Count(model.UserCountOptions{Roles: []string{model.SYSTEM_MANAGER_ROLE_ID}})
   992  	if countErr != nil {
   993  		systemManagerCount = 0
   994  	}
   995  
   996  	systemUserManagerPermissions := ""
   997  	systemUserManagerPermissionsModified := false
   998  	if role, err := ts.srv.GetRoleByName(model.SYSTEM_USER_MANAGER_ROLE_ID); err == nil {
   999  		systemUserManagerPermissionsModified = len(model.PermissionsChangedByPatch(role, &model.RolePatch{Permissions: &model.SystemUserManagerDefaultPermissions})) > 0
  1000  		systemUserManagerPermissions = strings.Join(role.Permissions, " ")
  1001  	}
  1002  	systemUserManagerCount, countErr := ts.dbStore.User().Count(model.UserCountOptions{Roles: []string{model.SYSTEM_USER_MANAGER_ROLE_ID}})
  1003  	if countErr != nil {
  1004  		systemManagerCount = 0
  1005  	}
  1006  
  1007  	systemReadOnlyAdminPermissions := ""
  1008  	systemReadOnlyAdminPermissionsModified := false
  1009  	if role, err := ts.srv.GetRoleByName(model.SYSTEM_READ_ONLY_ADMIN_ROLE_ID); err == nil {
  1010  		systemReadOnlyAdminPermissionsModified = len(model.PermissionsChangedByPatch(role, &model.RolePatch{Permissions: &model.SystemReadOnlyAdminDefaultPermissions})) > 0
  1011  		systemReadOnlyAdminPermissions = strings.Join(role.Permissions, " ")
  1012  	}
  1013  	systemReadOnlyAdminCount, countErr := ts.dbStore.User().Count(model.UserCountOptions{Roles: []string{model.SYSTEM_READ_ONLY_ADMIN_ROLE_ID}})
  1014  	if countErr != nil {
  1015  		systemReadOnlyAdminCount = 0
  1016  	}
  1017  
  1018  	ts.sendTelemetry(TrackPermissionsSystemScheme, map[string]interface{}{
  1019  		"system_admin_permissions":                    systemAdminPermissions,
  1020  		"system_user_permissions":                     systemUserPermissions,
  1021  		"system_manager_permissions":                  systemManagerPermissions,
  1022  		"system_user_manager_permissions":             systemUserManagerPermissions,
  1023  		"system_read_only_admin_permissions":          systemReadOnlyAdminPermissions,
  1024  		"team_admin_permissions":                      teamAdminPermissions,
  1025  		"team_user_permissions":                       teamUserPermissions,
  1026  		"team_guest_permissions":                      teamGuestPermissions,
  1027  		"channel_admin_permissions":                   channelAdminPermissions,
  1028  		"channel_user_permissions":                    channelUserPermissions,
  1029  		"channel_guest_permissions":                   channelGuestPermissions,
  1030  		"system_manager_permissions_modified":         systemManagerPermissionsModified,
  1031  		"system_manager_count":                        systemManagerCount,
  1032  		"system_user_manager_permissions_modified":    systemUserManagerPermissionsModified,
  1033  		"system_user_manager_count":                   systemUserManagerCount,
  1034  		"system_read_only_admin_permissions_modified": systemReadOnlyAdminPermissionsModified,
  1035  		"system_read_only_admin_count":                systemReadOnlyAdminCount,
  1036  	})
  1037  
  1038  	if schemes, err := ts.srv.GetSchemes(model.SCHEME_SCOPE_TEAM, 0, 100); err == nil {
  1039  		for _, scheme := range schemes {
  1040  			teamAdminPermissions := ""
  1041  			if role, err := ts.srv.GetRoleByName(scheme.DefaultTeamAdminRole); err == nil {
  1042  				teamAdminPermissions = strings.Join(role.Permissions, " ")
  1043  			}
  1044  
  1045  			teamUserPermissions := ""
  1046  			if role, err := ts.srv.GetRoleByName(scheme.DefaultTeamUserRole); err == nil {
  1047  				teamUserPermissions = strings.Join(role.Permissions, " ")
  1048  			}
  1049  
  1050  			teamGuestPermissions := ""
  1051  			if role, err := ts.srv.GetRoleByName(scheme.DefaultTeamGuestRole); err == nil {
  1052  				teamGuestPermissions = strings.Join(role.Permissions, " ")
  1053  			}
  1054  
  1055  			channelAdminPermissions := ""
  1056  			if role, err := ts.srv.GetRoleByName(scheme.DefaultChannelAdminRole); err == nil {
  1057  				channelAdminPermissions = strings.Join(role.Permissions, " ")
  1058  			}
  1059  
  1060  			channelUserPermissions := ""
  1061  			if role, err := ts.srv.GetRoleByName(scheme.DefaultChannelUserRole); err == nil {
  1062  				channelUserPermissions = strings.Join(role.Permissions, " ")
  1063  			}
  1064  
  1065  			channelGuestPermissions := ""
  1066  			if role, err := ts.srv.GetRoleByName(scheme.DefaultChannelGuestRole); err == nil {
  1067  				channelGuestPermissions = strings.Join(role.Permissions, " ")
  1068  			}
  1069  
  1070  			count, _ := ts.dbStore.Team().AnalyticsGetTeamCountForScheme(scheme.Id)
  1071  
  1072  			ts.sendTelemetry(TrackPermissionsTeamSchemes, map[string]interface{}{
  1073  				"scheme_id":                 scheme.Id,
  1074  				"team_admin_permissions":    teamAdminPermissions,
  1075  				"team_user_permissions":     teamUserPermissions,
  1076  				"team_guest_permissions":    teamGuestPermissions,
  1077  				"channel_admin_permissions": channelAdminPermissions,
  1078  				"channel_user_permissions":  channelUserPermissions,
  1079  				"channel_guest_permissions": channelGuestPermissions,
  1080  				"team_count":                count,
  1081  			})
  1082  		}
  1083  	}
  1084  }
  1085  
  1086  func (ts *TelemetryService) trackElasticsearch() {
  1087  	data := map[string]interface{}{}
  1088  
  1089  	for _, engine := range ts.searchEngine.GetActiveEngines() {
  1090  		if engine.GetVersion() != 0 && engine.GetName() == "elasticsearch" {
  1091  			data["elasticsearch_server_version"] = engine.GetVersion()
  1092  		}
  1093  	}
  1094  
  1095  	ts.sendTelemetry(TrackElasticsearch, data)
  1096  }
  1097  
  1098  func (ts *TelemetryService) trackGroups() {
  1099  	groupCount, err := ts.dbStore.Group().GroupCount()
  1100  	if err != nil {
  1101  		mlog.Debug("Could not get group_count", mlog.Err(err))
  1102  	}
  1103  
  1104  	groupTeamCount, err := ts.dbStore.Group().GroupTeamCount()
  1105  	if err != nil {
  1106  		mlog.Debug("Could not get group_team_count", mlog.Err(err))
  1107  	}
  1108  
  1109  	groupChannelCount, err := ts.dbStore.Group().GroupChannelCount()
  1110  	if err != nil {
  1111  		mlog.Debug("Could not get group_channel_count", mlog.Err(err))
  1112  	}
  1113  
  1114  	groupSyncedTeamCount, nErr := ts.dbStore.Team().GroupSyncedTeamCount()
  1115  	if nErr != nil {
  1116  		mlog.Debug("Could not get group_synced_team_count", mlog.Err(nErr))
  1117  	}
  1118  
  1119  	groupSyncedChannelCount, nErr := ts.dbStore.Channel().GroupSyncedChannelCount()
  1120  	if nErr != nil {
  1121  		mlog.Debug("Could not get group_synced_channel_count", mlog.Err(nErr))
  1122  	}
  1123  
  1124  	groupMemberCount, err := ts.dbStore.Group().GroupMemberCount()
  1125  	if err != nil {
  1126  		mlog.Debug("Could not get group_member_count", mlog.Err(err))
  1127  	}
  1128  
  1129  	distinctGroupMemberCount, err := ts.dbStore.Group().DistinctGroupMemberCount()
  1130  	if err != nil {
  1131  		mlog.Debug("Could not get distinct_group_member_count", mlog.Err(err))
  1132  	}
  1133  
  1134  	groupCountWithAllowReference, err := ts.dbStore.Group().GroupCountWithAllowReference()
  1135  	if err != nil {
  1136  		mlog.Debug("Could not get group_count_with_allow_reference", mlog.Err(err))
  1137  	}
  1138  
  1139  	ts.sendTelemetry(TrackGroups, map[string]interface{}{
  1140  		"group_count":                      groupCount,
  1141  		"group_team_count":                 groupTeamCount,
  1142  		"group_channel_count":              groupChannelCount,
  1143  		"group_synced_team_count":          groupSyncedTeamCount,
  1144  		"group_synced_channel_count":       groupSyncedChannelCount,
  1145  		"group_member_count":               groupMemberCount,
  1146  		"distinct_group_member_count":      distinctGroupMemberCount,
  1147  		"group_count_with_allow_reference": groupCountWithAllowReference,
  1148  	})
  1149  }
  1150  
  1151  func (ts *TelemetryService) trackChannelModeration() {
  1152  	channelSchemeCount, err := ts.dbStore.Scheme().CountByScope(model.SCHEME_SCOPE_CHANNEL)
  1153  	if err != nil {
  1154  		mlog.Debug("Could not get channel_scheme_count", mlog.Err(err))
  1155  	}
  1156  
  1157  	createPostUser, err := ts.dbStore.Scheme().CountWithoutPermission(model.SCHEME_SCOPE_CHANNEL, model.PERMISSION_CREATE_POST.Id, model.RoleScopeChannel, model.RoleTypeUser)
  1158  	if err != nil {
  1159  		mlog.Debug("Could not get create_post_user_disabled_count", mlog.Err(err))
  1160  	}
  1161  
  1162  	createPostGuest, err := ts.dbStore.Scheme().CountWithoutPermission(model.SCHEME_SCOPE_CHANNEL, model.PERMISSION_CREATE_POST.Id, model.RoleScopeChannel, model.RoleTypeGuest)
  1163  	if err != nil {
  1164  		mlog.Debug("Could not get create_post_guest_disabled_count", mlog.Err(err))
  1165  	}
  1166  
  1167  	// only need to track one of 'add_reaction' or 'remove_reaction` because they're both toggled together by the channel moderation feature
  1168  	postReactionsUser, err := ts.dbStore.Scheme().CountWithoutPermission(model.SCHEME_SCOPE_CHANNEL, model.PERMISSION_ADD_REACTION.Id, model.RoleScopeChannel, model.RoleTypeUser)
  1169  	if err != nil {
  1170  		mlog.Debug("Could not get post_reactions_user_disabled_count", mlog.Err(err))
  1171  	}
  1172  
  1173  	postReactionsGuest, err := ts.dbStore.Scheme().CountWithoutPermission(model.SCHEME_SCOPE_CHANNEL, model.PERMISSION_ADD_REACTION.Id, model.RoleScopeChannel, model.RoleTypeGuest)
  1174  	if err != nil {
  1175  		mlog.Debug("Could not get post_reactions_guest_disabled_count", mlog.Err(err))
  1176  	}
  1177  
  1178  	// only need to track one of 'manage_public_channel_members' or 'manage_private_channel_members` because they're both toggled together by the channel moderation feature
  1179  	manageMembersUser, err := ts.dbStore.Scheme().CountWithoutPermission(model.SCHEME_SCOPE_CHANNEL, model.PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id, model.RoleScopeChannel, model.RoleTypeUser)
  1180  	if err != nil {
  1181  		mlog.Debug("Could not get manage_members_user_disabled_count", mlog.Err(err))
  1182  	}
  1183  
  1184  	useChannelMentionsUser, err := ts.dbStore.Scheme().CountWithoutPermission(model.SCHEME_SCOPE_CHANNEL, model.PERMISSION_USE_CHANNEL_MENTIONS.Id, model.RoleScopeChannel, model.RoleTypeUser)
  1185  	if err != nil {
  1186  		mlog.Debug("Could not get use_channel_mentions_user_disabled_count", mlog.Err(err))
  1187  	}
  1188  
  1189  	useChannelMentionsGuest, err := ts.dbStore.Scheme().CountWithoutPermission(model.SCHEME_SCOPE_CHANNEL, model.PERMISSION_USE_CHANNEL_MENTIONS.Id, model.RoleScopeChannel, model.RoleTypeGuest)
  1190  	if err != nil {
  1191  		mlog.Debug("Could not get use_channel_mentions_guest_disabled_count", mlog.Err(err))
  1192  	}
  1193  
  1194  	ts.sendTelemetry(TrackChannelModeration, map[string]interface{}{
  1195  		"channel_scheme_count": channelSchemeCount,
  1196  
  1197  		"create_post_user_disabled_count":  createPostUser,
  1198  		"create_post_guest_disabled_count": createPostGuest,
  1199  
  1200  		"post_reactions_user_disabled_count":  postReactionsUser,
  1201  		"post_reactions_guest_disabled_count": postReactionsGuest,
  1202  
  1203  		"manage_members_user_disabled_count": manageMembersUser, // the UI does not allow this to be removed for guests
  1204  
  1205  		"use_channel_mentions_user_disabled_count":  useChannelMentionsUser,
  1206  		"use_channel_mentions_guest_disabled_count": useChannelMentionsGuest,
  1207  	})
  1208  }
  1209  
  1210  func (ts *TelemetryService) initRudder(endpoint string, rudderKey string) {
  1211  	if ts.rudderClient == nil {
  1212  		config := rudder.Config{}
  1213  		config.Logger = rudder.StdLogger(ts.log.StdLog(mlog.String("source", "rudder")))
  1214  		config.Endpoint = endpoint
  1215  		// For testing
  1216  		if endpoint != RudderDataplaneURL {
  1217  			config.Verbose = true
  1218  			config.BatchSize = 1
  1219  		}
  1220  		client, err := rudder.NewWithConfig(rudderKey, endpoint, config)
  1221  		if err != nil {
  1222  			mlog.Error("Failed to create Rudder instance", mlog.Err(err))
  1223  			return
  1224  		}
  1225  		client.Enqueue(rudder.Identify{
  1226  			UserId: ts.TelemetryID,
  1227  		})
  1228  
  1229  		ts.rudderClient = client
  1230  	}
  1231  }
  1232  
  1233  func (ts *TelemetryService) doTelemetryIfNeeded(firstRun time.Time) {
  1234  	hoursSinceFirstServerRun := time.Since(firstRun).Hours()
  1235  	// Send once every 10 minutes for the first hour
  1236  	// Send once every hour thereafter for the first 12 hours
  1237  	// Send at the 24 hour mark and every 24 hours after
  1238  	if hoursSinceFirstServerRun < 1 {
  1239  		ts.doTelemetry()
  1240  	} else if hoursSinceFirstServerRun <= 12 && time.Since(ts.timestampLastTelemetrySent) >= time.Hour {
  1241  		ts.doTelemetry()
  1242  	} else if hoursSinceFirstServerRun > 12 && time.Since(ts.timestampLastTelemetrySent) >= 24*time.Hour {
  1243  		ts.doTelemetry()
  1244  	}
  1245  }
  1246  
  1247  func (ts *TelemetryService) RunTelemetryJob(firstRun int64) {
  1248  	// Send on boot
  1249  	ts.doTelemetry()
  1250  	model.CreateRecurringTask("Telemetry", func() {
  1251  		ts.doTelemetryIfNeeded(utils.TimeFromMillis(firstRun))
  1252  	}, time.Minute*10)
  1253  }
  1254  
  1255  func (ts *TelemetryService) doTelemetry() {
  1256  	if *ts.srv.Config().LogSettings.EnableDiagnostics {
  1257  		ts.timestampLastTelemetrySent = time.Now()
  1258  		ts.sendDailyTelemetry(false)
  1259  	}
  1260  }
  1261  
  1262  // Shutdown closes the telemetry client.
  1263  func (ts *TelemetryService) Shutdown() error {
  1264  	if ts.rudderClient != nil {
  1265  		return ts.rudderClient.Close()
  1266  	}
  1267  	return nil
  1268  }
  1269  
  1270  func (ts *TelemetryService) trackWarnMetrics() {
  1271  	systemDataList, nErr := ts.dbStore.System().Get()
  1272  	if nErr != nil {
  1273  		return
  1274  	}
  1275  	for key, value := range systemDataList {
  1276  		if strings.HasPrefix(key, model.WARN_METRIC_STATUS_STORE_PREFIX) {
  1277  			if _, ok := model.WarnMetricsTable[key]; ok {
  1278  				ts.sendTelemetry(TrackWarnMetrics, map[string]interface{}{
  1279  					key: value != "false",
  1280  				})
  1281  			}
  1282  		}
  1283  	}
  1284  }
  1285  
  1286  func (ts *TelemetryService) trackPluginConfig(cfg *model.Config, marketplaceURL string) {
  1287  	pluginConfigData := map[string]interface{}{
  1288  		"enable_nps_survey":             pluginSetting(&cfg.PluginSettings, "com.mattermost.nps", "enablesurvey", true),
  1289  		"enable":                        *cfg.PluginSettings.Enable,
  1290  		"enable_uploads":                *cfg.PluginSettings.EnableUploads,
  1291  		"allow_insecure_download_url":   *cfg.PluginSettings.AllowInsecureDownloadUrl,
  1292  		"enable_health_check":           *cfg.PluginSettings.EnableHealthCheck,
  1293  		"enable_marketplace":            *cfg.PluginSettings.EnableMarketplace,
  1294  		"require_pluginSignature":       *cfg.PluginSettings.RequirePluginSignature,
  1295  		"enable_remote_marketplace":     *cfg.PluginSettings.EnableRemoteMarketplace,
  1296  		"automatic_prepackaged_plugins": *cfg.PluginSettings.AutomaticPrepackagedPlugins,
  1297  		"is_default_marketplace_url":    isDefault(*cfg.PluginSettings.MarketplaceUrl, model.PLUGIN_SETTINGS_DEFAULT_MARKETPLACE_URL),
  1298  		"signature_public_key_files":    len(cfg.PluginSettings.SignaturePublicKeyFiles),
  1299  	}
  1300  
  1301  	// knownPluginIDs lists all known plugin IDs in the Marketplace
  1302  	knownPluginIDs := []string{
  1303  		"antivirus",
  1304  		"com.github.manland.mattermost-plugin-gitlab",
  1305  		"com.github.moussetc.mattermost.plugin.giphy",
  1306  		"com.github.phillipahereza.mattermost-plugin-digitalocean",
  1307  		"com.mattermost.aws-sns",
  1308  		"com.mattermost.confluence",
  1309  		"com.mattermost.custom-attributes",
  1310  		"com.mattermost.mscalendar",
  1311  		"com.mattermost.nps",
  1312  		"com.mattermost.plugin-channel-export",
  1313  		"com.mattermost.plugin-incident-management",
  1314  		"com.mattermost.plugin-todo",
  1315  		"com.mattermost.webex",
  1316  		"com.mattermost.welcomebot",
  1317  		"github",
  1318  		"jenkins",
  1319  		"jira",
  1320  		"jitsi",
  1321  		"mattermost-autolink",
  1322  		"memes",
  1323  		"skype4business",
  1324  		"zoom",
  1325  	}
  1326  
  1327  	marketplacePlugins, err := ts.getAllMarketplaceplugins(marketplaceURL)
  1328  	if err != nil {
  1329  		mlog.Info("Failed to fetch marketplace plugins for telemetry. Using predefined list.", mlog.Err(err))
  1330  
  1331  		for _, id := range knownPluginIDs {
  1332  			pluginConfigData["enable_"+id] = pluginActivated(cfg.PluginSettings.PluginStates, id)
  1333  		}
  1334  	} else {
  1335  		for _, p := range marketplacePlugins {
  1336  			id := p.Manifest.Id
  1337  
  1338  			pluginConfigData["enable_"+id] = pluginActivated(cfg.PluginSettings.PluginStates, id)
  1339  		}
  1340  	}
  1341  
  1342  	pluginsEnvironment := ts.srv.GetPluginsEnvironment()
  1343  	if pluginsEnvironment != nil {
  1344  		if plugins, appErr := pluginsEnvironment.Available(); appErr != nil {
  1345  			mlog.Warn("Unable to add plugin versions to telemetry", mlog.Err(appErr))
  1346  		} else {
  1347  			// If marketplace request failed, use predefined list
  1348  			if marketplacePlugins == nil {
  1349  				for _, id := range knownPluginIDs {
  1350  					pluginConfigData["version_"+id] = pluginVersion(plugins, id)
  1351  				}
  1352  			} else {
  1353  				for _, p := range marketplacePlugins {
  1354  					id := p.Manifest.Id
  1355  
  1356  					pluginConfigData["version_"+id] = pluginVersion(plugins, id)
  1357  				}
  1358  			}
  1359  		}
  1360  	}
  1361  
  1362  	ts.sendTelemetry(TrackConfigPlugin, pluginConfigData)
  1363  }
  1364  
  1365  func (ts *TelemetryService) getAllMarketplaceplugins(marketplaceURL string) ([]*model.BaseMarketplacePlugin, error) {
  1366  	marketplaceClient, err := marketplace.NewClient(
  1367  		marketplaceURL,
  1368  		ts.srv.HttpService(),
  1369  	)
  1370  	if err != nil {
  1371  		return nil, err
  1372  	}
  1373  
  1374  	// Fetch all plugins from marketplace.
  1375  	filter := &model.MarketplacePluginFilter{
  1376  		PerPage:       -1,
  1377  		ServerVersion: model.CurrentVersion,
  1378  	}
  1379  
  1380  	license := ts.srv.License()
  1381  	if license != nil && *license.Features.EnterprisePlugins {
  1382  		filter.EnterprisePlugins = true
  1383  	}
  1384  
  1385  	if model.BuildEnterpriseReady == "true" {
  1386  		filter.BuildEnterpriseReady = true
  1387  	}
  1388  
  1389  	return marketplaceClient.GetPlugins(filter)
  1390  }