From 4a0f3ab7effd79f75efd976f5fd9e1d1531e5b19 Mon Sep 17 00:00:00 2001 From: devthejo Date: Mon, 23 Jun 2025 00:07:49 +0200 Subject: [PATCH] fix: sentry tracing --- src/location/trackLocation.js | 110 ++++----- src/notifications/autoCancelExpired.js | 322 ++++++++++++------------- 2 files changed, 217 insertions(+), 215 deletions(-) diff --git a/src/location/trackLocation.js b/src/location/trackLocation.js index e6e63db..9eb62ce 100644 --- a/src/location/trackLocation.js +++ b/src/location/trackLocation.js @@ -346,65 +346,67 @@ export default async function trackLocation() { if (count > 0) { locationLogger.info(`Found ${count} pending records, forcing sync`); - const transaction = Sentry.startTransaction({ - name: "force-sync-pending-records", - op: "geolocation-sync", - }); + await Sentry.startSpan( + { + name: "force-sync-pending-records", + op: "geolocation-sync", + }, + async (span) => { + try { + const { userToken } = getAuthState(); + const state = await BackgroundGeolocation.getState(); + if (userToken && state.enabled) { + const records = await BackgroundGeolocation.sync(); + locationLogger.debug("Forced sync result", { + recordsCount: records?.length || 0, + }); - try { - const { userToken } = getAuthState(); - const state = await BackgroundGeolocation.getState(); - if (userToken && state.enabled) { - const records = await BackgroundGeolocation.sync(); - locationLogger.debug("Forced sync result", { - recordsCount: records?.length || 0, - }); + Sentry.addBreadcrumb({ + message: "Forced sync completed", + category: "geolocation", + level: "info", + data: { + recordsCount: records?.length || 0, + hadToken: true, + wasEnabled: true, + }, + }); - Sentry.addBreadcrumb({ - message: "Forced sync completed", - category: "geolocation", - level: "info", - data: { - recordsCount: records?.length || 0, - hadToken: true, - wasEnabled: true, - }, - }); + span.setStatus("ok"); + } else { + Sentry.addBreadcrumb({ + message: "Forced sync skipped", + category: "geolocation", + level: "warning", + data: { + hasToken: !!userToken, + isEnabled: state.enabled, + }, + }); - transaction.setStatus("ok"); - } else { - Sentry.addBreadcrumb({ - message: "Forced sync skipped", - category: "geolocation", - level: "warning", - data: { - hasToken: !!userToken, - isEnabled: state.enabled, - }, - }); + span.setStatus("cancelled"); + } + } catch (error) { + locationLogger.error("Forced sync failed", { + error: error, + stack: error.stack, + }); - transaction.setStatus("cancelled"); - } - } catch (error) { - locationLogger.error("Forced sync failed", { - error: error, - stack: error.stack, - }); + Sentry.captureException(error, { + tags: { + module: "track-location", + operation: "force-sync-pending", + }, + contexts: { + pendingRecords: { count }, + }, + }); - Sentry.captureException(error, { - tags: { - module: "track-location", - operation: "force-sync-pending", - }, - contexts: { - pendingRecords: { count }, - }, - }); - - transaction.setStatus("internal_error"); - } finally { - transaction.finish(); - } + span.setStatus("internal_error"); + throw error; // Re-throw to ensure span captures the error + } + }, + ); } } catch (error) { locationLogger.error("Failed to get pending records count", { diff --git a/src/notifications/autoCancelExpired.js b/src/notifications/autoCancelExpired.js index e59f431..8f0169d 100644 --- a/src/notifications/autoCancelExpired.js +++ b/src/notifications/autoCancelExpired.js @@ -12,176 +12,176 @@ const logger = createLogger({ // Background task to cancel expired notifications const backgroundTask = async () => { - const transaction = Sentry.startTransaction({ - name: "auto-cancel-expired-notifications", - op: "background-task", - }); - - Sentry.getCurrentScope().setSpan(transaction); - - try { - logger.info("Starting auto-cancel expired notifications task"); - - Sentry.addBreadcrumb({ - message: "Auto-cancel task started", - category: "notifications", - level: "info", - }); - - // Get displayed notifications with timeout protection - const getNotificationsSpan = transaction.startChild({ - op: "get-displayed-notifications", - description: "Getting displayed notifications", - }); - - let notifications; - try { - // Add timeout protection for the API call - notifications = await Promise.race([ - notifee.getDisplayedNotifications(), - new Promise((_, reject) => - setTimeout( - () => reject(new Error("Timeout getting notifications")), - 10000, - ), - ), - ]); - getNotificationsSpan.setStatus("ok"); - } catch (error) { - getNotificationsSpan.setStatus("internal_error"); - throw error; - } finally { - getNotificationsSpan.finish(); - } - - if (!Array.isArray(notifications)) { - logger.warn("No notifications array received", { notifications }); - Sentry.addBreadcrumb({ - message: "No notifications array received", - category: "notifications", - level: "warning", - }); - return; - } - - const currentTime = Math.round(new Date() / 1000); - let cancelledCount = 0; - let errorCount = 0; - - logger.info("Processing notifications", { - totalNotifications: notifications.length, - currentTime, - }); - - Sentry.addBreadcrumb({ - message: "Processing notifications", - category: "notifications", - level: "info", - data: { - totalNotifications: notifications.length, - currentTime, - }, - }); - - // Process notifications with individual error handling - for (const notification of notifications) { + await Sentry.startSpan( + { + name: "auto-cancel-expired-notifications", + op: "background-task", + }, + async (span) => { try { - if (!notification || !notification.id) { - logger.warn("Invalid notification object", { notification }); - continue; - } + logger.info("Starting auto-cancel expired notifications task"); - const expires = notification.data?.expires; - if (!expires) { - continue; // Skip notifications without expiry - } - - if (typeof expires !== "number" || expires < currentTime) { - logger.debug("Cancelling expired notification", { - notificationId: notification.id, - expires, - currentTime, - expired: expires < currentTime, - }); - - // Cancel notification with timeout protection - await Promise.race([ - notifee.cancelNotification(notification.id), - new Promise((_, reject) => - setTimeout( - () => reject(new Error("Timeout cancelling notification")), - 5000, - ), - ), - ]); - - cancelledCount++; - - Sentry.addBreadcrumb({ - message: "Notification cancelled", - category: "notifications", - level: "info", - data: { - notificationId: notification.id, - expires, - }, - }); - } - } catch (notificationError) { - errorCount++; - logger.error("Failed to process notification", { - error: notificationError, - notificationId: notification?.id, + Sentry.addBreadcrumb({ + message: "Auto-cancel task started", + category: "notifications", + level: "info", }); - Sentry.captureException(notificationError, { + // Get displayed notifications with timeout protection + let notifications; + await Sentry.startSpan( + { + op: "get-displayed-notifications", + description: "Getting displayed notifications", + }, + async (getNotificationsSpan) => { + try { + // Add timeout protection for the API call + notifications = await Promise.race([ + notifee.getDisplayedNotifications(), + new Promise((_, reject) => + setTimeout( + () => reject(new Error("Timeout getting notifications")), + 10000, + ), + ), + ]); + getNotificationsSpan.setStatus("ok"); + } catch (error) { + getNotificationsSpan.setStatus("internal_error"); + throw error; + } + }, + ); + + if (!Array.isArray(notifications)) { + logger.warn("No notifications array received", { notifications }); + Sentry.addBreadcrumb({ + message: "No notifications array received", + category: "notifications", + level: "warning", + }); + return; + } + + const currentTime = Math.round(new Date() / 1000); + let cancelledCount = 0; + let errorCount = 0; + + logger.info("Processing notifications", { + totalNotifications: notifications.length, + currentTime, + }); + + Sentry.addBreadcrumb({ + message: "Processing notifications", + category: "notifications", + level: "info", + data: { + totalNotifications: notifications.length, + currentTime, + }, + }); + + // Process notifications with individual error handling + for (const notification of notifications) { + try { + if (!notification || !notification.id) { + logger.warn("Invalid notification object", { notification }); + continue; + } + + const expires = notification.data?.expires; + if (!expires) { + continue; // Skip notifications without expiry + } + + if (typeof expires !== "number" || expires < currentTime) { + logger.debug("Cancelling expired notification", { + notificationId: notification.id, + expires, + currentTime, + expired: expires < currentTime, + }); + + // Cancel notification with timeout protection + await Promise.race([ + notifee.cancelNotification(notification.id), + new Promise((_, reject) => + setTimeout( + () => reject(new Error("Timeout cancelling notification")), + 5000, + ), + ), + ]); + + cancelledCount++; + + Sentry.addBreadcrumb({ + message: "Notification cancelled", + category: "notifications", + level: "info", + data: { + notificationId: notification.id, + expires, + }, + }); + } + } catch (notificationError) { + errorCount++; + logger.error("Failed to process notification", { + error: notificationError, + notificationId: notification?.id, + }); + + Sentry.captureException(notificationError, { + tags: { + module: "auto-cancel-expired", + operation: "cancel-notification", + }, + contexts: { + notification: { + id: notification?.id, + expires: notification?.data?.expires, + }, + }, + }); + } + } + + logger.info("Auto-cancel task completed", { + totalNotifications: notifications.length, + cancelledCount, + errorCount, + }); + + Sentry.addBreadcrumb({ + message: "Auto-cancel task completed", + category: "notifications", + level: "info", + data: { + totalNotifications: notifications.length, + cancelledCount, + errorCount, + }, + }); + + span.setStatus("ok"); + } catch (error) { + logger.error("Auto-cancel task failed", { error }); + + Sentry.captureException(error, { tags: { module: "auto-cancel-expired", - operation: "cancel-notification", - }, - contexts: { - notification: { - id: notification?.id, - expires: notification?.data?.expires, - }, + operation: "background-task", }, }); + + span.setStatus("internal_error"); + throw error; // Re-throw to be handled by caller } - } - - logger.info("Auto-cancel task completed", { - totalNotifications: notifications.length, - cancelledCount, - errorCount, - }); - - Sentry.addBreadcrumb({ - message: "Auto-cancel task completed", - category: "notifications", - level: "info", - data: { - totalNotifications: notifications.length, - cancelledCount, - errorCount, - }, - }); - - transaction.setStatus("ok"); - } catch (error) { - logger.error("Auto-cancel task failed", { error }); - - Sentry.captureException(error, { - tags: { - module: "auto-cancel-expired", - operation: "background-task", - }, - }); - - transaction.setStatus("internal_error"); - throw error; // Re-throw to be handled by caller - } finally { - transaction.finish(); - } + }, + ); }; export const useAutoCancelExpired = () => {