[MM-57066][MM-57329] Added metrics for all notification stopping points, consolidated categories between metrics and logging (#26799)

* [MM-57066] Add metric counters for notification events

* Some small changes

* Account for Metrics() sometimes being nil

* Fix test (again)

* Fix more tests

* A few changes from testing - added success counter

* Missed a mock

* Lint

* Add feature flag for notification monitoring
Этот коммит содержится в:
Devin Binnie
2024-04-18 10:30:08 -04:00
коммит произвёл GitHub
родитель 0ce5def8e2
Коммит 02e23a3275
26 изменённых файлов: 572 добавлений и 241 удалений

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

@@ -24,22 +24,12 @@ import (
)
type notificationType string
type notifyPropsReason string
type statusReason string
const (
notificationTypeClear notificationType = "clear"
notificationTypeMessage notificationType = "message"
notificationTypeUpdateBadge notificationType = "update_badge"
notificationTypeDummy notificationType = "dummy"
NotifyPropsReasonChannelMuted notifyPropsReason = "channel_muted"
NotifyPropsReasonSystemMessage notifyPropsReason = "system_message"
NotifyPropsReasonSetToNone notifyPropsReason = "notify_props_set_to_note"
NotifyPropsReasonSetToMention notifyPropsReason = "notify_props_set_to_mention_and_was_not_mentioned"
StatusReasonDNDOrOOO statusReason = "status_is_dnd_or_ooo"
StatusReasonIsActive statusReason = "user_is_active_on_channel"
)
type PushNotificationsHub struct {
@@ -107,10 +97,12 @@ func (a *App) sendPushNotificationToAllSessions(msg *model.PushNotification, use
if rejectionReason != "" {
// Notifications rejected by a plugin should not be considered errors
a.NotificationsLog().Info("Notification rejected by plugin",
mlog.String("type", model.TypePush),
mlog.String("status", model.StatusNotSent),
mlog.String("reason", rejectionReason),
// This is likely normal operation so no need for metrics here
a.NotificationsLog().Debug("Notification rejected by plugin",
mlog.String("type", model.NotificationTypePush),
mlog.String("status", model.NotificationStatusNotSent),
mlog.String("reason", model.NotificationReasonRejectedByPlugin),
mlog.String("rejection_reason", rejectionReason),
mlog.String("user_id", userID),
)
return nil
@@ -118,10 +110,11 @@ func (a *App) sendPushNotificationToAllSessions(msg *model.PushNotification, use
sessions, err := a.getMobileAppSessions(userID)
if err != nil {
a.CountNotificationReason(model.NotificationStatusError, model.NotificationTypePush, model.NotificationReasonFetchError)
a.NotificationsLog().Error("Failed to send mobile app sessions",
mlog.String("type", model.TypePush),
mlog.String("status", model.StatusServerError),
mlog.String("reason", model.ReasonFetchError),
mlog.String("type", model.NotificationTypePush),
mlog.String("status", model.NotificationStatusError),
mlog.String("reason", model.NotificationReasonFetchError),
mlog.String("user_id", userID),
mlog.Err(err),
)
@@ -129,10 +122,11 @@ func (a *App) sendPushNotificationToAllSessions(msg *model.PushNotification, use
}
if msg == nil {
a.CountNotificationReason(model.NotificationStatusError, model.NotificationTypePush, model.NotificationReasonParseError)
a.NotificationsLog().Error("Failed to parse push notification",
mlog.String("type", model.TypePush),
mlog.String("status", model.StatusServerError),
mlog.String("reason", model.ReasonServerError),
mlog.String("type", model.NotificationTypePush),
mlog.String("status", model.NotificationStatusError),
mlog.String("reason", model.NotificationReasonParseError),
mlog.String("user_id", userID),
)
return model.NewAppError(
@@ -147,10 +141,11 @@ func (a *App) sendPushNotificationToAllSessions(msg *model.PushNotification, use
for _, session := range sessions {
// Don't send notifications to this session if it's expired or we want to skip it
if session.IsExpired() || (skipSessionId != "" && skipSessionId == session.Id) {
a.CountNotificationReason(model.NotificationStatusNotSent, model.NotificationTypePush, model.NotificationReasonSessionExpired)
a.NotificationsLog().Debug("Session expired or skipped",
mlog.String("type", model.TypePush),
mlog.String("status", model.StatusNotSent),
mlog.String("reason", model.ReasonUserStatus),
mlog.String("type", model.NotificationTypePush),
mlog.String("status", model.NotificationStatusNotSent),
mlog.String("reason", model.NotificationReasonSessionExpired),
mlog.String("user_id", session.UserId),
mlog.String("session_id", session.Id),
)
@@ -164,10 +159,11 @@ func (a *App) sendPushNotificationToAllSessions(msg *model.PushNotification, use
err := a.sendToPushProxy(tmpMessage, session)
if err != nil {
a.CountNotificationReason(model.NotificationStatusError, model.NotificationTypePush, model.NotificationReasonPushProxySendError)
a.NotificationsLog().Error("Failed to send to push proxy",
mlog.String("type", model.TypePush),
mlog.String("status", model.StatusNotSent),
mlog.String("reason", model.ReasonPushProxyError),
mlog.String("type", model.NotificationTypePush),
mlog.String("status", model.NotificationStatusNotSent),
mlog.String("reason", model.NotificationReasonPushProxySendError),
mlog.String("ack_id", tmpMessage.AckId),
mlog.String("push_type", tmpMessage.Type),
mlog.String("user_id", session.UserId),
@@ -178,7 +174,7 @@ func (a *App) sendPushNotificationToAllSessions(msg *model.PushNotification, use
}
a.NotificationsLog().Trace("Notification sent to push proxy",
mlog.String("type", model.TypePush),
mlog.String("type", model.NotificationTypePush),
mlog.String("ack_id", tmpMessage.AckId),
mlog.String("push_type", tmpMessage.Type),
mlog.String("user_id", session.UserId),
@@ -477,7 +473,7 @@ func (a *App) sendToPushProxy(msg *model.PushNotification, session *model.Sessio
msg.ServerId = a.TelemetryId()
a.NotificationsLog().Trace("Notification will be sent",
mlog.String("type", model.TypePush),
mlog.String("type", model.NotificationTypePush),
mlog.String("ack_id", msg.AckId),
mlog.String("push_type", msg.Type),
mlog.String("user_id", session.UserId),
@@ -507,7 +503,7 @@ func (a *App) SendAckToPushProxy(ack *model.PushNotificationAck) error {
}
a.NotificationsLog().Trace("Notification successfully received",
mlog.String("type", model.TypePush),
mlog.String("type", model.NotificationTypePush),
mlog.String("ack_id", ack.Id),
mlog.String("push_type", ack.NotificationType),
mlog.String("post_id", ack.PostId),
@@ -553,12 +549,12 @@ func (a *App) getMobileAppSessions(userID string) ([]*model.Session, *model.AppE
func (a *App) ShouldSendPushNotification(user *model.User, channelNotifyProps model.StringMap, wasMentioned bool, status *model.Status, post *model.Post, isGM bool) bool {
if notifyPropsAllowedReason := DoesNotifyPropsAllowPushNotification(user, channelNotifyProps, post, wasMentioned, isGM); notifyPropsAllowedReason != "" {
a.CountNotificationReason(model.NotificationStatusNotSent, model.NotificationTypePush, notifyPropsAllowedReason)
a.NotificationsLog().Debug("Notification not sent - notify props",
mlog.String("type", model.TypePush),
mlog.String("type", model.NotificationTypePush),
mlog.String("post_id", post.Id),
mlog.String("status", model.StatusNotSent),
mlog.String("reason", model.ReasonUserConfig),
mlog.String("notify_props_reason", notifyPropsAllowedReason),
mlog.String("status", model.NotificationStatusNotSent),
mlog.String("reason", notifyPropsAllowedReason),
mlog.String("sender_id", post.UserId),
mlog.String("receiver_id", user.Id),
)
@@ -566,12 +562,12 @@ func (a *App) ShouldSendPushNotification(user *model.User, channelNotifyProps mo
}
if statusAllowedReason := DoesStatusAllowPushNotification(user.NotifyProps, status, post.ChannelId); statusAllowedReason != "" {
a.CountNotificationReason(model.NotificationStatusNotSent, model.NotificationTypePush, statusAllowedReason)
a.NotificationsLog().Debug("Notification not sent - status",
mlog.String("type", model.TypePush),
mlog.String("type", model.NotificationTypePush),
mlog.String("post_id", post.Id),
mlog.String("status", model.StatusNotSent),
mlog.String("reason", model.ReasonUserConfig),
mlog.String("status_reason", statusAllowedReason),
mlog.String("status", model.NotificationStatusNotSent),
mlog.String("reason", statusAllowedReason),
mlog.String("sender_id", post.UserId),
mlog.String("receiver_id", user.Id),
mlog.String("receiver_status", status.Status),
@@ -582,7 +578,7 @@ func (a *App) ShouldSendPushNotification(user *model.User, channelNotifyProps mo
return true
}
func DoesNotifyPropsAllowPushNotification(user *model.User, channelNotifyProps model.StringMap, post *model.Post, wasMentioned, isGM bool) notifyPropsReason {
func DoesNotifyPropsAllowPushNotification(user *model.User, channelNotifyProps model.StringMap, post *model.Post, wasMentioned, isGM bool) model.NotificationReason {
userNotifyProps := user.NotifyProps
userNotify := userNotifyProps[model.PushNotifyProp]
channelNotify, ok := channelNotifyProps[model.PushNotifyProp]
@@ -600,19 +596,19 @@ func DoesNotifyPropsAllowPushNotification(user *model.User, channelNotifyProps m
// If the channel is muted do not send push notifications
if channelNotifyProps[model.MarkUnreadNotifyProp] == model.ChannelMarkUnreadMention {
return NotifyPropsReasonChannelMuted
return model.NotificationReasonChannelMuted
}
if post.IsSystemMessage() {
return NotifyPropsReasonSystemMessage
return model.NotificationReasonSystemMessage
}
if notify == model.ChannelNotifyNone {
return NotifyPropsReasonSetToNone
return model.NotificationReasonLevelSetToNone
}
if notify == model.ChannelNotifyMention && !wasMentioned {
return NotifyPropsReasonSetToMention
return model.NotificationReasonNotMentioned
}
if (notify == model.ChannelNotifyAll) &&
@@ -623,10 +619,10 @@ func DoesNotifyPropsAllowPushNotification(user *model.User, channelNotifyProps m
return ""
}
func DoesStatusAllowPushNotification(userNotifyProps model.StringMap, status *model.Status, channelID string) statusReason {
func DoesStatusAllowPushNotification(userNotifyProps model.StringMap, status *model.Status, channelID string) model.NotificationReason {
// If User status is DND or OOO return false right away
if status.Status == model.StatusDnd || status.Status == model.StatusOutOfOffice {
return StatusReasonDNDOrOOO
return model.NotificationReasonUserStatus
}
pushStatus, ok := userNotifyProps[model.PushStatusNotifyProp]
@@ -642,7 +638,7 @@ func DoesStatusAllowPushNotification(userNotifyProps model.StringMap, status *mo
return ""
}
return StatusReasonIsActive
return model.NotificationReasonUserIsActive
}
func (a *App) BuildPushNotificationMessage(c request.CTX, contentsConfig string, post *model.Post, user *model.User, channel *model.Channel, channelName string, senderName string,
@@ -689,11 +685,12 @@ func (a *App) SendTestPushNotification(deviceID string) string {
pushResponse, err := a.rawSendToPushProxy(msg)
if err != nil {
a.CountNotificationReason(model.NotificationStatusError, model.NotificationTypePush, model.NotificationReasonPushProxySendError)
a.NotificationsLog().Error("Failed to send test notification to push proxy",
mlog.String("type", model.TypePush),
mlog.String("type", model.NotificationTypePush),
mlog.String("push_type", msg.Type),
mlog.String("status", model.StatusServerError),
mlog.String("reason", model.ReasonPushProxyError),
mlog.String("status", model.NotificationStatusError),
mlog.String("reason", model.NotificationReasonPushProxySendError),
mlog.String("device_id", msg.DeviceId),
mlog.Err(err),
)
@@ -704,11 +701,12 @@ func (a *App) SendTestPushNotification(deviceID string) string {
case model.PushStatusRemove:
return "false"
case model.PushStatusFail:
a.CountNotificationReason(model.NotificationStatusError, model.NotificationTypePush, model.NotificationReasonPushProxyError)
a.NotificationsLog().Error("Push proxy failed to send test notification",
mlog.String("type", model.TypePush),
mlog.String("type", model.NotificationTypePush),
mlog.String("push_type", msg.Type),
mlog.String("status", model.StatusServerError),
mlog.String("reason", model.ReasonPushProxyError),
mlog.String("status", model.NotificationStatusError),
mlog.String("reason", model.NotificationReasonPushProxyError),
mlog.String("device_id", msg.DeviceId),
mlog.Err(errors.New(pushResponse[model.PushStatusErrorMsg])),
)