fix: sentry tracing

This commit is contained in:
devthejo 2025-06-23 00:07:49 +02:00
parent 8ba4056187
commit 4a0f3ab7ef
2 changed files with 217 additions and 215 deletions

View file

@ -346,65 +346,67 @@ export default async function trackLocation() {
if (count > 0) { if (count > 0) {
locationLogger.info(`Found ${count} pending records, forcing sync`); locationLogger.info(`Found ${count} pending records, forcing sync`);
const transaction = Sentry.startTransaction({ await Sentry.startSpan(
name: "force-sync-pending-records", {
op: "geolocation-sync", 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 { Sentry.addBreadcrumb({
const { userToken } = getAuthState(); message: "Forced sync completed",
const state = await BackgroundGeolocation.getState(); category: "geolocation",
if (userToken && state.enabled) { level: "info",
const records = await BackgroundGeolocation.sync(); data: {
locationLogger.debug("Forced sync result", { recordsCount: records?.length || 0,
recordsCount: records?.length || 0, hadToken: true,
}); wasEnabled: true,
},
});
Sentry.addBreadcrumb({ span.setStatus("ok");
message: "Forced sync completed", } else {
category: "geolocation", Sentry.addBreadcrumb({
level: "info", message: "Forced sync skipped",
data: { category: "geolocation",
recordsCount: records?.length || 0, level: "warning",
hadToken: true, data: {
wasEnabled: true, hasToken: !!userToken,
}, isEnabled: state.enabled,
}); },
});
transaction.setStatus("ok"); span.setStatus("cancelled");
} else { }
Sentry.addBreadcrumb({ } catch (error) {
message: "Forced sync skipped", locationLogger.error("Forced sync failed", {
category: "geolocation", error: error,
level: "warning", stack: error.stack,
data: { });
hasToken: !!userToken,
isEnabled: state.enabled,
},
});
transaction.setStatus("cancelled"); Sentry.captureException(error, {
} tags: {
} catch (error) { module: "track-location",
locationLogger.error("Forced sync failed", { operation: "force-sync-pending",
error: error, },
stack: error.stack, contexts: {
}); pendingRecords: { count },
},
});
Sentry.captureException(error, { span.setStatus("internal_error");
tags: { throw error; // Re-throw to ensure span captures the error
module: "track-location", }
operation: "force-sync-pending", },
}, );
contexts: {
pendingRecords: { count },
},
});
transaction.setStatus("internal_error");
} finally {
transaction.finish();
}
} }
} catch (error) { } catch (error) {
locationLogger.error("Failed to get pending records count", { locationLogger.error("Failed to get pending records count", {

View file

@ -12,176 +12,176 @@ const logger = createLogger({
// Background task to cancel expired notifications // Background task to cancel expired notifications
const backgroundTask = async () => { const backgroundTask = async () => {
const transaction = Sentry.startTransaction({ await Sentry.startSpan(
name: "auto-cancel-expired-notifications", {
op: "background-task", name: "auto-cancel-expired-notifications",
}); op: "background-task",
},
Sentry.getCurrentScope().setSpan(transaction); async (span) => {
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) {
try { try {
if (!notification || !notification.id) { logger.info("Starting auto-cancel expired notifications task");
logger.warn("Invalid notification object", { notification });
continue;
}
const expires = notification.data?.expires; Sentry.addBreadcrumb({
if (!expires) { message: "Auto-cancel task started",
continue; // Skip notifications without expiry category: "notifications",
} level: "info",
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, { // 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: { tags: {
module: "auto-cancel-expired", module: "auto-cancel-expired",
operation: "cancel-notification", operation: "background-task",
},
contexts: {
notification: {
id: notification?.id,
expires: notification?.data?.expires,
},
}, },
}); });
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 = () => { export const useAutoCancelExpired = () => {