Skip to content

Logging Plugin

The logging plugin provides console output for state changes, instance lifecycle events, and monitoring alerts. Reach for it when you want a passive, scannable record in the console or in CI logs — a running narrative of what your blocs are doing. For interactive, point-and-click inspection (state trees, diffs, time-travel) use DevTools instead; the two are complementary and can run side by side. Like all plugins, it observes every instance from outside — see Plugin Overview for the bigger picture.

Terminal window
pnpm add @blac/logging-plugin
import { LoggingPlugin } from '@blac/logging-plugin';
import { getPluginManager } from '@blac/core';
getPluginManager().install(new LoggingPlugin({ level: 'info' }), {
environment: 'development',
});

The default format: 'grouped' writes collapsible console.group entries for every event. Here is representative output for a short session — plugin install, a CartCubit state change, and its disposal:

Terminal window
▶ [BlaC] Plugin installed
Registered types: 1
Total instances: 0
▶ [BlaC] Created CartCubit#a1b2c3d4
Class: CartCubit
Instance ID: a1b2c3d4-e5f6-7890-abcd-ef1234567890
Initial state: { items: [], total: 0 }
▶ [BlaC] CartCubit#a1b2c3d4 state changed
Previous: { items: [], total: 0 }
Current: { items: [{ id: 1, name: "Widget", qty: 2 }], total: 19.98 }
▶ [BlaC] Disposed CartCubit#a1b2c3d4
Lifespan: 4.2s
State changes: 1
Final state: { items: [{ id: 1, name: "Widget", qty: 2 }], total: 19.98 }

Groups are collapsed by default — click the arrow to expand. Switch to format: 'simple' for a flat, line-per-event view:

Terminal window
[BlaC] Plugin installed (1 types, 0 instances)
[BlaC] Created CartCubit#a1b2c3d4
[BlaC] CartCubit#a1b2c3d4 state: {"items":[],"total":0} → {"items":[{"id":1,"name":"W...
[BlaC] Disposed CartCubit#a1b2c3d4 (lived 4.2s)

The simple format truncates state JSON at 50 characters, which keeps CI logs scannable.

Pass a LoggingPluginConfig object to the constructor:

new LoggingPlugin({
level: 'debug',
format: 'grouped',
include: ['CartCubit', 'AuthCubit'],
logStateChanges: true,
logLifecycle: true,
});
OptionTypeDefaultDescription
level'minimal' | 'info' | 'debug' | 'verbose''info'Log verbosity
format'simple' | 'grouped''grouped'Output format. 'grouped' uses console.group
loggerLoggerconsoleCustom logger implementation
prefixstring'[BlaC]'Prefix for log messages
logLifecyclebooleantrueLog instance creation and disposal
logStateChangesbooleantrueLog state changes
includeCallstackbooleanfalseShow call stacks for state changes
logPathsbooleanfalseLog the dirtytalk paths that changed
includestring[]Whitelist: only log these class names
excludestring[]Blacklist: skip these class names
filterFilterFnCustom filter function
OptionTypeDefaultDescription
instanceCountWarningThresholdnumber50Warn when instance count exceeds this
detectRapidLifecyclesbooleantrueDetect rapid create/dispose cycles
rapidLifecycleWindowMsnumber1000Time window for rapid lifecycle detection
rapidLifecycleThresholdnumber5Cycles in window to trigger warning
LevelLifecycleState changesMonitoring
minimalNoNoYes
infoYesYesYes
debugYesYes (detailed)Yes
verboseYesYes (full)Yes
new LoggingPlugin({
include: ['CartCubit', 'AuthCubit'], // only these
exclude: ['TimerCubit'], // or skip these
});
new LoggingPlugin({
filter: (ctx) => {
// ctx: { instance, className, instanceId }
return ctx.className !== 'InternalCubit'; // skip specific types
},
});

Replace console with your own logging implementation:

new LoggingPlugin({
logger: {
log: (...args) => myLogger.info(...args),
warn: (...args) => myLogger.warn(...args),
error: (...args) => myLogger.error(...args),
group: (label) => myLogger.group(label),
groupEnd: () => myLogger.groupEnd(),
},
});

Call logStats() to print a summary of the current registry state:

const logging = new LoggingPlugin({ level: 'info' });
getPluginManager().install(logging);
// later, in a debug context:
logging.logStats();

State change logging is automatically disabled if more than 1,000 changes per second are detected. This prevents flooding the console in high-frequency scenarios. A warning is logged when rate limiting kicks in.

  • Plugin Overview — the plugin catalog and the install API
  • DevTools — interactive inspection; pairs well with logging
  • Performance — diagnosing the emit storms the rate limiter guards against
  • Plugin Authoring — the hooks this plugin is built on