From 441f5657c84882b5d441c3d0bda36797523ebbc0 Mon Sep 17 00:00:00 2001 From: Harrison Healey Date: Tue, 21 May 2024 18:04:12 -0400 Subject: [PATCH] MM-57882 Add metric for the time it takes to open the Threads list (#26983) * MM-57882 Add metric for the time it takes to open the Threads list * Clean up mark because the starting mark may be missing * Pass global threads load duration to Prometheus * Update mocks --- server/channels/app/metrics.go | 2 ++ server/einterfaces/metrics.go | 1 + server/einterfaces/mocks/MetricsInterface.go | 5 +++ server/enterprise/metrics/metrics.go | 34 ++++++++++++++----- server/public/model/metrics.go | 19 ++++++----- .../global_threads/global_threads.tsx | 8 +++++ .../global_threads_link.tsx | 6 ++++ .../src/utils/performance_telemetry/index.ts | 2 ++ 8 files changed, 59 insertions(+), 18 deletions(-) diff --git a/server/channels/app/metrics.go b/server/channels/app/metrics.go index 9de379ae1b..7a57b159c9 100644 --- a/server/channels/app/metrics.go +++ b/server/channels/app/metrics.go @@ -42,6 +42,8 @@ func (a *App) RegisterPerformanceReport(rctx request.CTX, report *model.Performa a.Metrics().ObserveClientTeamSwitchDuration(commonLabels["platform"], commonLabels["agent"], h.Value/1000) case model.ClientRHSLoadDuration: a.Metrics().ObserveClientRHSLoadDuration(commonLabels["platform"], commonLabels["agent"], h.Value/1000) + case model.ClientGlobalThreadsLoadDuration: + a.Metrics().ObserveGlobalThreadsLoadDuration(commonLabels["platform"], commonLabels["agent"], h.Value/1000) default: // we intentionally skip unknown metrics } diff --git a/server/einterfaces/metrics.go b/server/einterfaces/metrics.go index 95993accaa..af7ec7ecdb 100644 --- a/server/einterfaces/metrics.go +++ b/server/einterfaces/metrics.go @@ -112,4 +112,5 @@ type MetricsInterface interface { ObserveClientChannelSwitchDuration(platform, agent string, elapsed float64) ObserveClientTeamSwitchDuration(platform, agent string, elapsed float64) ObserveClientRHSLoadDuration(platform, agent string, elapsed float64) + ObserveGlobalThreadsLoadDuration(platform, agent string, elapsed float64) } diff --git a/server/einterfaces/mocks/MetricsInterface.go b/server/einterfaces/mocks/MetricsInterface.go index 628c636c35..c114fd375b 100644 --- a/server/einterfaces/mocks/MetricsInterface.go +++ b/server/einterfaces/mocks/MetricsInterface.go @@ -353,6 +353,11 @@ func (_m *MetricsInterface) ObserveFilesSearchDuration(elapsed float64) { _m.Called(elapsed) } +// ObserveGlobalThreadsLoadDuration provides a mock function with given fields: platform, agent, elapsed +func (_m *MetricsInterface) ObserveGlobalThreadsLoadDuration(platform string, agent string, elapsed float64) { + _m.Called(platform, agent, elapsed) +} + // ObservePluginAPIDuration provides a mock function with given fields: pluginID, apiName, success, elapsed func (_m *MetricsInterface) ObservePluginAPIDuration(pluginID string, apiName string, success bool, elapsed float64) { _m.Called(pluginID, apiName, success, elapsed) diff --git a/server/enterprise/metrics/metrics.go b/server/enterprise/metrics/metrics.go index cd209ea7fc..47e08162b0 100644 --- a/server/enterprise/metrics/metrics.go +++ b/server/enterprise/metrics/metrics.go @@ -211,15 +211,16 @@ type MetricsInterfaceImpl struct { NotificationNotSentCounters *prometheus.CounterVec NotificationUnsupportedCounters *prometheus.CounterVec - ClientTimeToFirstByte *prometheus.HistogramVec - ClientFirstContentfulPaint *prometheus.HistogramVec - ClientLargestContentfulPaint *prometheus.HistogramVec - ClientInteractionToNextPaint *prometheus.HistogramVec - ClientCumulativeLayoutShift *prometheus.HistogramVec - ClientLongTasks *prometheus.CounterVec - ClientChannelSwitchDuration *prometheus.HistogramVec - ClientTeamSwitchDuration *prometheus.HistogramVec - ClientRHSLoadDuration *prometheus.HistogramVec + ClientTimeToFirstByte *prometheus.HistogramVec + ClientFirstContentfulPaint *prometheus.HistogramVec + ClientLargestContentfulPaint *prometheus.HistogramVec + ClientInteractionToNextPaint *prometheus.HistogramVec + ClientCumulativeLayoutShift *prometheus.HistogramVec + ClientLongTasks *prometheus.CounterVec + ClientChannelSwitchDuration *prometheus.HistogramVec + ClientTeamSwitchDuration *prometheus.HistogramVec + ClientRHSLoadDuration *prometheus.HistogramVec + ClientGlobalThreadsLoadDuration *prometheus.HistogramVec } func init() { @@ -1232,6 +1233,17 @@ func New(ps *platform.PlatformService, driver, dataSource string) *MetricsInterf ) m.Registry.MustRegister(m.ClientRHSLoadDuration) + m.ClientGlobalThreadsLoadDuration = prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Namespace: MetricsNamespace, + Subsystem: MetricsSubsystemClientsWeb, + Name: "global_threads_load", + Help: "Duration of the time taken from when a user clicks to open Threads in the LHS until when the global threads view becomes visible (milliseconds)", + }, + []string{"platform", "agent"}, + ) + m.Registry.MustRegister(m.ClientGlobalThreadsLoadDuration) + return m } @@ -1726,6 +1738,10 @@ func (mi *MetricsInterfaceImpl) ObserveClientRHSLoadDuration(platform, agent str mi.ClientRHSLoadDuration.With(prometheus.Labels{"platform": platform, "agent": agent}).Observe(elapsed) } +func (mi *MetricsInterfaceImpl) ObserveGlobalThreadsLoadDuration(platform, agent string, elapsed float64) { + mi.ClientGlobalThreadsLoadDuration.With(prometheus.Labels{"platform": platform, "agent": agent}).Observe(elapsed) +} + func extractDBCluster(driver, connectionString string) (string, error) { host, err := extractHost(driver, connectionString) if err != nil { diff --git a/server/public/model/metrics.go b/server/public/model/metrics.go index ac144cf6b0..85383d0f04 100644 --- a/server/public/model/metrics.go +++ b/server/public/model/metrics.go @@ -14,15 +14,16 @@ import ( type MetricType string const ( - ClientTimeToFirstByte MetricType = "TTFB" - ClientFirstContentfulPaint MetricType = "FCP" - ClientLargestContentfulPaint MetricType = "LCP" - ClientInteractionToNextPaint MetricType = "INP" - ClientCumulativeLayoutShift MetricType = "CLS" - ClientLongTasks MetricType = "long_tasks" - ClientChannelSwitchDuration MetricType = "channel_switch" - ClientTeamSwitchDuration MetricType = "team_switch" - ClientRHSLoadDuration MetricType = "rhs_load" + ClientTimeToFirstByte MetricType = "TTFB" + ClientFirstContentfulPaint MetricType = "FCP" + ClientLargestContentfulPaint MetricType = "LCP" + ClientInteractionToNextPaint MetricType = "INP" + ClientCumulativeLayoutShift MetricType = "CLS" + ClientLongTasks MetricType = "long_tasks" + ClientChannelSwitchDuration MetricType = "channel_switch" + ClientTeamSwitchDuration MetricType = "team_switch" + ClientRHSLoadDuration MetricType = "rhs_load" + ClientGlobalThreadsLoadDuration MetricType = "global_threads_load" performanceReportTTLMilliseconds = 300 * 1000 // 300 seconds/5 minutes ) diff --git a/webapp/channels/src/components/threading/global_threads/global_threads.tsx b/webapp/channels/src/components/threading/global_threads/global_threads.tsx index 60bb090633..335fac1d40 100644 --- a/webapp/channels/src/components/threading/global_threads/global_threads.tsx +++ b/webapp/channels/src/components/threading/global_threads/global_threads.tsx @@ -31,6 +31,7 @@ import LoadingScreen from 'components/loading_screen'; import NoResultsIndicator from 'components/no_results_indicator'; import {PreviousViewedTypes} from 'utils/constants'; +import {Mark, Measure, measureAndReport} from 'utils/performance_telemetry'; import type {GlobalState} from 'types/store/index'; import {LhsItemType, LhsPage} from 'types/store/lhs'; @@ -117,6 +118,13 @@ const GlobalThreads = () => { }); }, [filter, threadIds, unreadThreadIds]); + useEffect(() => { + if (!isLoading) { + measureAndReport(Measure.GlobalThreadsLoad, Mark.GlobalThreadsLinkClicked, undefined, true); + performance.clearMarks(Mark.GlobalThreadsLinkClicked); + } + }, [isLoading]); + useEffect(() => { if (!selectedThread && !selectedPost && !isLoading) { clear(); diff --git a/webapp/channels/src/components/threading/global_threads_link/global_threads_link.tsx b/webapp/channels/src/components/threading/global_threads_link/global_threads_link.tsx index 5876f46d34..6dd8eb0ecf 100644 --- a/webapp/channels/src/components/threading/global_threads_link/global_threads_link.tsx +++ b/webapp/channels/src/components/threading/global_threads_link/global_threads_link.tsx @@ -35,6 +35,7 @@ import Constants, { RHSStates, } from 'utils/constants'; import {t} from 'utils/i18n'; +import {Mark} from 'utils/performance_telemetry'; import type {GlobalState} from 'types/store'; @@ -67,10 +68,15 @@ const GlobalThreadsLink = () => { const showTutorialTrigger = isFeatureEnabled && crtTutorialTrigger === Constants.CrtTutorialTriggerSteps.START && !appHaveOpenModal && Boolean(threadsCount) && threadsCount.total >= 1; const openThreads = useCallback((e) => { e.stopPropagation(); + trackEvent('crt', 'go_to_global_threads'); + + performance.mark(Mark.GlobalThreadsLinkClicked); + if (showTutorialTrigger) { dispatch(openModal({modalId: ModalIdentifiers.COLLAPSED_REPLY_THREADS_MODAL, dialogType: CollapsedReplyThreadsModal, dialogProps: {}})); } + if (rhsOpen && rhsState === RHSStates.EDIT_HISTORY) { dispatch(closeRightHandSide()); } diff --git a/webapp/channels/src/utils/performance_telemetry/index.ts b/webapp/channels/src/utils/performance_telemetry/index.ts index 552c1eedb1..dc736ef5da 100644 --- a/webapp/channels/src/utils/performance_telemetry/index.ts +++ b/webapp/channels/src/utils/performance_telemetry/index.ts @@ -3,6 +3,7 @@ export const enum Mark { ChannelLinkClicked = 'SidebarChannelLink#click', + GlobalThreadsLinkClicked = 'GlobalThreadsLink#click', PostListLoaded = 'PostList#component', PostSelected = 'PostList#postSelected', TeamLinkClicked = 'TeamLink#click', @@ -10,6 +11,7 @@ export const enum Mark { export const enum Measure { ChannelSwitch = 'channel_switch', + GlobalThreadsLoad = 'global_threads_load', RhsLoad = 'rhs_load', TeamSwitch = 'team_switch', }