feat(metrics): add onboarding screen metrics and section navigation (#16112) (#16145)

* feat(metrics): add onboarding screen metrics and section navigation

Fixes #16100

Adds metrics for navigating to the different screens of the onboarding and when navigating to a new section while logged in; only when enabled of course.

I refactored the code a little to make it simpler. I moved the check to see if the metrics collection is enabled in the async task itself, so we don't have to check it each time we add a new metric

* fix metric sent from module

* review comments

* add flowtype
This commit is contained in:
Jonathan Rainville 2024-08-19 12:52:17 -04:00 committed by GitHub
parent afc129ee5b
commit 42a9530452
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 69 additions and 35 deletions

View File

@ -57,4 +57,4 @@ QtObject:
proc showCommunityMemberUnbannedNotification*(self: GlobalEvents, sectionId: string, title: string, message: string) {.signal.}
proc addCentralizedMetric*(self: GlobalEvents, eventName: string, eventValueJson: string) {.signal.}
proc addCentralizedMetricIfEnabled*(self: GlobalEvents, eventName: string, eventValueJson: string) {.signal.}

View File

@ -1,4 +1,4 @@
import NimQml, tables, json, sugar, sequtils, stew/shims/strformat, marshal, times, chronicles, stint, browsers
import NimQml, tables, json, sugar, sequtils, stew/shims/strformat, marshal, times, chronicles, stint, browsers, strutils
import io_interface, view, controller, chat_search_item, chat_search_model
import ephemeral_notification_item, ephemeral_notification_model
@ -884,6 +884,15 @@ method activeSectionSet*[T](self: Module[T], sectionId: string, skipSavingInSett
of conf.COMMUNITIESPORTAL_SECTION_ID:
self.communitiesModule.onActivated()
# If metrics are enabled, send a navigation event
var sectionIdToSend = sectionId
if sectionId == singletonInstance.userProfile.getPubKey():
sectionIdToSend = conf.CHAT_SECTION_NAME
elif sectionId.startsWith("0x"):
# This is a community
sectionIdToSend = "community"
singletonInstance.globalEvents.addCentralizedMetricIfEnabled("navigation", $(%*{"viewId": sectionIdToSend}))
self.view.model().setActiveSection(sectionId)
self.view.activeSectionSet(item)

View File

@ -1,5 +1,6 @@
import NimQml, chronicles
import NimQml, chronicles, json
import io_interface
import ../../global/global_singleton
import selected_login_account
import internal/[state, state_wrapper]
import models/login_account_model as login_acc_model
@ -74,6 +75,9 @@ QtObject:
return self.currentStartupState.getStateObj()
proc setCurrentStartupState*(self: View, state: State) =
# If metrics is enabled, we send a metric of the screen visited
singletonInstance.globalEvents.addCentralizedMetricIfEnabled("navigation", $(%*{"viewId": state.stateType, "flowType": state.flowType}))
self.currentStartupState.setStateObj(state)
proc getCurrentStartupState(self: View): QVariant {.slot.} =
return self.currentStartupStateVariant

View File

@ -2,13 +2,23 @@ include ../../common/json_utils
include ../../../app/core/tasks/common
type
AsyncAddCentralizedMetricTaskArg = ref object of QObjectTaskArg
AsyncAddCentralizedMetricIfEnabledTaskArg = ref object of QObjectTaskArg
eventName: string
eventValueJson: string
proc asyncAddCentralizedMetricTask(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[AsyncAddCentralizedMetricTaskArg](argEncoded)
proc asyncAddCentralizedMetricIfEnabledTask(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[AsyncAddCentralizedMetricIfEnabledTaskArg](argEncoded)
try:
let metricsEnabled = getIsCentralizedMetricsEnabled()
if not metricsEnabled:
arg.finish(%* {
"metricId": "",
"metricsDisabled": true,
"error": "",
})
return
debug "Add metric for ", eventName = arg.eventName, eventValueJson = arg.eventValueJson
var metric = CentralizedMetricDto()
metric.eventName = arg.eventName
metric.eventValue = if arg.eventValueJson.len > 0: parseJson(arg.eventValueJson) else: JsonNode()
@ -21,6 +31,7 @@ proc asyncAddCentralizedMetricTask(argEncoded: string) {.gcsafe, nimcall.} =
if jsonObj.hasKey("error"):
arg.finish(%* {
"metricId": "",
"metricsDisabled": false,
"error": jsonObj{"error"}.getStr,
})
return
@ -29,6 +40,7 @@ proc asyncAddCentralizedMetricTask(argEncoded: string) {.gcsafe, nimcall.} =
arg.finish(%* {
"metricId": response,
"metricsDisabled": false,
"error": "",
})

View File

@ -8,51 +8,7 @@ import status_go
import constants
import ./dto
include async_tasks
logScope:
topics = "metrics"
QtObject:
type MetricsService* = ref object of QObject
threadpool: ThreadPool
proc delete*(self: MetricsService) =
self.QObject.delete
proc newService*(threadpool: ThreadPool): MetricsService =
new(result, delete)
result.QObject.setup
result.threadpool = threadpool
signalConnect(singletonInstance.globalEvents, "addCentralizedMetric(QString, QString)",
result, "addCentralizedMetric(QString, QString)", 2)
# eventValueJson is a json string
proc addCentralizedMetric*(self: MetricsService, eventName: string, eventValueJson: string) {.slot.} =
let arg = AsyncAddCentralizedMetricTaskArg(
tptr: asyncAddCentralizedMetricTask,
vptr: cast[ByteAddress](self.vptr),
slot: "onCentralizedMetricAdded",
eventName: eventName,
eventValueJson: eventValueJson,
)
self.threadpool.start(arg)
proc onCentralizedMetricAdded*(self: MetricsService, response: string) {.slot.} =
try:
let responseObj = response.parseJson
let errorString = responseObj{"error"}.getStr()
if errorString != "":
error "onCentralizedMetricAdded", error=errorString
return
debug "onCentralizedMetricAdded", metricId=responseObj{"metricId"}.getStr()
except Exception as e:
error "onCentralizedMetricAdded", exceptionMsg = e.msg
proc centralizedMetricsEnabledChaned*(self: MetricsService) {.signal.}
proc isCentralizedMetricsEnabled*(self: MetricsService): bool {.slot.} =
proc getIsCentralizedMetricsEnabled*(): bool =
try:
let response = status_go.centralizedMetricsInfo()
let jsonObj = response.parseJson
@ -64,9 +20,60 @@ QtObject:
except Exception:
return false
include async_tasks
logScope:
topics = "metrics"
QtObject:
type MetricsService* = ref object of QObject
threadpool: ThreadPool
metricsEnabled: bool
proc delete*(self: MetricsService) =
self.QObject.delete
proc newService*(threadpool: ThreadPool): MetricsService =
new(result, delete)
result.QObject.setup
result.threadpool = threadpool
signalConnect(singletonInstance.globalEvents, "addCentralizedMetricIfEnabled(QString, QString)",
result, "addCentralizedMetricIfEnabled(QString, QString)", 2)
# eventValueJson is a json string
proc addCentralizedMetricIfEnabled*(self: MetricsService, eventName: string, eventValueJson: string) {.slot.} =
let arg = AsyncAddCentralizedMetricIfEnabledTaskArg(
tptr: asyncAddCentralizedMetricIfEnabledTask,
vptr: cast[ByteAddress](self.vptr),
slot: "onCentralizedMetricAddedIdEnabled",
eventName: eventName,
eventValueJson: eventValueJson,
)
self.threadpool.start(arg)
proc onCentralizedMetricAddedIdEnabled*(self: MetricsService, response: string) {.slot.} =
try:
let responseObj = response.parseJson
let errorString = responseObj{"error"}.getStr()
if errorString != "":
error "onCentralizedMetricAddedIdEnabled", error=errorString
return
if responseObj{"metricsDisabled"}.getBool:
return
debug "onCentralizedMetricAddedIdEnabled", metricId=responseObj{"metricId"}.getStr()
except Exception as e:
error "onCentralizedMetricAddedIdEnabled", exceptionMsg = e.msg
proc centralizedMetricsEnabledChanged*(self: MetricsService) {.signal.}
proc isCentralizedMetricsEnabled*(self: MetricsService): bool {.slot.} =
return getIsCentralizedMetricsEnabled()
QtProperty[bool] isCentralizedMetricsEnabled:
read = isCentralizedMetricsEnabled
notify = centralizedMetricsEnabledChaned
notify = centralizedMetricsEnabledChanged
proc toggleCentralizedMetrics*(self: MetricsService, enabled: bool) {.slot.} =
try:
@ -79,6 +86,6 @@ QtObject:
if jsonObj{"error"}.getStr.len > 0:
error "toggleCentralizedMetrics", errorMsg=jsonObj["error"].getStr
else:
self.centralizedMetricsEnabledChaned()
self.centralizedMetricsEnabledChanged()
except Exception as e:
error "toggleCentralizedMetrics", exceptionMsg = e.msg

View File

@ -7,9 +7,9 @@ QtObject {
metrics.toggleCentralizedMetrics(enabled)
}
function addCentralizedMetric(eventName, eventValue = null) {
function addCentralizedMetricIfEnabled(eventName, eventValue = null) {
let eventValueJsonStr = !!eventValue ? JSON.stringify(eventValue) : ""
metrics.addCentralizedMetric(eventName, eventValueJsonStr)
metrics.addCentralizedMetricIfEnabled(eventName, eventValueJsonStr)
}
readonly property bool isCentralizedMetricsEnabled : metrics.isCentralizedMetricsEnabled

View File

@ -1460,4 +1460,6 @@ QtObject {
LessThanFiveMins,
MoreThanFiveMins
}
readonly property string navigationMetric: "navigation"
}

View File

@ -106,7 +106,7 @@ QtObject {
// Metrics
signal openMetricsEnablePopupRequested(string placement, var cb)
signal addCentralizedMetric(string eventName, var eventValue)
signal addCentralizedMetricIfEnabled(string eventName, var eventValue)
signal openAddEditSavedAddressesPopup(var params)
signal openDeleteSavedAddressesPopup(var params)

View File

@ -289,7 +289,7 @@ StatusWindow {
restoreAppState();
Global.openMetricsEnablePopupRequested.connect(openMetricsEnablePopup)
Global.addCentralizedMetric.connect(metricsStore.addCentralizedMetric)
Global.addCentralizedMetricIfEnabled.connect(metricsStore.addCentralizedMetricIfEnabled)
}
signal navigateTo(string path)
@ -381,8 +381,8 @@ StatusWindow {
onClosed: metricsPopupLoader.active = false
onToggleMetrics: {
applicationWindow.metricsStore.toggleCentralizedMetrics(enabled)
if(enabled) {
Global.addCentralizedMetric("usage_data_shared", {placement: metricsPopupLoader.item.placement})
if (enabled) {
Global.addCentralizedMetricIfEnabled("usage_data_shared", {placement: metricsPopupLoader.item.placement})
}
}
}