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