Some checks failed
Server CI / Postgres (shard 0) (push) Has been skipped
Server CI / Postgres (shard 3) (push) Has been skipped
BuildEnv Docker Image / build-image (push) Failing after 4s
BuildEnv Docker Image / build-image-fips (push) Failing after 4s
Migration Review & Release Notes / Generate migration review & release notes (push) Failing after 3s
Server CI / Build Environment (push) Failing after 3s
Server CI / Postgres (shard 1) (push) Has been skipped
Tools CI / check-style (mattermost-govet) (push) Failing after 4s
Server CI / Postgres (shard 2) (push) Has been skipped
Tools CI / check-style (mmgotool) (push) Failing after 3s
Server CI / Elasticsearch v8 Compatibility (push) Has been skipped
Server CI / OpenSearch v2 Compatibility (push) Has been skipped
Server CI / Postgres FIPS (shard 0) (push) Has been skipped
Tools CI / Test (mattermost-govet) (push) Failing after 3s
Server CI / Postgres FIPS (shard 1) (push) Has been skipped
Server CI / Postgres FIPS (shard 2) (push) Has been skipped
Tools CI / Test (mmgotool) (push) Failing after 3s
Server CI / Postgres FIPS (shard 3) (push) Has been skipped
Server CI / Run mmctl tests (push) Has been skipped
Server CI / Run mmctl tests (FIPS) (push) Has been skipped
Server CI / Merge Postgres Test Results (push) Has been skipped
Server CI / Merge Postgres FIPS Test Results (push) Has been skipped
Server CI / Check backport migrations (push) Has been skipped
Server CI / Check generated files (push) Has been skipped
Server CI / check-style (push) Has been skipped
Server CI / Vet API (push) Has been skipped
Server CI / Build mattermost server app (push) Has been skipped
Server CI / Server CI Complete (push) Failing after 2s
Server CI / Server CI Artifacts (push) Has been skipped
Server CI / Sentry Upload (push) Has been skipped
Server CI / Server CI Report (push) Failing after 5m1s
Server CI Nightly Race / Race Detector (push) Has been skipped
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Webapp CI Cache Warm / Warm Webapp node_modules Cache (push) Has been cancelled
E2E CI Cache Warm / Warm E2E npm Registry Cache (push) Has been cancelled
API / build (push) Has been cancelled
Web App CI / check-types (push) Has been cancelled
Web App CI / check-lint (push) Has been cancelled
Web App CI / check-i18n (push) Has been cancelled
Web App CI / check-external-links (push) Has been cancelled
Web App CI / test (platform) (push) Has been cancelled
Web App CI / test (mattermost-redux) (push) Has been cancelled
Web App CI / test (channels shard 1/4) (push) Has been cancelled
Web App CI / test (channels shard 2/4) (push) Has been cancelled
Web App CI / test (channels shard 3/4) (push) Has been cancelled
Web App CI / test (channels shard 4/4) (push) Has been cancelled
Web App CI / upload-coverage (push) Has been cancelled
Web App CI / build (push) Has been cancelled
YAML Lint / yamllint (push) Has been cancelled
Push mirrored docker images / cd/Push mirrored docker images (push) Has been cancelled
docs-cd / Build and deploy docs (push) Has been cancelled
Docs CI / build (push) Has been cancelled
E2E Cache Warm: Cypress deps / Warm Cypress deps cache (push) Has been cancelled
Scorecards supply-chain security / Scorecard analysis (push) Has been cancelled
Server CI Weekly / Postgres FIPS (push) Has been skipped
Server CI Weekly / Run mmctl tests (FIPS) (push) Has been skipped
Server CI Weekly / Postgres with binary parameters (push) Has been skipped
Server CI Weekly / Build Environment (push) Failing after 1s
Server CI Cache Warm / Warm Go Module and Build Cache (push) Failing after 2s
Server CI Nightly Race / Build Environment (push) Failing after 1s
161 lines
5.9 KiB
Go
161 lines
5.9 KiB
Go
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
package model
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/Masterminds/semver/v3"
|
|
)
|
|
|
|
type MetricType string
|
|
|
|
const (
|
|
ClientTimeToFirstByte MetricType = "TTFB"
|
|
ClientTimeToLastByte MetricType = "TTLB"
|
|
ClientTimeToDOMInteractive MetricType = "dom_interactive"
|
|
ClientSplashScreenEnd MetricType = "splash_screen"
|
|
ClientFirstContentfulPaint MetricType = "FCP"
|
|
ClientLargestContentfulPaint MetricType = "LCP"
|
|
ClientInteractionToNextPaint MetricType = "INP"
|
|
ClientCumulativeLayoutShift MetricType = "CLS"
|
|
ClientLongTasks MetricType = "long_tasks"
|
|
ClientPageLoadDuration MetricType = "page_load"
|
|
ClientChannelSwitchDuration MetricType = "channel_switch"
|
|
ClientTeamSwitchDuration MetricType = "team_switch"
|
|
ClientRHSLoadDuration MetricType = "rhs_load"
|
|
ClientGlobalThreadsLoadDuration MetricType = "global_threads_load"
|
|
|
|
MobileClientLoadDuration MetricType = "mobile_load"
|
|
MobileClientChannelSwitchDuration MetricType = "mobile_channel_switch"
|
|
MobileClientTeamSwitchDuration MetricType = "mobile_team_switch"
|
|
MobileClientNetworkRequestsAverageSpeed MetricType = "mobile_network_requests_average_speed"
|
|
MobileClientNetworkRequestsEffectiveLatency MetricType = "mobile_network_requests_effective_latency"
|
|
MobileClientNetworkRequestsElapsedTime MetricType = "mobile_network_requests_elapsed_time"
|
|
MobileClientNetworkRequestsLatency MetricType = "mobile_network_requests_latency"
|
|
MobileClientNetworkRequestsTotalCompressedSize MetricType = "mobile_network_requests_total_compressed_size"
|
|
MobileClientNetworkRequestsTotalParallelRequests MetricType = "mobile_network_requests_total_parallel_requests"
|
|
MobileClientNetworkRequestsTotalRequests MetricType = "mobile_network_requests_total_requests"
|
|
MobileClientNetworkRequestsTotalSequentialRequests MetricType = "mobile_network_requests_total_sequential_requests"
|
|
MobileClientNetworkRequestsTotalSize MetricType = "mobile_network_requests_total_size"
|
|
|
|
DesktopClientCPUUsage MetricType = "desktop_cpu"
|
|
DesktopClientMemoryUsage MetricType = "desktop_memory"
|
|
|
|
// PluginWebappPerf is the metric type for plugin webapp performance metrics
|
|
PluginWebappPerf MetricType = "plugin_webapp_perf"
|
|
|
|
performanceReportTTLMilliseconds = 300 * 1000 // 300 seconds/5 minutes
|
|
)
|
|
|
|
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",
|
|
)
|
|
AcceptedTrueFalseLabels = SliceToMapKey("true", "false")
|
|
AcceptedSplashScreenOrigins = SliceToMapKey("root", "team_controller")
|
|
AcceptedNetworkRequestGroups = SliceToMapKey(
|
|
"Cold Start",
|
|
"Cold Start Deferred",
|
|
"DeepLink",
|
|
"DeepLink Deferred",
|
|
"Login",
|
|
"Login Deferred",
|
|
"Notification",
|
|
"Notification Deferred",
|
|
"Server Switch",
|
|
"Server Switch Deferred",
|
|
"WebSocket Reconnect",
|
|
"WebSocket Reconnect Deferred",
|
|
)
|
|
)
|
|
|
|
type MetricSample struct {
|
|
Metric MetricType `json:"metric"`
|
|
Value float64 `json:"value"`
|
|
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"`
|
|
ClientID string `json:"client_id"`
|
|
Labels map[string]string `json:"labels"`
|
|
Start float64 `json:"start"`
|
|
End float64 `json:"end"`
|
|
Counters []*MetricSample `json:"counters"`
|
|
Histograms []*MetricSample `json:"histograms"`
|
|
}
|
|
|
|
func (r *PerformanceReport) IsValid() error {
|
|
if r == nil {
|
|
return fmt.Errorf("the report is nil")
|
|
}
|
|
|
|
reportVersion, err := semver.NewVersion(r.Version)
|
|
if err != nil {
|
|
return fmt.Errorf("could not parse semver version: %s, %w", r.Version, err)
|
|
}
|
|
|
|
if reportVersion.Major() != performanceReportVersion.Major() || reportVersion.Minor() > performanceReportVersion.Minor() {
|
|
return fmt.Errorf("report version is not supported: server version: %s, report version: %s", performanceReportVersion.String(), r.Version)
|
|
}
|
|
|
|
if r.Start > r.End {
|
|
return fmt.Errorf("report timestamps are erroneous: start_timestamp %f is greater than end_timestamp %f", r.Start, r.End)
|
|
}
|
|
|
|
now := GetMillis()
|
|
if r.End < float64(now-performanceReportTTLMilliseconds) {
|
|
return fmt.Errorf("report is outdated: end_time %f is past %d ms from now", r.End, performanceReportTTLMilliseconds)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r *PerformanceReport) ProcessLabels() map[string]string {
|
|
return map[string]string{
|
|
"platform": processLabel(r.Labels, "platform", acceptedPlatforms, "other"),
|
|
"agent": processLabel(r.Labels, "agent", acceptedAgents, "other"),
|
|
"desktop_app_version": r.Labels["desktop_app_version"],
|
|
"network_request_group": processLabel(r.Labels, "network_request_group", AcceptedNetworkRequestGroups, "Login"),
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|