From d9e4bc4647480119812ca2cfe1e3481cd3923697 Mon Sep 17 00:00:00 2001 From: jbiskur Date: Wed, 8 Apr 2026 11:13:00 +0100 Subject: [PATCH] feat: configurable log levels for pulse and provision events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New LogLevelConfig options on PathwaysBuilder: - pulseSuccess (default: 'debug') — successful pulse emissions - pulseFailure (default: 'warn') — pulse emission failures - provisionSuccess (default: 'info') — virtual pathway registered - provisionFailure (default: 'error') — virtual pathway registration failed Structured context added to provision() logs: - success: { pathwayName, pathwayId, status, flowTypes } - failure: { pathwayName, url, status, body, phase } (now logged BEFORE the throw so NoopLogger consumers still get the crash message but structured loggers capture full context) Log levels propagated through PathwayPumpOptions.pulse to the data-pump PulseEmitter (requires @flowcore/data-pump with matching pulse log level support). Co-Authored-By: Claude Opus 4.6 (1M context) --- src/pathways/builder.ts | 57 +++++++++++++++++++++++++++---- src/pathways/pump/pathway-pump.ts | 10 +++++- src/pathways/pump/types.ts | 4 +++ 3 files changed, 63 insertions(+), 8 deletions(-) diff --git a/src/pathways/builder.ts b/src/pathways/builder.ts index ff9bf0b..642a656 100644 --- a/src/pathways/builder.ts +++ b/src/pathways/builder.ts @@ -107,11 +107,20 @@ export interface AuditWebhookSendOptions extends WebhookSendOptions { export type LogLevel = keyof Pick /** - * Configuration for log levels + * Configuration for log levels used by PathwaysBuilder for various operations. + * * @property writeSuccess Log level used when a write operation is successful. Defaults to 'info'. + * @property pulseSuccess Log level used when a pulse is successfully sent. Defaults to 'debug'. + * @property pulseFailure Log level used when a pulse emission fails. Defaults to 'warn'. + * @property provisionSuccess Log level used when virtual pathway provisioning succeeds. Defaults to 'info'. + * @property provisionFailure Log level used when virtual pathway provisioning fails. Defaults to 'error'. */ export type LogLevelConfig = { writeSuccess?: LogLevel + pulseSuccess?: LogLevel + pulseFailure?: LogLevel + provisionSuccess?: LogLevel + provisionFailure?: LogLevel } /** @@ -362,6 +371,10 @@ export class PathwaysBuilder< // Initialize log levels with defaults this.logLevel = { writeSuccess: logLevel?.writeSuccess ?? "info", + pulseSuccess: logLevel?.pulseSuccess ?? "debug", + pulseFailure: logLevel?.pulseFailure ?? "warn", + provisionSuccess: logLevel?.provisionSuccess ?? "info", + provisionFailure: logLevel?.provisionFailure ?? "error", } // Store configuration values for cloning @@ -1286,10 +1299,11 @@ export class PathwaysBuilder< if (this.pathwayName) { const flowTypes = [...new Set(registrations.map((r) => r.flowType))] const cpBaseUrl = this.pulseUrl + const url = `${cpBaseUrl}/api/v1/pathways/by-name/${encodeURIComponent(this.pathwayName)}` - const response = await fetch( - `${cpBaseUrl}/api/v1/pathways/by-name/${encodeURIComponent(this.pathwayName)}`, - { + let response: Response + try { + response = await fetch(url, { method: "PUT", headers: { "Content-Type": "application/json", @@ -1307,11 +1321,27 @@ export class PathwaysBuilder< flowTypes, }, }), - }, - ) + }) + } catch (err) { + const msg = err instanceof Error ? err.message : String(err) + this.logger[this.logLevel.provisionFailure]("Virtual pathway registration failed", { + pathwayName: this.pathwayName, + url, + error: msg, + phase: "network", + }) + throw new Error(`Failed to register virtual pathway "${this.pathwayName}": ${msg}`) + } if (!response.ok) { const text = await response.text().catch(() => "") + this.logger[this.logLevel.provisionFailure]("Virtual pathway registration failed", { + pathwayName: this.pathwayName, + url, + status: response.status, + body: text, + phase: "response", + }) throw new Error( `Failed to register virtual pathway "${this.pathwayName}": ${response.status} ${text}`, ) @@ -1319,10 +1349,11 @@ export class PathwaysBuilder< const result = await response.json() as { pathwayId: string; status: string } this.pathwayId = result.pathwayId - this.logger.info("Virtual pathway registered", { + this.logger[this.logLevel.provisionSuccess]("Virtual pathway registered", { pathwayName: this.pathwayName, pathwayId: this.pathwayId, status: result.status, + flowTypes, }) } } @@ -1350,9 +1381,21 @@ export class PathwaysBuilder< url: this.pulseUrl, intervalMs: this.pulseIntervalMs, pathwayId: this.pathwayId, + successLogLevel: this.logLevel.pulseSuccess, + failureLogLevel: this.logLevel.pulseFailure, }, } this.logger.info("Auto-configured pulse", { pathwayId: this.pathwayId, url: this.pulseUrl }) + } else if (options.pulse) { + // Respect explicit pulse config but inject log levels from builder config if not set + options = { + ...options, + pulse: { + ...options.pulse, + successLogLevel: options.pulse.successLogLevel ?? this.logLevel.pulseSuccess, + failureLogLevel: options.pulse.failureLogLevel ?? this.logLevel.pulseFailure, + }, + } } // If cluster active and not leader, don't start pump diff --git a/src/pathways/pump/pathway-pump.ts b/src/pathways/pump/pathway-pump.ts index d8cd086..9b20911 100644 --- a/src/pathways/pump/pathway-pump.ts +++ b/src/pathways/pump/pathway-pump.ts @@ -38,7 +38,13 @@ export class PathwayPump { private readonly bufferSize: number private readonly maxRedeliveryCount: number private readonly logger: Logger - private readonly pulseConfig?: { url: string; intervalMs?: number; pathwayId?: string } + private readonly pulseConfig?: { + url: string + intervalMs?: number + pathwayId?: string + successLogLevel?: "debug" | "info" | "warn" | "error" + failureLogLevel?: "debug" | "info" | "warn" | "error" + } private pumps: Map = new Map() private stateManagers: Map = new Map() @@ -164,6 +170,8 @@ export class PathwayPump { url: this.pulseConfig.url, intervalMs: this.pulseConfig.intervalMs, pathwayId: this.pulseConfig.pathwayId ?? "unknown", + successLogLevel: this.pulseConfig.successLogLevel, + failureLogLevel: this.pulseConfig.failureLogLevel, } } diff --git a/src/pathways/pump/types.ts b/src/pathways/pump/types.ts index 321fc20..928a0d7 100644 --- a/src/pathways/pump/types.ts +++ b/src/pathways/pump/types.ts @@ -18,6 +18,10 @@ export interface PathwayPumpOptions { intervalMs?: number /** Pathway ID for this pump */ pathwayId?: string + /** Log level for successful pulses. Defaults to 'debug'. */ + successLogLevel?: "debug" | "info" | "warn" | "error" + /** Log level for pulse failures. Defaults to 'warn'. */ + failureLogLevel?: "debug" | "info" | "warn" | "error" } }