[aider assisted] MM-61888: Add ClientSideUserIds field to MetricsSettings (#30127)

We add a new config setting to allow the admin to set a fixed
list of userIDs to track for all client side webapp metrics.

This gives the admin to get a deeper look at how the application
is behaving for a single user.

A new section in the system console is also added for the user
to edit this setting from the UI.

https://mattermost.atlassian.net/browse/MM-61888

```release-note
A new config setting MetricsSettings.ClientSideUserIds is added
where you can set the user ids you want to track for client side webapp
metrics.
```

* fix lint errors

```release-note
NONE
```

* fixing tests

```release-note
NONE
```
Этот коммит содержится в:
Agniva De Sarker
2025-02-13 21:10:34 +05:30
коммит произвёл GitHub
родитель 632a60b332
Коммит 1a58f923e0
13 изменённых файлов: 861 добавлений и 88 удалений

Просмотреть файл

@@ -91,7 +91,11 @@ func TestSubmitMetrics(t *testing.T) {
t.Run("metrics enabled and valid", func(t *testing.T) {
metricsMock := setupMetricsMock()
metricsMock.On("IncrementClientLongTasks", mock.AnythingOfType("string"), mock.AnythingOfType("string"), mock.AnythingOfType("float64")).Return()
metricsMock.On("IncrementClientLongTasks",
mock.AnythingOfType("string"),
mock.AnythingOfType("string"),
mock.AnythingOfType("string"),
mock.AnythingOfType("float64")).Return()
platform.RegisterMetricsInterface(func(_ *platform.PlatformService, _, _ string) einterfaces.MetricsInterface {
return metricsMock
@@ -159,7 +163,11 @@ func TestSubmitMetrics(t *testing.T) {
t.Run("metrics recorded for API errors", func(t *testing.T) {
metricsMock := setupMetricsMock()
metricsMock.On("IncrementClientLongTasks", mock.AnythingOfType("string"), mock.AnythingOfType("string"), mock.AnythingOfType("float64")).Return()
metricsMock.On("IncrementClientLongTasks",
mock.AnythingOfType("string"),
mock.AnythingOfType("string"),
mock.AnythingOfType("string"),
mock.AnythingOfType("float64")).Return()
platform.RegisterMetricsInterface(func(_ *platform.PlatformService, _, _ string) einterfaces.MetricsInterface {
return metricsMock
@@ -190,7 +198,11 @@ func TestSubmitMetrics(t *testing.T) {
t.Run("metrics recorded for URL length limit errors", func(t *testing.T) {
metricsMock := setupMetricsMock()
metricsMock.On("IncrementClientLongTasks", mock.AnythingOfType("string"), mock.AnythingOfType("string"), mock.AnythingOfType("float64")).Return()
metricsMock.On("IncrementClientLongTasks",
mock.AnythingOfType("string"),
mock.AnythingOfType("string"),
mock.AnythingOfType("string"),
mock.AnythingOfType("float64")).Return()
platform.RegisterMetricsInterface(func(_ *platform.PlatformService, _, _ string) einterfaces.MetricsInterface {
return metricsMock

Просмотреть файл

@@ -19,7 +19,7 @@ func (a *App) RegisterPerformanceReport(rctx request.CTX, report *model.Performa
for _, c := range report.Counters {
switch c.Metric {
case model.ClientLongTasks:
a.Metrics().IncrementClientLongTasks(commonLabels["platform"], commonLabels["agent"], c.Value)
a.Metrics().IncrementClientLongTasks(commonLabels["platform"], commonLabels["agent"], userID, c.Value)
default:
// we intentionally skip unknown metrics
}
@@ -50,22 +50,26 @@ func (a *App) RegisterPerformanceReport(rctx request.CTX, report *model.Performa
case model.ClientFirstContentfulPaint:
a.Metrics().ObserveClientFirstContentfulPaint(commonLabels["platform"],
commonLabels["agent"],
userID,
h.Value/1000)
case model.ClientLargestContentfulPaint:
a.Metrics().ObserveClientLargestContentfulPaint(
commonLabels["platform"],
commonLabels["agent"],
h.GetLabelValue("region", model.AcceptedLCPRegions, "other"),
userID,
h.Value/1000)
case model.ClientInteractionToNextPaint:
a.Metrics().ObserveClientInteractionToNextPaint(
commonLabels["platform"],
commonLabels["agent"],
h.GetLabelValue("interaction", model.AcceptedInteractions, "other"),
userID,
h.Value/1000)
case model.ClientCumulativeLayoutShift:
a.Metrics().ObserveClientCumulativeLayoutShift(commonLabels["platform"],
commonLabels["agent"],
userID,
h.Value)
case model.ClientPageLoadDuration:
a.Metrics().ObserveClientPageLoadDuration(commonLabels["platform"],
@@ -76,20 +80,24 @@ func (a *App) RegisterPerformanceReport(rctx request.CTX, report *model.Performa
commonLabels["platform"],
commonLabels["agent"],
h.GetLabelValue("fresh", model.AcceptedTrueFalseLabels, ""),
userID,
h.Value/1000)
case model.ClientTeamSwitchDuration:
a.Metrics().ObserveClientTeamSwitchDuration(
commonLabels["platform"],
commonLabels["agent"],
h.GetLabelValue("fresh", model.AcceptedTrueFalseLabels, ""),
userID,
h.Value/1000)
case model.ClientRHSLoadDuration:
a.Metrics().ObserveClientRHSLoadDuration(commonLabels["platform"],
commonLabels["agent"],
userID,
h.Value/1000)
case model.ClientGlobalThreadsLoadDuration:
a.Metrics().ObserveGlobalThreadsLoadDuration(commonLabels["platform"],
commonLabels["agent"],
userID,
h.Value/1000)
case model.MobileClientLoadDuration:
a.Metrics().ObserveMobileClientLoadDuration(commonLabels["platform"],

Просмотреть файл

@@ -108,16 +108,16 @@ type MetricsInterface interface {
ObserveClientTimeToLastByte(platform, agent, userID string, elapsed float64)
ObserveClientTimeToDomInteractive(platform, agent, userID string, elapsed float64)
ObserveClientSplashScreenEnd(platform, agent, pageType, userID string, elapsed float64)
ObserveClientFirstContentfulPaint(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)
ObserveClientFirstContentfulPaint(platform, agent, userID string, elapsed float64)
ObserveClientLargestContentfulPaint(platform, agent, region, userID string, elapsed float64)
ObserveClientInteractionToNextPaint(platform, agent, interaction, userID string, elapsed float64)
ObserveClientCumulativeLayoutShift(platform, agent, userID string, elapsed float64)
IncrementClientLongTasks(platform, agent, userID string, inc float64)
ObserveClientPageLoadDuration(platform, agent, userID string, elapsed float64)
ObserveClientChannelSwitchDuration(platform, agent, fresh string, elapsed float64)
ObserveClientTeamSwitchDuration(platform, agent, fresh string, elapsed float64)
ObserveClientRHSLoadDuration(platform, agent string, elapsed float64)
ObserveGlobalThreadsLoadDuration(platform, agent string, elapsed float64)
ObserveClientChannelSwitchDuration(platform, agent, fresh, userID string, elapsed float64)
ObserveClientTeamSwitchDuration(platform, agent, fresh, userID string, elapsed float64)
ObserveClientRHSLoadDuration(platform, agent, userID string, elapsed float64)
ObserveGlobalThreadsLoadDuration(platform, agent, userID string, elapsed float64)
ObserveMobileClientLoadDuration(platform string, elapsed float64)
ObserveMobileClientChannelSwitchDuration(platform string, elapsed float64)
ObserveMobileClientTeamSwitchDuration(platform string, elapsed float64)

Просмотреть файл

@@ -78,9 +78,9 @@ func (_m *MetricsInterface) IncrementChannelIndexCounter() {
_m.Called()
}
// IncrementClientLongTasks provides a mock function with given fields: platform, agent, inc
func (_m *MetricsInterface) IncrementClientLongTasks(platform string, agent string, inc float64) {
_m.Called(platform, agent, inc)
// IncrementClientLongTasks provides a mock function with given fields: platform, agent, userID, inc
func (_m *MetricsInterface) IncrementClientLongTasks(platform string, agent string, userID string, inc float64) {
_m.Called(platform, agent, userID, inc)
}
// IncrementClusterEventType provides a mock function with given fields: eventType
@@ -303,29 +303,29 @@ func (_m *MetricsInterface) ObserveAPIEndpointDuration(endpoint string, method s
_m.Called(endpoint, method, statusCode, originClient, pageLoadContext, elapsed)
}
// ObserveClientChannelSwitchDuration provides a mock function with given fields: platform, agent, fresh, elapsed
func (_m *MetricsInterface) ObserveClientChannelSwitchDuration(platform string, agent string, fresh string, elapsed float64) {
_m.Called(platform, agent, fresh, elapsed)
// ObserveClientChannelSwitchDuration provides a mock function with given fields: platform, agent, fresh, userID, elapsed
func (_m *MetricsInterface) ObserveClientChannelSwitchDuration(platform string, agent string, fresh string, userID string, elapsed float64) {
_m.Called(platform, agent, fresh, userID, elapsed)
}
// ObserveClientCumulativeLayoutShift provides a mock function with given fields: platform, agent, elapsed
func (_m *MetricsInterface) ObserveClientCumulativeLayoutShift(platform string, agent string, elapsed float64) {
_m.Called(platform, agent, elapsed)
// ObserveClientCumulativeLayoutShift provides a mock function with given fields: platform, agent, userID, elapsed
func (_m *MetricsInterface) ObserveClientCumulativeLayoutShift(platform string, agent string, userID string, elapsed float64) {
_m.Called(platform, agent, userID, elapsed)
}
// ObserveClientFirstContentfulPaint provides a mock function with given fields: platform, agent, elapsed
func (_m *MetricsInterface) ObserveClientFirstContentfulPaint(platform string, agent string, elapsed float64) {
_m.Called(platform, agent, elapsed)
// ObserveClientFirstContentfulPaint provides a mock function with given fields: platform, agent, userID, elapsed
func (_m *MetricsInterface) ObserveClientFirstContentfulPaint(platform string, agent string, userID string, elapsed float64) {
_m.Called(platform, agent, userID, 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)
// ObserveClientInteractionToNextPaint provides a mock function with given fields: platform, agent, interaction, userID, elapsed
func (_m *MetricsInterface) ObserveClientInteractionToNextPaint(platform string, agent string, interaction string, userID string, elapsed float64) {
_m.Called(platform, agent, interaction, userID, 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)
// ObserveClientLargestContentfulPaint provides a mock function with given fields: platform, agent, region, userID, elapsed
func (_m *MetricsInterface) ObserveClientLargestContentfulPaint(platform string, agent string, region string, userID string, elapsed float64) {
_m.Called(platform, agent, region, userID, elapsed)
}
// ObserveClientPageLoadDuration provides a mock function with given fields: platform, agent, userID, elapsed
@@ -333,9 +333,9 @@ func (_m *MetricsInterface) ObserveClientPageLoadDuration(platform string, agent
_m.Called(platform, agent, userID, elapsed)
}
// ObserveClientRHSLoadDuration provides a mock function with given fields: platform, agent, elapsed
func (_m *MetricsInterface) ObserveClientRHSLoadDuration(platform string, agent string, elapsed float64) {
_m.Called(platform, agent, elapsed)
// ObserveClientRHSLoadDuration provides a mock function with given fields: platform, agent, userID, elapsed
func (_m *MetricsInterface) ObserveClientRHSLoadDuration(platform string, agent string, userID string, elapsed float64) {
_m.Called(platform, agent, userID, elapsed)
}
// ObserveClientSplashScreenEnd provides a mock function with given fields: platform, agent, pageType, userID, elapsed
@@ -343,9 +343,9 @@ func (_m *MetricsInterface) ObserveClientSplashScreenEnd(platform string, agent
_m.Called(platform, agent, pageType, userID, elapsed)
}
// ObserveClientTeamSwitchDuration provides a mock function with given fields: platform, agent, fresh, elapsed
func (_m *MetricsInterface) ObserveClientTeamSwitchDuration(platform string, agent string, fresh string, elapsed float64) {
_m.Called(platform, agent, fresh, elapsed)
// ObserveClientTeamSwitchDuration provides a mock function with given fields: platform, agent, fresh, userID, elapsed
func (_m *MetricsInterface) ObserveClientTeamSwitchDuration(platform string, agent string, fresh string, userID string, elapsed float64) {
_m.Called(platform, agent, fresh, userID, elapsed)
}
// ObserveClientTimeToDomInteractive provides a mock function with given fields: platform, agent, userID, elapsed
@@ -388,9 +388,9 @@ 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)
// ObserveGlobalThreadsLoadDuration provides a mock function with given fields: platform, agent, userID, elapsed
func (_m *MetricsInterface) ObserveGlobalThreadsLoadDuration(platform string, agent string, userID string, elapsed float64) {
_m.Called(platform, agent, userID, elapsed)
}
// ObserveMobileClientChannelSwitchDuration provides a mock function with given fields: platform, elapsed

Просмотреть файл

@@ -55,6 +55,8 @@ type MetricsInterfaceImpl struct {
Registry *prometheus.Registry
ClientSideUserIds map[string]bool
DbMasterConnectionsGauge prometheus.GaugeFunc
DbReadConnectionsGauge prometheus.GaugeFunc
DbSearchConnectionsGauge prometheus.GaugeFunc
@@ -240,7 +242,7 @@ func init() {
})
}
// New creates a new MetricsInterface. The driver and datasoruce parameters are added during
// New creates a new MetricsInterface. The driver and datasource parameters are added during
// migrating configuration store to the new platform service. Once the store and license are migrated,
// we will be able to remove server dependency and lean on platform service during initialization.
func New(ps *platform.PlatformService, driver, dataSource string) *MetricsInterfaceImpl {
@@ -248,6 +250,12 @@ func New(ps *platform.PlatformService, driver, dataSource string) *MetricsInterf
Platform: ps,
}
// Initialize ClientSideUserIds map
m.ClientSideUserIds = make(map[string]bool)
for _, userId := range ps.Config().MetricsSettings.ClientSideUserIds {
m.ClientSideUserIds[userId] = true
}
m.Registry = prometheus.NewRegistry()
options := collectors.ProcessCollectorOpts{
Namespace: MetricsNamespace,
@@ -1196,7 +1204,7 @@ func New(ps *platform.PlatformService, driver, dataSource string) *MetricsInterf
Help: "Duration from when a browser starts to request a page from a server until when it starts to receive data in response (seconds)",
ConstLabels: additionalLabels,
},
[]string{"platform", "agent"},
[]string{"platform", "agent", "user_id"},
m.Platform.Log(),
)
m.Registry.MustRegister(m.ClientTimeToFirstByte)
@@ -1209,7 +1217,7 @@ func New(ps *platform.PlatformService, driver, dataSource string) *MetricsInterf
Help: "Duration from when a browser starts to request a page from a server until when it receives the last byte of the resource or immediately before the transport connection is closed, whichever comes first. (seconds)",
ConstLabels: additionalLabels,
},
[]string{"platform", "agent"},
[]string{"platform", "agent", "user_id"},
m.Platform.Log(),
)
m.Registry.MustRegister(m.ClientTimeToLastByte)
@@ -1223,7 +1231,7 @@ func New(ps *platform.PlatformService, driver, dataSource string) *MetricsInterf
Buckets: []float64{.1, .25, .5, 1, 2.5, 5, 7.5, 10, 12.5, 15},
ConstLabels: additionalLabels,
},
[]string{"platform", "agent"},
[]string{"platform", "agent", "user_id"},
m.Platform.Log(),
)
m.Registry.MustRegister(m.ClientTimeToDOMInteractive)
@@ -1237,7 +1245,7 @@ func New(ps *platform.PlatformService, driver, dataSource string) *MetricsInterf
Buckets: []float64{.1, .25, .5, 1, 2.5, 5, 7.5, 10, 12.5, 15},
ConstLabels: additionalLabels,
},
[]string{"platform", "agent", "page_type"},
[]string{"platform", "agent", "page_type", "user_id"},
m.Platform.Log(),
)
m.Registry.MustRegister(m.ClientSplashScreenEnd)
@@ -1253,7 +1261,7 @@ func New(ps *platform.PlatformService, driver, dataSource string) *MetricsInterf
Buckets: []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10, 15, 20},
ConstLabels: additionalLabels,
},
[]string{"platform", "agent"},
[]string{"platform", "agent", "user_id"},
)
m.Registry.MustRegister(m.ClientFirstContentfulPaint)
@@ -1268,7 +1276,7 @@ func New(ps *platform.PlatformService, driver, dataSource string) *MetricsInterf
Buckets: []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10, 15, 20},
ConstLabels: additionalLabels,
},
[]string{"platform", "agent", "region"},
[]string{"platform", "agent", "region", "user_id"},
)
m.Registry.MustRegister(m.ClientLargestContentfulPaint)
@@ -1280,7 +1288,7 @@ func New(ps *platform.PlatformService, driver, dataSource string) *MetricsInterf
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)",
ConstLabels: additionalLabels,
},
[]string{"platform", "agent", "interaction"},
[]string{"platform", "agent", "interaction", "user_id"},
)
m.Registry.MustRegister(m.ClientInteractionToNextPaint)
@@ -1292,7 +1300,7 @@ func New(ps *platform.PlatformService, driver, dataSource string) *MetricsInterf
Help: "Measure of how much a page's content shifts unexpectedly",
ConstLabels: additionalLabels,
},
[]string{"platform", "agent"},
[]string{"platform", "agent", "user_id"},
)
m.Registry.MustRegister(m.ClientCumulativeLayoutShift)
@@ -1304,7 +1312,7 @@ func New(ps *platform.PlatformService, driver, dataSource string) *MetricsInterf
Help: "Counter of the number of times that the browser's main UI thread is blocked for more than 50ms by a single task",
ConstLabels: additionalLabels,
},
[]string{"platform", "agent"},
[]string{"platform", "agent", "user_id"},
)
m.Registry.MustRegister(m.ClientLongTasks)
@@ -1317,7 +1325,7 @@ func New(ps *platform.PlatformService, driver, dataSource string) *MetricsInterf
Buckets: []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10, 20, 40},
ConstLabels: additionalLabels,
},
[]string{"platform", "agent"},
[]string{"platform", "agent", "user_id"},
m.Platform.Log(),
)
m.Registry.MustRegister(m.ClientPageLoadDuration)
@@ -1330,7 +1338,7 @@ func New(ps *platform.PlatformService, driver, dataSource string) *MetricsInterf
Help: "Duration of the time taken from when a user clicks on a channel in the LHS to when posts in that channel become visible (seconds)",
ConstLabels: additionalLabels,
},
[]string{"platform", "agent", "fresh"},
[]string{"platform", "agent", "fresh", "user_id"},
)
m.Registry.MustRegister(m.ClientChannelSwitchDuration)
@@ -1342,7 +1350,7 @@ func New(ps *platform.PlatformService, driver, dataSource string) *MetricsInterf
Help: "Duration of the time taken from when a user clicks on a team in the LHS to when posts in that team become visible (seconds)",
ConstLabels: additionalLabels,
},
[]string{"platform", "agent", "fresh"},
[]string{"platform", "agent", "fresh", "user_id"},
)
m.Registry.MustRegister(m.ClientTeamSwitchDuration)
@@ -1354,7 +1362,7 @@ func New(ps *platform.PlatformService, driver, dataSource string) *MetricsInterf
Help: "Duration of the time taken from when a user clicks to open a thread in the RHS until when posts in that thread become visible (seconds)",
ConstLabels: additionalLabels,
},
[]string{"platform", "agent"},
[]string{"platform", "agent", "user_id"},
)
m.Registry.MustRegister(m.ClientRHSLoadDuration)
@@ -1366,7 +1374,7 @@ func New(ps *platform.PlatformService, driver, dataSource string) *MetricsInterf
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)",
ConstLabels: additionalLabels,
},
[]string{"platform", "agent"},
[]string{"platform", "agent", "user_id"},
)
m.Registry.MustRegister(m.ClientGlobalThreadsLoadDuration)
@@ -2024,63 +2032,81 @@ func (mi *MetricsInterfaceImpl) DecrementHTTPWebSockets(originClient string) {
mi.HTTPWebsocketsGauge.With(prometheus.Labels{"origin_client": originClient}).Dec()
}
func (mi *MetricsInterfaceImpl) getEffectiveUserID(userID string) string {
if mi.ClientSideUserIds[userID] {
return userID
}
return "<placeholder>"
}
func (mi *MetricsInterfaceImpl) ObserveClientTimeToFirstByte(platform, agent, userID string, elapsed float64) {
mi.ClientTimeToFirstByte.With(prometheus.Labels{"platform": platform, "agent": agent}, userID).Observe(elapsed)
effectiveUserID := mi.getEffectiveUserID(userID)
mi.ClientTimeToFirstByte.With(prometheus.Labels{"platform": platform, "agent": agent, "user_id": effectiveUserID}, userID).Observe(elapsed)
}
func (mi *MetricsInterfaceImpl) ObserveClientTimeToLastByte(platform, agent, userID string, elapsed float64) {
mi.ClientTimeToLastByte.With(prometheus.Labels{"platform": platform, "agent": agent}, userID).Observe(elapsed)
effectiveUserID := mi.getEffectiveUserID(userID)
mi.ClientTimeToLastByte.With(prometheus.Labels{"platform": platform, "agent": agent, "user_id": effectiveUserID}, userID).Observe(elapsed)
}
func (mi *MetricsInterfaceImpl) ObserveClientTimeToDomInteractive(platform, agent, userID string, elapsed float64) {
mi.ClientTimeToDOMInteractive.With(prometheus.Labels{"platform": platform, "agent": agent}, userID).Observe(elapsed)
effectiveUserID := mi.getEffectiveUserID(userID)
mi.ClientTimeToDOMInteractive.With(prometheus.Labels{"platform": platform, "agent": agent, "user_id": effectiveUserID}, userID).Observe(elapsed)
}
func (mi *MetricsInterfaceImpl) ObserveClientSplashScreenEnd(platform, agent, pageType, userID string, elapsed float64) {
mi.ClientSplashScreenEnd.With(prometheus.Labels{"platform": platform, "agent": agent, "page_type": pageType}, userID).Observe(elapsed)
effectiveUserID := mi.getEffectiveUserID(userID)
mi.ClientSplashScreenEnd.With(prometheus.Labels{"platform": platform, "agent": agent, "page_type": pageType, "user_id": effectiveUserID}, userID).Observe(elapsed)
}
func (mi *MetricsInterfaceImpl) ObserveClientFirstContentfulPaint(platform, agent string, elapsed float64) {
mi.ClientFirstContentfulPaint.With(prometheus.Labels{"platform": platform, "agent": agent}).Observe(elapsed)
func (mi *MetricsInterfaceImpl) ObserveClientFirstContentfulPaint(platform, agent, userID string, elapsed float64) {
effectiveUserID := mi.getEffectiveUserID(userID)
mi.ClientFirstContentfulPaint.With(prometheus.Labels{"platform": platform, "agent": agent, "user_id": effectiveUserID}).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) ObserveClientLargestContentfulPaint(platform, agent, region, userID string, elapsed float64) {
effectiveUserID := mi.getEffectiveUserID(userID)
mi.ClientLargestContentfulPaint.With(prometheus.Labels{"platform": platform, "agent": agent, "region": region, "user_id": effectiveUserID}).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) ObserveClientInteractionToNextPaint(platform, agent, interaction, userID string, elapsed float64) {
effectiveUserID := mi.getEffectiveUserID(userID)
mi.ClientInteractionToNextPaint.With(prometheus.Labels{"platform": platform, "agent": agent, "interaction": interaction, "user_id": effectiveUserID}).Observe(elapsed)
}
func (mi *MetricsInterfaceImpl) ObserveClientCumulativeLayoutShift(platform, agent string, elapsed float64) {
mi.ClientCumulativeLayoutShift.With(prometheus.Labels{"platform": platform, "agent": agent}).Observe(elapsed)
func (mi *MetricsInterfaceImpl) ObserveClientCumulativeLayoutShift(platform, agent, userID string, elapsed float64) {
effectiveUserID := mi.getEffectiveUserID(userID)
mi.ClientCumulativeLayoutShift.With(prometheus.Labels{"platform": platform, "agent": agent, "user_id": effectiveUserID}).Observe(elapsed)
}
func (mi *MetricsInterfaceImpl) IncrementClientLongTasks(platform, agent string, inc float64) {
mi.ClientLongTasks.With(prometheus.Labels{"platform": platform, "agent": agent}).Add(inc)
func (mi *MetricsInterfaceImpl) IncrementClientLongTasks(platform, agent, userID string, inc float64) {
effectiveUserID := mi.getEffectiveUserID(userID)
mi.ClientLongTasks.With(prometheus.Labels{"platform": platform, "agent": agent, "user_id": effectiveUserID}).Add(inc)
}
func (mi *MetricsInterfaceImpl) ObserveClientPageLoadDuration(platform, agent, userID string, elapsed float64) {
mi.ClientPageLoadDuration.With(prometheus.Labels{
"platform": platform,
"agent": agent,
}, userID).Observe(elapsed)
effectiveUserID := mi.getEffectiveUserID(userID)
mi.ClientPageLoadDuration.With(prometheus.Labels{"platform": platform, "agent": agent, "user_id": effectiveUserID}, userID).Observe(elapsed)
}
func (mi *MetricsInterfaceImpl) ObserveClientChannelSwitchDuration(platform, agent, fresh string, elapsed float64) {
mi.ClientChannelSwitchDuration.With(prometheus.Labels{"platform": platform, "agent": agent, "fresh": fresh}).Observe(elapsed)
func (mi *MetricsInterfaceImpl) ObserveClientChannelSwitchDuration(platform, agent, fresh, userID string, elapsed float64) {
effectiveUserID := mi.getEffectiveUserID(userID)
mi.ClientChannelSwitchDuration.With(prometheus.Labels{"platform": platform, "agent": agent, "fresh": fresh, "user_id": effectiveUserID}).Observe(elapsed)
}
func (mi *MetricsInterfaceImpl) ObserveClientTeamSwitchDuration(platform, agent, fresh string, elapsed float64) {
mi.ClientTeamSwitchDuration.With(prometheus.Labels{"platform": platform, "agent": agent, "fresh": fresh}).Observe(elapsed)
func (mi *MetricsInterfaceImpl) ObserveClientTeamSwitchDuration(platform, agent, fresh, userID string, elapsed float64) {
effectiveUserID := mi.getEffectiveUserID(userID)
mi.ClientTeamSwitchDuration.With(prometheus.Labels{"platform": platform, "agent": agent, "fresh": fresh, "user_id": effectiveUserID}).Observe(elapsed)
}
func (mi *MetricsInterfaceImpl) ObserveClientRHSLoadDuration(platform, agent string, elapsed float64) {
mi.ClientRHSLoadDuration.With(prometheus.Labels{"platform": platform, "agent": agent}).Observe(elapsed)
func (mi *MetricsInterfaceImpl) ObserveClientRHSLoadDuration(platform, agent, userID string, elapsed float64) {
effectiveUserID := mi.getEffectiveUserID(userID)
mi.ClientRHSLoadDuration.With(prometheus.Labels{"platform": platform, "agent": agent, "user_id": effectiveUserID}).Observe(elapsed)
}
func (mi *MetricsInterfaceImpl) ObserveGlobalThreadsLoadDuration(platform, agent string, elapsed float64) {
mi.ClientGlobalThreadsLoadDuration.With(prometheus.Labels{"platform": platform, "agent": agent}).Observe(elapsed)
func (mi *MetricsInterfaceImpl) ObserveGlobalThreadsLoadDuration(platform, agent, userID string, elapsed float64) {
effectiveUserID := mi.getEffectiveUserID(userID)
mi.ClientGlobalThreadsLoadDuration.With(prometheus.Labels{"platform": platform, "agent": agent, "user_id": effectiveUserID}).Observe(elapsed)
}
func (mi *MetricsInterfaceImpl) ObserveDesktopCpuUsage(platform, version, process string, usage float64) {

Просмотреть файл

@@ -9076,6 +9076,14 @@
"id": "model.config.is_valid.message_export.global_relay.smtp_username.app_error",
"translation": "Message export job GlobalRelaySettings.SmtpUsername must be set."
},
{
"id": "model.config.is_valid.metrics_client_side_user_id.app_error",
"translation": "Invalid client side user id: {{.Id}}"
},
{
"id": "model.config.is_valid.metrics_client_side_user_ids.app_error",
"translation": "Number of elements in ClientSideUserIds {{.CurrentLength}} is higher than maximum limit of {{.MaxLength}}."
},
{
"id": "model.config.is_valid.move_thread.domain_invalid.app_error",
"translation": "Invalid domain for move thread settings"
@@ -9426,7 +9434,7 @@
},
{
"id": "model.incoming_hook.id.app_error",
"translation": "Invalid Id."
"translation": "Invalid Id: {{.Id}}."
},
{
"id": "model.incoming_hook.parse_data.app_error",

Просмотреть файл

@@ -1071,11 +1071,12 @@ func (s *ClusterSettings) SetDefaults() {
}
type MetricsSettings struct {
Enable *bool `access:"environment_performance_monitoring,write_restrictable,cloud_restrictable"`
BlockProfileRate *int `access:"environment_performance_monitoring,write_restrictable,cloud_restrictable"`
ListenAddress *string `access:"environment_performance_monitoring,write_restrictable,cloud_restrictable"` // telemetry: none
EnableClientMetrics *bool `access:"environment_performance_monitoring,write_restrictable,cloud_restrictable"`
EnableNotificationMetrics *bool `access:"environment_performance_monitoring,write_restrictable,cloud_restrictable"`
Enable *bool `access:"environment_performance_monitoring,write_restrictable,cloud_restrictable"`
BlockProfileRate *int `access:"environment_performance_monitoring,write_restrictable,cloud_restrictable"`
ListenAddress *string `access:"environment_performance_monitoring,write_restrictable,cloud_restrictable"` // telemetry: none
EnableClientMetrics *bool `access:"environment_performance_monitoring,write_restrictable,cloud_restrictable"`
EnableNotificationMetrics *bool `access:"environment_performance_monitoring,write_restrictable,cloud_restrictable"`
ClientSideUserIds []string `access:"environment_performance_monitoring,write_restrictable,cloud_restrictable"` // telemetry: none
}
func (s *MetricsSettings) SetDefaults() {
@@ -1098,6 +1099,23 @@ func (s *MetricsSettings) SetDefaults() {
if s.EnableNotificationMetrics == nil {
s.EnableNotificationMetrics = NewPointer(true)
}
if s.ClientSideUserIds == nil {
s.ClientSideUserIds = []string{}
}
}
func (s *MetricsSettings) isValid() *AppError {
const maxLength = 5
if len(s.ClientSideUserIds) > maxLength {
return NewAppError("MetricsSettings.IsValid", "model.config.is_valid.metrics_client_side_user_ids.app_error", map[string]any{"MaxLength": maxLength, "CurrentLength": len(s.ClientSideUserIds)}, "", http.StatusBadRequest)
}
for _, id := range s.ClientSideUserIds {
if !IsValidId(id) {
return NewAppError("MetricsSettings.IsValid", "model.config.is_valid.metrics_client_side_user_id.app_error", map[string]any{"Id": id}, "", http.StatusBadRequest)
}
}
return nil
}
type ExperimentalSettings struct {
@@ -3806,6 +3824,10 @@ func (o *Config) IsValid() *AppError {
return NewAppError("Config.IsValid", "model.config.is_valid.cluster_email_batching.app_error", nil, "", http.StatusBadRequest)
}
if appErr := o.MetricsSettings.isValid(); appErr != nil {
return appErr
}
if appErr := o.CacheSettings.isValid(); appErr != nil {
return appErr
}

Просмотреть файл

@@ -66,7 +66,7 @@ type IncomingWebhooksWithCount struct {
func (o *IncomingWebhook) IsValid() *AppError {
if !IsValidId(o.Id) {
return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.id.app_error", nil, "", http.StatusBadRequest)
return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.id.app_error", map[string]any{"Id": o.Id}, "", http.StatusBadRequest)
}
if o.CreateAt == 0 {