@hadoku/logger
v1.4.4
Published
Unified logger for the hadoku ecosystem — one API across browser, Node/PM2, and Cloudflare Workers runtimes. Convention: structured stdout with `event=<name>` markers and optional telemetry push to monitoring-api.
Maintainers
Readme
@wolffm/logger
Unified logger for the hadoku ecosystem. One API across browser, Node/PM2, and Cloudflare Workers runtimes.
Consolidates three previously-fragmented loggers:
@wolffm/task-ui-components/src/utils/logger.ts(browser)workers/shared/cloudflareWorkerLogger.ts(CF Workers)services/mgmt-api/src/logger.ts(Node/PM2)
Convention
All terminal failures use logger.event(<name>, {...}) and render as a single greppable line in stdout:
[2026-05-30T05:12:33Z] [ERROR] [mgmt-api] scraper=hopper-redfin run_id=run_xyz error="captcha bootstrap" duration_ms=116270 event=run_failedOne grep event=run_failed across all service logs finds every terminal failure in the ecosystem.
Runtimes
Browser (@wolffm/logger/client)
Singleton, admin-gated (logs only visible when on localhost or localStorage.isAdmin === 'true'). ERROR-level always renders.
import { logger, configureLogger } from '@wolffm/logger/client';
// at app boot
configureLogger({ prefix: '[task-ui]' });
logger.info('mounted');
logger.error('save failed', { taskId });
logger.event('boot_failed', { phase: 'session-init' });
// UI sugar (preserved from old task-ui-components surface)
logger.component('mount', 'TaskList');
logger.theme('pink');
logger.apiResponse('POST', '/task/api/save', 200);Node / PM2 (@wolffm/logger/server)
import { createServerLogger } from '@wolffm/logger/server';
const log = createServerLogger({ service: 'mgmt-api' });
log.info('starting', { port: 4000 });
log.event('run_failed', { scraper: 'hopper-redfin', error: 'captcha' });Writes structured lines to process.stdout (info/warn/debug) and process.stderr (error). PM2 captures both.
Cloudflare Workers (@wolffm/logger/worker)
import { createWorkerLogger } from '@wolffm/logger/worker';
const log = createWorkerLogger({ service: 'edge-router' });
log.error('auth failed', { keyPrefix, route });
log.event('upstream_502', { backend: 'tunnel', durationMs });Routes per-level to console.error|warn|info|log. CF Workers Logs captures the stream.
Telemetry push (optional)
Wire a TelemetrySink to mirror ERROR/WARN entries into monitoring-api D1. Without a sink, the logger is stdout-only.
import { createMonitoringApiSink } from '@wolffm/logger';
import { createServerLogger } from '@wolffm/logger/server';
const sink = createMonitoringApiSink({
url: 'https://hadoku.me/health/api/telemetry',
userKey: process.env.MGMT_CRON_KEY!,
source: 'worker',
});
const log = createServerLogger({ service: 'mgmt-api', telemetrySink: sink });
log.event('cron_failed', { jobName, error }); // → stdout + monitoring-apiTrade-offs
- ERROR always renders, even below
minLevel. Silent errors defeat the convention. - Telemetry push is fire-and-forget; a failed POST never blocks the caller. Stdout copy is written first so PM2 logs always have the record.
- Context renders as flat
key=valpairs in stdout (greppable) and as a full JSON object in telemetry payloads (queryable). Quote-escaping handles values with spaces or=.
