Browse Source

feat(logging): enhance debug logging across app

Improves application logging and error tracking:
- Add structured logging in main.common.ts for app initialization
- Enhance API error handling with detailed context in services
- Add deep link debugging in Capacitor platform
- Improve plan service logging with retry information
- Update endorser server logs for better cache debugging

Technical changes:
- Replace console.error with info for non-critical cache misses
- Add component context to global error handler
- Add detailed logging for plan loading and retries
- Improve deep link route matching logs
- Add mount state logging for Capacitor

This improves debugging capabilities across web and mobile platforms.
deep_linking
Matthew Raymer 1 day ago
parent
commit
cee7a6ded3
  1. 10
      src/libs/endorserServer.ts
  2. 48
      src/main.capacitor.ts
  3. 37
      src/main.common.ts
  4. 11
      src/services/api.ts
  5. 80
      src/services/plan.ts
  6. 3
      src/views/ClaimView.vue
  7. 4
      vite.config.common.mts

10
src/libs/endorserServer.ts

@ -649,19 +649,19 @@ export async function getPlanFromCache(
cred = resp.data.data[0];
planCache.set(handleId, cred);
} else {
console.error(
"Failed to load plan with handle",
console.info(
"[EndorserServer] Plan cache is empty for handle",
handleId,
" Got data:",
resp.data,
JSON.stringify(resp.data),
);
}
} catch (error) {
console.error(
"Failed to load plan with handle",
"[EndorserServer] Failed to load plan with handle",
handleId,
" Got error:",
error,
JSON.stringify(error),
);
}
}

48
src/main.capacitor.ts

@ -5,6 +5,9 @@ import { handleApiError } from "./services/api";
import { loadPlanWithRetry } from "./services/plan";
import { Capacitor } from '@capacitor/core';
console.log("[Capacitor] Starting initialization");
console.log("[Capacitor] Platform:", process.env.VITE_PLATFORM);
const app = initializeApp();
// Store initial deep link if app is not ready
@ -20,44 +23,32 @@ window.addEventListener('unhandledrejection', (event) => {
// Create reusable handler function
const handleDeepLink = async (data: { url: string }) => {
try {
if (Capacitor.isNativePlatform()) {
console.log("[Capacitor Deep Link] START Handler");
console.log("[Capacitor Deep Link] Received URL:", data.url);
}
console.log("[Capacitor Deep Link] START Handler");
console.log("[Capacitor Deep Link] Received URL:", data.url);
// Wait for app to be mounted
if (!app._container) {
console.log("[Capacitor Deep Link] Waiting for app mount");
await new Promise<void>((resolve) => {
const interval = setInterval(() => {
if (app._container) {
clearInterval(interval);
resolve();
}
}, 100);
});
}
// Wait for router to be ready
await router.isReady();
const url = new URL(data.url);
const path = url.pathname.substring(1);
if (Capacitor.isNativePlatform()) {
console.log("[Capacitor Deep Link] Parsed path:", path);
// Parse the custom URL scheme
const parts = data.url.split('://');
if (parts.length !== 2) {
throw new Error('Invalid URL format');
}
const path = parts[1]; // This will be "claim/01JMAAFZRNSRTQ0EBSD70A8E1H"
console.log("[Capacitor Deep Link] Parsed path:", path);
// Map parameterized routes
const paramRoutes = {
'claim': /^claim\/(.+)$/,
'claim': /^claim\/(.+)$/, // Updated pattern without leading slash
};
// Check if path matches any parameterized route
for (const [routeName, pattern] of Object.entries(paramRoutes)) {
const match = path.match(pattern);
if (match) {
if (Capacitor.isNativePlatform()) {
console.log(`[Capacitor Deep Link] Matched route: ${routeName}, param: ${match[1]}`);
}
await router.push({
console.log(`[Capacitor Deep Link] Matched route: ${routeName}, param: ${match[1]}`);
await router.replace({
name: routeName,
params: { id: match[1] }
});
@ -65,7 +56,7 @@ const handleDeepLink = async (data: { url: string }) => {
}
}
await router.push('/' + path);
await router.replace('/' + path);
} catch (error) {
console.error("[Capacitor Deep Link] Error:", error);
handleApiError(error, 'deep-link');
@ -75,5 +66,6 @@ const handleDeepLink = async (data: { url: string }) => {
// Register listener
App.addListener("appUrlOpen", handleDeepLink);
// Mount app
console.log("[Capacitor] Mounting app");
app.mount("#app");
console.log("[Capacitor] App mounted");

37
src/main.common.ts

@ -11,12 +11,17 @@ import Camera from "simple-vue-camera";
// Global Error Handler
function setupGlobalErrorHandler(app: VueApp) {
console.log("[App Init] Setting up global error handler");
app.config.errorHandler = (
err: unknown,
instance: ComponentPublicInstance | null,
info: string
) => {
console.error("Ouch! Global Error Handler.", err, info, instance);
console.error("[App Error] Global Error Handler:", {
error: err,
info,
component: instance?.$options.name || 'unknown'
});
alert(
(err instanceof Error ? err.message : "Something bad happened") +
" - Try reloading or restarting the app."
@ -26,15 +31,31 @@ function setupGlobalErrorHandler(app: VueApp) {
// Function to initialize the app
export function initializeApp() {
const app = createApp(App)
.component("fa", FontAwesomeIcon)
.component("camera", Camera)
.use(createPinia())
.use(VueAxios, axios)
.use(router)
.use(Notifications);
console.log("[App Init] Starting app initialization");
console.log("[App Init] Platform:", process.env.VITE_PLATFORM);
const app = createApp(App);
console.log("[App Init] Vue app created");
app.component("fa", FontAwesomeIcon)
.component("camera", Camera);
console.log("[App Init] Components registered");
const pinia = createPinia();
app.use(pinia);
console.log("[App Init] Pinia store initialized");
app.use(VueAxios, axios);
console.log("[App Init] Axios initialized");
app.use(router);
console.log("[App Init] Router initialized");
app.use(Notifications);
console.log("[App Init] Notifications initialized");
setupGlobalErrorHandler(app);
console.log("[App Init] App initialization complete");
return app;
}

11
src/services/api.ts

@ -1,6 +1,15 @@
export const handleApiError = (error: any, endpoint: string) => {
if (process.env.VITE_PLATFORM === 'capacitor') {
console.error(`[Capacitor API Error] ${endpoint}:`, error);
console.error(`[Capacitor API Error] ${endpoint}:`, {
message: error.message,
status: error.response?.status,
data: error.response?.data,
config: {
url: error.config?.url,
method: error.config?.method,
headers: error.config?.headers
}
});
}
// Specific handling for rate limits

80
src/services/plan.ts

@ -1,19 +1,71 @@
export const loadPlanWithRetry = async (handle: string, retries = 3) => {
for (let i = 0; i < retries; i++) {
try {
const plan = await loadPlan(handle);
if (plan) return plan;
} catch (err) {
console.warn(`[Plan Load] Attempt ${i + 1} failed for ${handle}`);
if (i === retries - 1) throw err;
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
import axios from 'axios';
interface PlanResponse {
data?: any;
status?: number;
error?: string;
}
export const loadPlanWithRetry = async (handle: string, retries = 3): Promise<PlanResponse> => {
try {
console.log(`[Plan Service] Loading plan ${handle}, attempt 1/${retries}`);
console.log(`[Plan Service] Context: Deep link handle=${handle}, isClaimFlow=${handle.includes('claim')}`);
// Different endpoint if this is a claim flow
const response = await loadPlan(handle);
console.log(`[Plan Service] Plan ${handle} loaded successfully:`, {
status: response?.status,
headers: response?.headers,
data: response?.data
});
return response;
} catch (error: any) {
console.error(`[Plan Service] Error loading plan ${handle}:`, {
message: error.message,
status: error.response?.status,
statusText: error.response?.statusText,
data: error.response?.data,
headers: error.response?.headers,
config: {
url: error.config?.url,
method: error.config?.method,
baseURL: error.config?.baseURL,
headers: error.config?.headers
}
});
if (retries > 1) {
console.log(`[Plan Service] Retrying plan ${handle}, ${retries-1} attempts remaining`);
await new Promise(resolve => setTimeout(resolve, 1000));
return loadPlanWithRetry(handle, retries - 1);
}
return {
error: `Failed to load plan ${handle} after ${4-retries} attempts: ${error.message}`,
status: error.response?.status
};
}
};
const loadPlan = async (handle: string) => {
// Implement your plan loading logic here
// This is a placeholder - replace with actual implementation
const response = await fetch(`/api/plans/${handle}`);
return response.json();
export const loadPlan = async (handle: string): Promise<PlanResponse> => {
console.log(`[Plan Service] Making API request for plan ${handle}`);
const endpoint = handle.includes('claim')
? `/api/claims/${handle}`
: `/api/plans/${handle}`;
console.log(`[Plan Service] Using endpoint: ${endpoint}`);
try {
const response = await axios.get(endpoint);
return response;
} catch (error: any) {
console.error(`[Plan Service] API request failed for ${handle}:`, {
endpoint,
error: error.message,
response: error.response?.data
});
throw error;
}
};

3
src/views/ClaimView.vue

@ -585,6 +585,7 @@ export default class ClaimView extends Vue {
}
async created() {
console.log("ClaimView created");
const settings = await retrieveSettingsForActiveAccount();
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";
@ -659,6 +660,7 @@ export default class ClaimView extends Vue {
}
async loadClaim(claimId: string, userDid: string) {
console.log("[ClaimView] loadClaim called with claimId:", claimId);
const urlPath = libsUtil.isGlobalUri(claimId)
? "/api/claim/byHandle/"
: "/api/claim/";
@ -666,6 +668,7 @@ export default class ClaimView extends Vue {
const headers = await serverUtil.getHeaders(userDid);
try {
console.log("[ClaimView] Making API request to:", url);
const resp = await this.axios.get(url, { headers });
if (resp.status === 200) {
this.veriClaim = resp.data;

4
vite.config.common.mts

@ -17,6 +17,9 @@ export async function createBuildConfig(mode: string) {
const isCapacitor = mode === "capacitor";
const isPyWebView = mode === "pywebview";
// Explicitly set platform
process.env.VITE_PLATFORM = mode;
if (isElectron || isPyWebView || isCapacitor) {
process.env.VITE_PWA_ENABLED = 'false';
}
@ -35,6 +38,7 @@ export async function createBuildConfig(mode: string) {
},
define: {
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
'process.env.VITE_PLATFORM': JSON.stringify(mode),
'process.env.VITE_PWA_ENABLED': JSON.stringify(!(isElectron || isPyWebView || isCapacitor)),
__dirname: isElectron ? JSON.stringify(process.cwd()) : '""',
},

Loading…
Cancel
Save