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