MM-58535 Add more information to LCP and INP metrics (#27484)
* Improve mocking of imported resources in unit tests We have Webpack configured so that, when code imports an image or other resource, the code gets the URL of that image. Jest now matches that behaviour which is needed because React Testing Library would previously throw an error. * Polyfill ResizeObserver in all unit tests * Ensure haveIChannelPermission always returns a boolean value The previous code could sometimes return undefined. While that should behave the same in practice, it can cause React to print prop type warnings * MM-58535 Add region label to LCP metrics * MM-58535 Upgrade web-vitals and add INP attribution * Change new labels to use snake_case * Remove replaceGlobalStore option from renderWithContext I was going to add this in case any tests failed with this option set to false, but after running those tests, that's not the case. I'm going to remove this as an option since it seems more likely than not that anyone using RTL would prefer to have this on.
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
99881b819a
Коммит
e3b2b13292
@@ -31,9 +31,19 @@ func (a *App) RegisterPerformanceReport(rctx request.CTX, report *model.Performa
|
||||
case model.ClientFirstContentfulPaint:
|
||||
a.Metrics().ObserveClientFirstContentfulPaint(commonLabels["platform"], commonLabels["agent"], h.Value/1000)
|
||||
case model.ClientLargestContentfulPaint:
|
||||
a.Metrics().ObserveClientLargestContentfulPaint(commonLabels["platform"], commonLabels["agent"], h.Value/1000)
|
||||
a.Metrics().ObserveClientLargestContentfulPaint(
|
||||
commonLabels["platform"],
|
||||
commonLabels["agent"],
|
||||
h.GetLabelValue("region", model.AcceptedLCPRegions, "other"),
|
||||
h.Value/1000,
|
||||
)
|
||||
case model.ClientInteractionToNextPaint:
|
||||
a.Metrics().ObserveClientInteractionToNextPaint(commonLabels["platform"], commonLabels["agent"], h.Value/1000)
|
||||
a.Metrics().ObserveClientInteractionToNextPaint(
|
||||
commonLabels["platform"],
|
||||
commonLabels["agent"],
|
||||
h.GetLabelValue("interaction", model.AcceptedInteractions, "other"),
|
||||
h.Value/1000,
|
||||
)
|
||||
case model.ClientCumulativeLayoutShift:
|
||||
a.Metrics().ObserveClientCumulativeLayoutShift(commonLabels["platform"], commonLabels["agent"], h.Value)
|
||||
case model.ClientPageLoadDuration:
|
||||
|
||||
@@ -105,8 +105,8 @@ type MetricsInterface interface {
|
||||
|
||||
ObserveClientTimeToFirstByte(platform, agent string, elapsed float64)
|
||||
ObserveClientFirstContentfulPaint(platform, agent string, elapsed float64)
|
||||
ObserveClientLargestContentfulPaint(platform, agent string, elapsed float64)
|
||||
ObserveClientInteractionToNextPaint(platform, agent string, elapsed float64)
|
||||
ObserveClientLargestContentfulPaint(platform, agent, region string, elapsed float64)
|
||||
ObserveClientInteractionToNextPaint(platform, agent, interaction string, elapsed float64)
|
||||
ObserveClientCumulativeLayoutShift(platform, agent string, elapsed float64)
|
||||
IncrementClientLongTasks(platform, agent string, inc float64)
|
||||
ObserveClientPageLoadDuration(platform, agent string, elapsed float64)
|
||||
|
||||
@@ -313,14 +313,14 @@ func (_m *MetricsInterface) ObserveClientFirstContentfulPaint(platform string, a
|
||||
_m.Called(platform, agent, elapsed)
|
||||
}
|
||||
|
||||
// ObserveClientInteractionToNextPaint provides a mock function with given fields: platform, agent, elapsed
|
||||
func (_m *MetricsInterface) ObserveClientInteractionToNextPaint(platform string, agent string, elapsed float64) {
|
||||
_m.Called(platform, agent, elapsed)
|
||||
// ObserveClientInteractionToNextPaint provides a mock function with given fields: platform, agent, interaction, elapsed
|
||||
func (_m *MetricsInterface) ObserveClientInteractionToNextPaint(platform string, agent string, interaction string, elapsed float64) {
|
||||
_m.Called(platform, agent, interaction, elapsed)
|
||||
}
|
||||
|
||||
// ObserveClientLargestContentfulPaint provides a mock function with given fields: platform, agent, elapsed
|
||||
func (_m *MetricsInterface) ObserveClientLargestContentfulPaint(platform string, agent string, elapsed float64) {
|
||||
_m.Called(platform, agent, elapsed)
|
||||
// ObserveClientLargestContentfulPaint provides a mock function with given fields: platform, agent, region, elapsed
|
||||
func (_m *MetricsInterface) ObserveClientLargestContentfulPaint(platform string, agent string, region string, elapsed float64) {
|
||||
_m.Called(platform, agent, region, elapsed)
|
||||
}
|
||||
|
||||
// ObserveClientPageLoadDuration provides a mock function with given fields: platform, agent, elapsed
|
||||
|
||||
@@ -1175,7 +1175,7 @@ func New(ps *platform.PlatformService, driver, dataSource string) *MetricsInterf
|
||||
// Extend the range of buckets for this while we get a better idea of the expected range of this metric is
|
||||
Buckets: []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10, 15, 20},
|
||||
},
|
||||
[]string{"platform", "agent"},
|
||||
[]string{"platform", "agent", "region"},
|
||||
)
|
||||
m.Registry.MustRegister(m.ClientLargestContentfulPaint)
|
||||
|
||||
@@ -1186,7 +1186,7 @@ func New(ps *platform.PlatformService, driver, dataSource string) *MetricsInterf
|
||||
Name: "interaction_to_next_paint",
|
||||
Help: "Measure of how long it takes for a user to see the effects of clicking with a mouse, tapping with a touchscreen, or pressing a key on the keyboard (seconds)",
|
||||
},
|
||||
[]string{"platform", "agent"},
|
||||
[]string{"platform", "agent", "interaction"},
|
||||
)
|
||||
m.Registry.MustRegister(m.ClientInteractionToNextPaint)
|
||||
|
||||
@@ -1783,12 +1783,12 @@ func (mi *MetricsInterfaceImpl) ObserveClientFirstContentfulPaint(platform, agen
|
||||
mi.ClientFirstContentfulPaint.With(prometheus.Labels{"platform": platform, "agent": agent}).Observe(elapsed)
|
||||
}
|
||||
|
||||
func (mi *MetricsInterfaceImpl) ObserveClientLargestContentfulPaint(platform, agent string, elapsed float64) {
|
||||
mi.ClientLargestContentfulPaint.With(prometheus.Labels{"platform": platform, "agent": agent}).Observe(elapsed)
|
||||
func (mi *MetricsInterfaceImpl) ObserveClientLargestContentfulPaint(platform, agent, region string, elapsed float64) {
|
||||
mi.ClientLargestContentfulPaint.With(prometheus.Labels{"platform": platform, "agent": agent, "region": region}).Observe(elapsed)
|
||||
}
|
||||
|
||||
func (mi *MetricsInterfaceImpl) ObserveClientInteractionToNextPaint(platform, agent string, elapsed float64) {
|
||||
mi.ClientInteractionToNextPaint.With(prometheus.Labels{"platform": platform, "agent": agent}).Observe(elapsed)
|
||||
func (mi *MetricsInterfaceImpl) ObserveClientInteractionToNextPaint(platform, agent, interaction string, elapsed float64) {
|
||||
mi.ClientInteractionToNextPaint.With(prometheus.Labels{"platform": platform, "agent": agent, "interaction": interaction}).Observe(elapsed)
|
||||
}
|
||||
|
||||
func (mi *MetricsInterfaceImpl) ObserveClientCumulativeLayoutShift(platform, agent string, elapsed float64) {
|
||||
|
||||
@@ -37,6 +37,20 @@ var (
|
||||
performanceReportVersion = semver.MustParse("0.1.0")
|
||||
acceptedPlatforms = sliceToMapKey("linux", "macos", "ios", "android", "windows", "other")
|
||||
acceptedAgents = sliceToMapKey("desktop", "firefox", "chrome", "safari", "edge", "other")
|
||||
|
||||
AcceptedInteractions = sliceToMapKey("keyboard", "pointer", "other")
|
||||
AcceptedLCPRegions = sliceToMapKey(
|
||||
"post",
|
||||
"post_textbox",
|
||||
"channel_sidebar",
|
||||
"team_sidebar",
|
||||
"channel_header",
|
||||
"global_header",
|
||||
"announcement_bar",
|
||||
"center_channel",
|
||||
"modal_content",
|
||||
"other",
|
||||
)
|
||||
)
|
||||
|
||||
type MetricSample struct {
|
||||
@@ -46,6 +60,10 @@ type MetricSample struct {
|
||||
Labels map[string]string `json:"labels,omitempty"`
|
||||
}
|
||||
|
||||
func (s *MetricSample) GetLabelValue(name string, acceptedValues map[string]any, defaultValue string) string {
|
||||
return processLabel(s.Labels, name, acceptedValues, defaultValue)
|
||||
}
|
||||
|
||||
// PerformanceReport is a set of samples collected from a client
|
||||
type PerformanceReport struct {
|
||||
Version string `json:"version"`
|
||||
@@ -84,37 +102,25 @@ func (r *PerformanceReport) IsValid() error {
|
||||
}
|
||||
|
||||
func (r *PerformanceReport) ProcessLabels() map[string]string {
|
||||
var platform, agent string
|
||||
var ok bool
|
||||
|
||||
// check if the platform is specified
|
||||
platform, ok = r.Labels["platform"]
|
||||
if !ok {
|
||||
platform = "other"
|
||||
}
|
||||
platform = strings.ToLower(platform)
|
||||
|
||||
// check if platform is one of the accepted platforms
|
||||
_, ok = acceptedPlatforms[platform]
|
||||
if !ok {
|
||||
platform = "other"
|
||||
}
|
||||
|
||||
// check if the agent is specified
|
||||
agent, ok = r.Labels["agent"]
|
||||
if !ok {
|
||||
agent = "other"
|
||||
}
|
||||
agent = strings.ToLower(agent)
|
||||
|
||||
// check if agent is one of the accepted agents
|
||||
_, ok = acceptedAgents[agent]
|
||||
if !ok {
|
||||
agent = "other"
|
||||
}
|
||||
|
||||
return map[string]string{
|
||||
"platform": platform,
|
||||
"agent": agent,
|
||||
"platform": processLabel(r.Labels, "platform", acceptedPlatforms, "other"),
|
||||
"agent": processLabel(r.Labels, "agent", acceptedAgents, "other"),
|
||||
}
|
||||
}
|
||||
|
||||
func processLabel(labels map[string]string, name string, acceptedValues map[string]any, defaultValue string) string {
|
||||
// check if the label is specified
|
||||
value, ok := labels[name]
|
||||
if !ok {
|
||||
return defaultValue
|
||||
}
|
||||
value = strings.ToLower(value)
|
||||
|
||||
// check if the value is one that we accept
|
||||
_, ok = acceptedValues[value]
|
||||
if !ok {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user