HormoneTrack-web/js/util/app-log.js
Siphonight 491efef8eb v1.4.10 — portage initial de l'app Android v1.4.10
Portage navigateur complet de l'app Android HormoneTrack v1.4.10 :
- moteur PK fidèle (Estrannaise tables ODS, Transfem Science V3C,
  WHSAH fit Mona, Bateman) — paramètres identiques, invariants Android
  préservés (fixes #19-#23, #35, #52-#62), 121 tests Node épinglés
- calibration par période d'ester et par modèle affiché (#60/#61)
- UI 6 écrans + éditeur, CurveChart Canvas (zoom/pan fractionnaire,
  prévision, pics/creux, fuseau configurable), rappels web
  (Notification API), seuils d'alerte, i18n FR/EN
- sauvegarde JSON v2 compatible Android bidirectionnelle (rétrocompat v1)
- 100 % local : localStorage, aucun serveur applicatif, aucune télémétrie
- processus : scripts/check.sh (syntaxe, i18n, tests, E2E navigateur,
  smoke HTTP), docs séparées (README + DEVELOPPEMENT + CHANGELOG)
- dépôt GIT SÉPARÉ de l'Android : historique 100 % propre, versions
  alignées sur l'Android porté, changelogs indépendants

Non porté (impossible dans un navigateur, documenté §12) : agenda
récurrent, notifications onglet fermé, montre.
2026-09-08 14:34:58 +02:00

106 lines
3.6 KiB
JavaScript

/**
* ─────────────────────────────────────────────────────────────────────────────
* AppLog — journal de diagnostic (portage de `util/AppLog.kt`, v1.3.1).
*
* Ligne horodatée par événement notable (rappels, import/export, erreurs),
* buffer circulaire de MAX_LINES, persisté dans le localStorage (Android :
* `filesDir/debug-log.txt`). Exportable depuis Paramètres (« Logs de
* diagnostic ») pour le debug à distance — l'utilisateur joint le fichier à
* son rapport de bug.
*
* ⚠️ NE JAMAIS PROPAGER D'EXCEPTION depuis log() (fix Android v1.3.3, §14
* #45) : log() est appelé de partout, y compris dans des callbacks système —
* une erreur d'écriture (quota localStorage dépassé…) doit coûter AU PIRE
* une ligne de journal, jamais un crash.
* ─────────────────────────────────────────────────────────────────────────────
*/
import { store } from '../data/store.js';
/** Taille maximale du buffer circulaire (identique au Kotlin). */
export const MAX_LINES = 500;
/** Buffer mémoire (miroir de l'ArrayDeque Kotlin). */
let buffer = [];
/** Formatteur partagé — 2 chiffres. */
function pad(n) {
return String(n).padStart(2, '0');
}
/**
* Ligne horodatée : « 2026-09-08 12:34:56 [tag] message » (heure locale —
* même format qu'Android SimpleDateFormat "yyyy-MM-dd HH:mm:ss").
*
* @param {number} tsMs
* @param {string} tag
* @param {string} message
* @returns {string}
*/
export function formatLine(tsMs, tag, message) {
const d = new Date(tsMs);
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} `
+ `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())} `
+ `[${tag}] ${message}`;
}
/**
* Buffer circulaire : garde les MAX dernières lignes (pur — testable).
*
* @param {string[]} existing
* @param {number} max
* @returns {string[]}
*/
export function trimLines(existing, max) {
return existing.length <= max ? existing : existing.slice(existing.length - max);
}
/**
* Charge le journal persisté dans le buffer mémoire. À appeler une fois au
* démarrage — un journal corrompu ne doit jamais empêcher l'app de démarrer
* (on perd l'historique, pas le process).
*/
export function init() {
const raw = store.getDebugLog();
buffer = raw ? trimLines(raw.split('\n'), MAX_LINES) : [];
log('app', `démarrage — ${buffer.length} lignes de logs existantes`);
}
/**
* Journalise une ligne (buffer mémoire + persistance). Fail-safe : toute
* erreur d'IO est avalée (quota localStorage…).
*
* @param {string} tag
* @param {string} message
*/
export function log(tag, message) {
const line = formatLine(Date.now(), tag, message);
buffer = trimLines([...buffer, line], MAX_LINES);
try {
store.setDebugLog(buffer.join('\n'));
} catch (e) {
// Journalisation best-effort : ne jamais faire planter l'app pour un log
}
}
/** @returns {string} tout le journal (une ligne par \n). */
export function all() {
return buffer.join('\n');
}
/** @returns {number} nombre de lignes en buffer. */
export function count() {
return buffer.length;
}
/** Efface le journal (bouton Paramètres) puis journalise l'effacement. */
export function clear() {
buffer = [];
try {
store.setDebugLog('');
} catch (e) {
// idem : best-effort
}
log('app', 'logs effacés');
}