feat: frontend LOG_LEVEL support via logger utility (#209)
- Inject LOG_LEVEL at build time via Vite define (__LOG_LEVEL__, default: warn) - Create frontend logger utility (frontend/src/utils/logger.ts) mirroring backend API - Replace all console.error calls with log.error in MedicationsPage, AppContext, Auth - Supports levels: silent > error > warn > info > debug Closes #205
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { createContext, type ReactNode, useCallback, useContext, useEffect, useRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { log } from "../utils/logger";
|
||||
import { ConfirmModal } from "./ConfirmModal";
|
||||
import { PasswordInput } from "./PasswordInput";
|
||||
|
||||
@@ -109,7 +110,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
||||
}
|
||||
setLoading(false);
|
||||
} catch (err) {
|
||||
console.error(`Failed to fetch auth state (attempt ${retryCount + 1}/${maxRetries + 1}):`, err);
|
||||
log.error(`Failed to fetch auth state (attempt ${retryCount + 1}/${maxRetries + 1}):`, err);
|
||||
|
||||
// Retry on connection errors or 5xx errors (server might be restarting)
|
||||
if (retryCount < maxRetries) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import { useAuth } from "../components/Auth";
|
||||
import { useCollapsedDays, useDoses, useMedications, useRefill, useSettings, useShare } from "../hooks";
|
||||
import type { Coverage, Medication, ScheduleEvent, StockThresholds } from "../types";
|
||||
import { getSystemLocale } from "../utils/formatters";
|
||||
import { log } from "../utils/logger";
|
||||
import { buildSchedulePreview, calculateCoverage, computeMissedPastDoseIds, isDoseDismissed } from "../utils/schedule";
|
||||
|
||||
// =============================================================================
|
||||
@@ -514,7 +515,7 @@ export function AppProvider({ children }: { children: React.ReactNode }) {
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
} catch (err) {
|
||||
console.error("Export error:", err);
|
||||
log.error("Export error:", err);
|
||||
}
|
||||
setExporting(false);
|
||||
},
|
||||
@@ -568,7 +569,7 @@ export function AppProvider({ children }: { children: React.ReactNode }) {
|
||||
try {
|
||||
data = text ? JSON.parse(text) : {};
|
||||
} catch {
|
||||
console.error("Import response parse error:", text);
|
||||
log.error("Import response parse error:", text);
|
||||
alert(`${t("exportImport.importError")}: Server returned invalid response`);
|
||||
return;
|
||||
}
|
||||
@@ -590,7 +591,7 @@ export function AppProvider({ children }: { children: React.ReactNode }) {
|
||||
settingsHook.loadSettings();
|
||||
doses.loadTakenDoses();
|
||||
} catch (err) {
|
||||
console.error("Import error:", err);
|
||||
log.error("Import error:", err);
|
||||
alert(t("exportImport.importError"));
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import { useMedicationForm, useUnsavedChangesWarning } from "../hooks";
|
||||
import type { DoseUnit, Medication } from "../types";
|
||||
import { DOSE_UNITS, FIELD_LIMITS, getPackageSize } from "../types";
|
||||
import { combineDateAndTime, formatDateTime, formatNumber } from "../utils/formatters";
|
||||
import { log } from "../utils/logger";
|
||||
|
||||
export function MedicationsPage() {
|
||||
const { t } = useTranslation();
|
||||
@@ -299,7 +300,7 @@ export function MedicationsPage() {
|
||||
setOriginalForm(form);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Save error:", err);
|
||||
log.error("Save error:", err);
|
||||
alert(err instanceof Error && err.message ? err.message : t("common.saveFailed"));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Frontend logger that respects LOG_LEVEL (injected at build time via Vite define).
|
||||
* Mirrors the backend logger API so usage is consistent across the stack.
|
||||
*
|
||||
* Levels (high → low): silent > error > warn > info > debug
|
||||
* Default: "warn" — only warn and error messages are shown.
|
||||
*/
|
||||
|
||||
declare const __LOG_LEVEL__: string;
|
||||
|
||||
const LOG_LEVELS: Record<string, number> = {
|
||||
silent: 50,
|
||||
error: 40,
|
||||
warn: 30,
|
||||
info: 20,
|
||||
debug: 10,
|
||||
};
|
||||
|
||||
const configuredLevel = typeof __LOG_LEVEL__ !== "undefined" ? __LOG_LEVEL__.toLowerCase() : "warn";
|
||||
const threshold = LOG_LEVELS[configuredLevel] ?? LOG_LEVELS.warn;
|
||||
|
||||
function shouldLog(level: string): boolean {
|
||||
return (LOG_LEVELS[level] ?? 0) >= threshold;
|
||||
}
|
||||
|
||||
export const log = {
|
||||
debug(...args: unknown[]): void {
|
||||
if (shouldLog("debug")) console.debug(...args);
|
||||
},
|
||||
info(...args: unknown[]): void {
|
||||
if (shouldLog("info")) console.info(...args);
|
||||
},
|
||||
warn(...args: unknown[]): void {
|
||||
if (shouldLog("warn")) console.warn(...args);
|
||||
},
|
||||
error(...args: unknown[]): void {
|
||||
if (shouldLog("error")) console.error(...args);
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user