From 6bfd232ff93d197bb3156a7fe0eec6289562f718 Mon Sep 17 00:00:00 2001 From: Daniel Henkel <9447057+dhenkel92@users.noreply.github.com> Date: Tue, 19 Dec 2023 11:48:16 +0100 Subject: [PATCH] feature: add tracing to achievement system (#935) --- common/achievement/create.ts | 6 ++++-- common/achievement/evaluate.ts | 6 +++++- common/achievement/index.ts | 39 +++++++++++++++++++++------------- common/notification/index.ts | 20 ++++++++++------- 4 files changed, 45 insertions(+), 26 deletions(-) diff --git a/common/achievement/create.ts b/common/achievement/create.ts index 52332a1d9..4234e79a3 100644 --- a/common/achievement/create.ts +++ b/common/achievement/create.ts @@ -1,8 +1,9 @@ import { Prisma } from '@prisma/client'; -import { Achievement_template, JsonFilter, achievement_template_for_enum } from '../../graphql/generated'; +import { Achievement_template, achievement_template_for_enum } from '../../graphql/generated'; import { ActionID, SpecificNotificationContext } from '../notification/actions'; import { prisma } from '../prisma'; import { TemplateSelectEnum, getAchievementTemplates } from './template'; +import tracer from '../logger/tracing'; async function findUserAchievement(templateId: number, userId: string, context: SpecificNotificationContext) { const keys = context ? Object.keys(context) : []; @@ -36,7 +37,8 @@ async function getOrCreateUserAchievement(template: Achieve return existingUserAchievement; } -async function createAchievement(currentTemplate: Achievement_template, userId: string, context: SpecificNotificationContext) { +const createAchievement = tracer.wrap('achievement.createAchievement', _createAchievement); +async function _createAchievement(currentTemplate: Achievement_template, userId: string, context: SpecificNotificationContext) { const templatesByGroup = await getAchievementTemplates(TemplateSelectEnum.BY_GROUP); const keys = Object.keys(context); const userAchievementsByGroup = await prisma.user_achievement.findMany({ diff --git a/common/achievement/evaluate.ts b/common/achievement/evaluate.ts index d1d72f10d..4f9466f25 100644 --- a/common/achievement/evaluate.ts +++ b/common/achievement/evaluate.ts @@ -6,9 +6,13 @@ import swan from '@onlabsorg/swan-js'; import { bucketCreatorDefs } from './bucket'; import { getLogger } from '../logger/logger'; import { getBucketContext } from './util'; +import tracer from '../logger/tracing'; + const logger = getLogger('Achievement'); -export async function evaluateAchievement( +export const evaluateAchievement = tracer.wrap('achievement.evaluateAchievement', _evaluateAchievement); + +async function _evaluateAchievement( condition: string, dataAggregation: ConditionDataAggregations, metrics: string[], diff --git a/common/achievement/index.ts b/common/achievement/index.ts index de0c3bd68..a908e1292 100644 --- a/common/achievement/index.ts +++ b/common/achievement/index.ts @@ -8,14 +8,16 @@ import { evaluateAchievement } from './evaluate'; import { AchievementToCheck, ActionEvent, ConditionDataAggregations, UserAchievementContext, UserAchievementTemplate } from './types'; import { createAchievement, getOrCreateUserAchievement } from './create'; import { actionTakenAt } from '../notification'; +import tracer from '../logger/tracing'; const logger = getLogger('Achievement'); -export async function rewardActionTaken(user: User, actionId: ID, context: SpecificNotificationContext) { +export const rewardActionTaken = tracer.wrap('achievement.rewardActionTaken', _rewardActionTaken); +async function _rewardActionTaken(user: User, actionId: ID, context: SpecificNotificationContext) { if (!isGamificationFeatureActive()) { return; } - const templatesForAction = await getTemplatesByAction(actionId); + const templatesForAction = await tracer.trace('achievement.getTemplatesByAction', () => getTemplatesByAction(actionId)); if (templatesForAction.length === 0) { logger.debug(`No achievement found for action '${actionId}'`); @@ -30,20 +32,27 @@ export async function rewardActionTaken(user: User, actionI user: user, context, }; - await trackEvent(actionEvent); - - for (const [, group] of templatesByGroups) { - let achievementToCheck: AchievementToCheck; - for (const template of group) { - const userAchievement = await getOrCreateUserAchievement(template, user.userID, context); - if (userAchievement.achievedAt === null || userAchievement.recordValue) { - achievementToCheck = userAchievement; - break; + await tracer.trace('achievement.trackEvent', () => trackEvent(actionEvent)); + + for (const [groupName, group] of templatesByGroups) { + await tracer.trace('achievement.evaluateAchievementGroups', async (span) => { + span.setTag('achievement.group', groupName); + let achievementToCheck: AchievementToCheck; + for (const template of group) { + const userAchievement = await tracer.trace('achievement.getOrCreateUserAchievement', () => + getOrCreateUserAchievement(template, user.userID, context) + ); + if (userAchievement.achievedAt === null || userAchievement.recordValue) { + achievementToCheck = userAchievement; + break; + } } - } - if (achievementToCheck) { - await checkUserAchievement(achievementToCheck as UserAchievementTemplate, actionEvent); - } + span.setTag('achievement.foundToCheck', !!achievementToCheck); + if (achievementToCheck) { + span.setTag('achievement.id', achievementToCheck.id); + await tracer.trace('achievement.checkUserAchievement', () => checkUserAchievement(achievementToCheck as UserAchievementTemplate, actionEvent)); + } + }); } } diff --git a/common/notification/index.ts b/common/notification/index.ts index 285e16585..305d22949 100644 --- a/common/notification/index.ts +++ b/common/notification/index.ts @@ -14,7 +14,7 @@ import { Channels } from '../../graphql/types/preferences'; import { ALL_PREFERENCES } from './defaultPreferences'; import assert from 'assert'; import { Prisma } from '@prisma/client'; -import { addTagsToActiveSpan } from '../logger/tracing'; +import tracer, { addTagsToActiveSpan } from '../logger/tracing'; import * as Achievement from '../../common/achievement'; const logger = getLogger('Notification'); @@ -397,14 +397,17 @@ export async function actionTaken( attachments?: AttachmentGroup, noDuplicates = false ) { - if (!user.active) { - logger.debug(`No action '${actionId}' taken for User(${user.userID}) as the account is deactivated`); - return; - } + return await tracer.trace('notification.actionTaken', async (span) => { + span.setTag('actionId', actionId); - await Achievement.rewardActionTaken(user, actionId, notificationContext); + if (!user.active) { + logger.debug(`No action '${actionId}' taken for User(${user.userID}) as the account is deactivated`); + return; + } - return await actionTakenAt(new Date(), user, actionId, notificationContext, false, noDuplicates, attachments); + await Achievement.rewardActionTaken(user, actionId, notificationContext); + return await actionTakenAt(new Date(), user, actionId, notificationContext, false, noDuplicates, attachments); + }); } /* actionTakenAt is the mighty variant of actionTaken: @@ -443,7 +446,8 @@ If 'noDuplicates' is set, a Notification will be ignored if a Notification alrea Otherwise a Notification will just be sent multiple times. */ -export async function actionTakenAt( +export const actionTakenAt = tracer.wrap('notification.actionTakenAt', _actionTakenAt); +export async function _actionTakenAt( at: Date, user: User, actionId: ID,