@creezio/observability
v0.26.0
Published
Observabilité — activité/CP + ops/fleet + fleet-collector (P25) + usage analytics (N6) + request-logs admin (O5)
Readme
@creezio/observability
Rôle
@creezio/observability regroupe les briques d'observabilité Creezio :
- store d'événements activité / plugin usage / control-plane ;
ApiMount/platform/observability;- ops journal desktop JSONL, règles de boot et émission d'événements ;
- agent flotte desktop opt-in, fleet activity et samples ;
- usage analytics UI/admin ;
- request logs API/MCP avec redaction ;
- UI admin analytics, request logs et endpoints ;
fleet-collectorautonome (creezio-fleet-collector).
Le package est marque-agnostique : endpoints, consentement, identité d'installation, chemins et labels UI sont injectés par la marque ou par env neutre.
Périmètre kit vs marque
Kit
- Fournit les schémas/stores observability.
- Enregistre les événements et agrégations génériques.
- Écrit un journal ops local best-effort, avec redaction.
- Produit les heartbeats/crash/bundles de flotte via hooks.
- Capture les logs API/MCP dans un ring buffer mémoire et miroir JSONL.
- Stocke et agrège les événements usage analytics.
- Fournit routes Hono ingest/admin et UI React admin.
- Fournit un collector HTTP autonome pour la flotte.
Marque
- Configure les DB adapters (
configureUsageAnalytics) et request logs (configureRequestLogs). - Configure les tokens UI analytics (
configureUsageAnalyticsUiBrand). - Appelle
initOpsJournal,track*etcreateFleetAgentdepuis l'app desktop. - Fournit consentement, install id, version, santé services, samples et commandes distantes.
- Monte les middlewares
requestLogApiMiddleware/requestLogMcpMiddleware. - Monte les routes analytics/admin avec auth owner.
- Déploie/configure le
fleet-collectoret ses secrets.
Installation/build
npm run build -w @creezio/observability
npm run typecheck -w @creezio/observability
npm run test:fleet-collector -w @creezio/observabilityLancement collector :
npm run fleet-collector -w @creezio/observability
# ou
npx creezio-fleet-collectorExports :
@creezio/observability: stores, helpers, ops, fleet, usage, request logs.@creezio/observability/ui: UI admin et tracker client.@creezio/observability/fleet-collector/*: collector autonome.
Configuration détaillée
Store observability et ApiMount
import {
createObservabilityApiMount,
createSqliteObservabilityStore,
} from "@creezio/observability";
const store = createSqliteObservabilityStore({ db });
const mount = createObservabilityApiMount(store);Usage analytics
import {
configureUsageAnalytics,
configureUsageAnalyticsUiBrand,
} from "@creezio/observability";
configureUsageAnalytics({
getWriteDb: () => db,
getDb: () => db,
tableExists: (name) => Boolean(db.prepare("SELECT 1 FROM sqlite_master WHERE name=?").get(name)),
});
configureUsageAnalyticsUiBrand({
aidAttr: "data-brand-aid",
titlebarNoDragClass: "brand-titlebar-no-drag",
mirrorFleetAction: (payload) => recordFleetAction(payload),
});configureUsageAnalytics({ getWriteDb }) est requis avant les routes et queries usage.
Request logs
import {
configureRequestLogs,
requestLogApiMiddleware,
requestLogMcpMiddleware,
} from "@creezio/observability";
configureRequestLogs({
getFleetStateDir: () => "/var/lib/brand/fleet-state",
});
api.use("/api/v1/*", requestLogApiMiddleware);
mcp.use("/mcp/*", requestLogMcpMiddleware);Si getFleetStateDir est absent, le package lit :
CREEZIO_FLEET_STATE_DIR- sinon toute variable
${envPrefix}_FLEET_STATE_DIRdérivée du manifest marque (posée par le host — aucun préfixe marque câblé dans le kit)
Ops journal
import {
initOpsJournal,
setOpsJournalHooks,
track,
trackDecision,
} from "@creezio/observability";
setOpsJournalHooks({
log: (scope, line) => logger.info(`[${scope}] ${line}`),
onAnomaly: (evt) => reportAnomaly(evt),
});
initOpsJournal(userDataDir, appVersion);
track({ level: "info", kind: "boot.start", ctx: { appVersion } });
trackDecision("service.meili", "ok", { durationMs: 120 });Le journal écrit dans <userData>/ops, garde une rétention bornée et ne doit jamais faire crasher l'app.
Préfixes d'événements ops (src/ops/types.ts) : le SoT d'émission reste
TF2EVENT (préfixe historique conservé pour ne pas casser les collecteurs
déployés) ; la lecture est dual-read via OPS_EVENT_PREFIXES (TF2EVENT ,
CertivanEVENT , …) — un parseur doit accepter tous les préfixes connus.
Fleet agent
import { createFleetAgent } from "@creezio/observability";
const fleet = createFleetAgent({
baseUrl: "https://fleet.example.com/i-token",
getConfig: () => telemetryConfig,
isScopeActive: (cfg, scope) => cfg.enabled && Boolean(cfg.scopes[scope]),
getInstallId: () => installId,
getAppVersion: () => appVersion,
getTunnelInfo: () => ({ slug: "demo", hostname: "demo.example.com" }),
log: (scope, line) => logger.info(`[${scope}] ${line}`),
});
fleet.startFleetAgent({
appKind: "server",
getHealth: async () => ({ next: "ok", hermes: "ok" }),
getRequestLogsSample: async () => listRequestLogs({ limit: 20 }).logs,
getHeartbeatExtras: async () => ({ dossierStats: { open: 12 } }),
});Fleet collector env
Le collector lit des env neutres, avec dual-read legacy :
CREEZIO_FLEET_PORT/FLEET_PORTCREEZIO_FLEET_INGEST_TOKEN/FLEET_INGEST_TOKENCREEZIO_FLEET_OPS_USER,_PASS,_TOKENCREEZIO_FLEET_DIR/FLEET_DIRFLEET_PUBLIC_DOMAIN/CREEZIO_FLEET_DOMAINCREEZIO_FLEET_TUNNEL_SUFFIXCREEZIO_FLEET_UI_TITLE,_MARK,_HOME_TITLE,_REALMCREEZIO_FLEET_UI_EXTRAS_TITLECREEZIO_FLEET_UI_ETAT_LABELS
Voir fleet-collector/README.md.
API publique avec exemples
Observability store / ApiMount
Endpoints de createObservabilityApiMount(store) :
GET /eventsPOST /eventsGET /usageGET /orgsGET /summary
curl "$API/platform/observability/events?kind=activity&limit=20"
curl -X POST "$API/platform/observability/events" \
-H "Content-Type: application/json" \
-d '{"kind":"activity","action":"page_view","userId":"u1","meta":{"path":"/dashboard"}}'Usage analytics routes
import {
createUsageAnalyticsAdminRoutes,
createUsageAnalyticsIngestRoutes,
} from "@creezio/observability";
api.route(
"/usage",
createUsageAnalyticsIngestRoutes({
getSession: async (c) => c.get("session") ?? null,
getUserKind: (userId) => getUser(userId)?.kind ?? "human",
}),
);
admin.route("/", createUsageAnalyticsAdminRoutes());Endpoints :
POST /usage/eventsGET /analytics/overviewGET /analytics/timelineGET /analytics/pagesGET /analytics/clicksGET /analytics/usersGET /analytics/eventsGET /analytics/productivityDELETE /analytics/events
Request logs
import {
createRequestLogsRoutes,
listRequestLogs,
} from "@creezio/observability";
admin.route("/admin", createRequestLogsRoutes());
const recentErrors = listRequestLogs({
source: "api",
errorsOnly: true,
limit: 50,
});Routes :
GET /request-logs?limit=100&source=api|mcp|all&q=...&errorsOnly=1DELETE /request-logs
UI
import {
AnalyticsClient,
RequestLogsClient,
UsageAnalyticsProvider,
} from "@creezio/observability/ui";
export function AdminObservability() {
return (
<UsageAnalyticsProvider session={{ userId: "u1", username: "Owner" }}>
<AnalyticsClient />
<RequestLogsClient />
</UsageAnalyticsProvider>
);
}Flux
Usage analytics
UsageAnalyticsProviderinstalle le tracker client.- Les clics et pages sont annotés via
aidAttr. - Les événements sont batchés vers
POST /usage/events. insertUsageEventsécrit en SQLite.- Les routes admin agrègent overview, timeline, pages, clicks, users et productivité.
- Optionnellement,
mirrorFleetActioncopie les actions vers le buffer flotte.
Request logs
- Les middlewares lisent requête/réponse de manière best-effort.
- Les secrets sont redacted par nom de clé et patterns de valeur.
pushRequestLogajoute au ring buffer mémoire.- Si un fleet state dir est configuré, un résumé JSONL est écrit pour l'agent flotte.
- L'UI admin lit/purge via
createRequestLogsRoutes.
Ops journal et fleet
initOpsJournalcrée un boot id et un fichier JSONL.track*enregistre décisions, anomalies, crashes et événements externes.createFleetAgentconstruit des heartbeats opt-in selon scopes.- L'agent poste
/heartbeat,/crash,/bundleet poll/commands. fleet-collectorstocke les données et expose une UI ops.
Intégration marques
- Configurer usage analytics avant les routes et avant l'UI tracker.
- Brancher request logs tôt dans la stack Hono, avant auth, mais redaction toujours active.
- Monter les routes admin derrière auth owner.
- Initialiser ops journal après logger et avant les services à diagnostiquer.
- Créer un
FleetAgentuniquement si la télémétrie opt-in est disponible. - Garder les extras métier opaques (
dossierStats, etc.) dansgetHeartbeatExtras. - Déployer
fleet-collectoravec tokens forts et Basic/Bearer ops.
Dépendances
- Runtime :
@creezio/api-kernel,@creezio/platform-core,hono. - UI peer :
react,next,lucide-react,recharts, Radix UI,clsx,tailwind-merge,class-variance-authority. - Node runtime pour ops/fleet collector :
fs,path,os, HTTP.
