logger plugin - greydragon888/real-router GitHub Wiki
@real-router/logger-plugin
1. Overview
- Name: Logger Plugin
- Package:
@real-router/logger-plugin - Purpose: Logging router events using native console API for debugging and navigation monitoring.
- Typical scenarios: Debugging transitions in development mode; monitoring navigation performance; analyzing route parameter changes.
- Note: Uses native
consolemethods (log, warn, error) instead of external logger package.
2. Installation and Setup
npm install @real-router/logger-plugin
# or
pnpm add @real-router/logger-plugin
import { createRouter } from "@real-router/core";
import { loggerPluginFactory } from "@real-router/logger-plugin";
const router = createRouter(routes);
router.usePlugin(loggerPluginFactory());
3. Configuration Options
The plugin uses default configuration from DEFAULT_CONFIG. All logging is done via native console methods.
| Option | Type | Default | Description |
|---|---|---|---|
level |
LogLevel |
"all" |
Logging level: "all", "transitions", "errors", "none" |
usePerformanceMarks |
boolean |
false |
Create Performance API marks/measures for DevTools |
showTiming |
boolean |
true |
Show transition execution time |
showParamsDiff |
boolean |
true |
Show diff of changed parameters when navigating within same route |
context |
string |
"logger-plugin" |
Context for console messages (useful with multiple routers) |
Types
type LogLevel = "all" | "transitions" | "errors" | "none";
interface LoggerPluginConfig {
usePerformanceMarks?: boolean;
level?: LogLevel;
showTiming?: boolean;
showParamsDiff?: boolean;
context?: string;
}
Configuration Examples
// Minimal configuration (all default values)
router.usePlugin(loggerPluginFactory());
// With custom context for multiple routers
router.usePlugin(
loggerPluginFactory({
context: "main-router",
}),
);
// Performance profiling enabled
router.usePlugin(
loggerPluginFactory({
usePerformanceMarks: true,
showTiming: true,
}),
);
// Errors only (for production-like environments)
router.usePlugin(
loggerPluginFactory({
level: "errors",
showTiming: false,
}),
);
// Minimal output
router.usePlugin(
loggerPluginFactory({
level: "transitions",
showParamsDiff: false,
showTiming: false,
}),
);
4. Lifecycle Hooks
The plugin implements all lifecycle hooks:
| Hook | Implemented | Description |
|---|---|---|
onStart |
β | Logs "Router started", creates performance mark |
onStop |
β | Logs "Router stopped", creates measure router:lifetime |
onTransitionStart |
β | Opens console.group, logs transition start, shows params diff |
onTransitionSuccess |
β | Logs success with timing, closes group |
onTransitionError |
β | Logs error with code and timing, closes group |
onTransitionCancel |
β | Logs cancellation with timing, closes group |
teardown |
β | Closes open groups, resets timing |
Hook Implementation Details
onStart
- Creates performance mark
router:start - Logs "Router started"
onStop
- Closes open console groups
- Creates performance mark
router:stop - Creates measure
router:lifetimebetween start and stop - Logs "Router stopped"
onTransitionStart
- Opens console.group "Router transition"
- Records start time for timing
- Creates mark
router:transition-start:{from}β{to} - Logs "Transition: {from} β {to}" with from/to objects
- Calls logParamsDiff if route hasn't changed
onTransitionSuccess
- Creates mark
router:transition-end:{label} - Creates measure
router:transition:{label} - Logs "Transition success (X.XXms)"
- Closes console.group
- Resets timing
onTransitionCancel
- Creates mark
router:transition-cancel:{label} - Creates measure
router:transition-cancelled:{label} - Logs warning "Transition cancelled (X.XXms)"
- Closes console.group
- Resets timing
onTransitionError
- Creates mark
router:transition-error:{label} - Creates measure
router:transition-failed:{label} - Logs error "Transition error: {code} (X.XXms)" with error/stack
- Closes console.group
- Resets timing
teardown
- Closes open console groups
- Resets transitionStartTime
5. Router Interaction
Router Interface Extension
The plugin does not extend the Router interface. It's a purely observational plugin.
Used Router Methods
| Method | Purpose |
|---|---|
| - | Plugin doesn't call router methods |
Data Received from Router
| Data | Description |
|---|---|
toState |
Target transition state |
fromState |
Source transition state |
err |
Error object in onTransitionError |
6. Side Effects
Console APIs
- console.log: For regular messages (router start/stop, transitions)
- console.warn: For transition cancellations and warnings
- console.error: For transition errors
- console.group / console.groupEnd: Grouping transition messages
Performance API
When usePerformanceMarks is enabled:
- performance.mark(): Creating marks
- performance.measure(): Creating measurements between marks
Console Groups Logic
- Group opens on
onTransitionStart - Group closes on
onTransitionSuccess,onTransitionCancel,onTransitionError,onStop,teardown - Double group opening is prevented
- Closing unclosed group is prevented
7. Integration with Other Plugins
| Plugin | Interaction |
|---|---|
@real-router/browser-plugin |
Works correctly, logs all transitions including popstate |
@real-router/persistent-params-plugin |
Shows persistent params in diff |
| Custom plugins | Logs all transitions regardless of source |
Execution Order
Logger plugin is usually registered first to capture all events:
router.usePlugin(loggerPluginFactory()); // First
router.usePlugin(browserPluginFactory());
router.usePlugin(persistentParamsPluginFactory(["lang"]));
8. Behavior
Main Scenarios
- Router start/stop: Logged with performance marks
- Transition success: Logged with timing and states
- Transition error: Logged with error code, stack trace and timing
- Transition cancel: Logged as warning with timing
- Nested routes: Full route name (e.g., "users.view")
- Parameters: Included in logged state objects
Timing Format
- Microseconds (
ΞΌs) for time < 0.1ms - Milliseconds (
ms) for time β₯ 0.1ms - Format:
(X.XXΞΌs)or(X.XXms) (?)for invalid time
Params Diff Format
When navigating within same route with different parameters:
Changed: { id: "123" β "456" }
Added: {"newParam": "value"}
Removed: {"oldParam": "value"}
Edge Cases
- Missing console.group: Graceful degradation, logging continues
- Missing console: Doesn't cause errors
- Rapid transitions: Correctly handles multiple transitions
- Router restart: Correctly logs repeated start
- 100 transitions: Stable operation without leaks
Guarantees
- No side effects on router: Plugin only reads, doesn't modify router
- Group balance: Groups always close (success, error, cancel, stop, teardown)
- Timing reset: Timing resets after each transition
- Single group: Multiple groups don't open for one transition
9. Limitations and Known Issues
- Production: Recommended to disable (
level: "none") or uselevel: "errors"in production for performance - usePerformanceMarks: Disabled by default, requires explicit enabling
- Shallow diff: Params diff performs only shallow comparison
- Performance API: Safe fallback if Performance API unavailable
10. Performance Marks and Measures
When usePerformanceMarks: true:
Marks
| Mark | When Created |
|---|---|
router:start |
On router start |
router:stop |
On router stop |
router:transition-start:{from}β{to} |
On transition start |
router:transition-end:{from}β{to} |
On successful completion |
router:transition-cancel:{from}β{to} |
On transition cancellation |
router:transition-error:{from}β{to} |
On transition error |
Measures
| Measure | Start | End |
|---|---|---|
router:lifetime |
router:start | router:stop |
router:transition:{label} |
transition-start | transition-end |
router:transition-cancelled:{label} |
transition-start | transition-cancel |
router:transition-failed:{label} |
transition-start | transition-error |
11. Usage Examples
Basic Example
import { createRouter } from "@real-router/core";
import { loggerPluginFactory } from "@real-router/logger-plugin";
const routes = [
{ name: "home", path: "/" },
{ name: "users", path: "/users" },
{ name: "users.view", path: "/:id" },
];
const router = createRouter(routes);
router.usePlugin(loggerPluginFactory());
await router.start();
router.navigate("users");
// Console output:
// βΌ Router transition
// [logger-plugin] Transition: home β users {from: {...}, to: {...}}
// [logger-plugin] Transition success (0.15ms) {to: {...}, from: {...}}
router.navigate("users.view", { id: "123" });
// Console output:
// βΌ Router transition
// [logger-plugin] Transition: users β users.view {from: {...}, to: {...}}
// [logger-plugin] Transition success (0.12ms) {to: {...}, from: {...}}
router.navigate("users.view", { id: "456" });
// Console output:
// βΌ Router transition
// [logger-plugin] Transition: users.view β users.view {from: {...}, to: {...}}
// [logger-plugin] Changed: { id: "123" β "456" }
// [logger-plugin] Transition success (0.08ms) {to: {...}, from: {...}}
With Performance API
import { createRouter } from "@real-router/core";
import { loggerPluginFactory } from "@real-router/logger-plugin";
const router = createRouter(routes);
// Performance marks visible in DevTools Performance tab
router.usePlugin(
loggerPluginFactory({
usePerformanceMarks: true,
}),
);
await router.start();
router.navigate("users");
router.stop();
// In DevTools Performance tab you'll see:
// - router:start
// - router:transition-start:homeβusers
// - router:transition-end:homeβusers
// - router:transition:homeβusers (measure)
// - router:stop
// - router:lifetime (measure)
12. Migration from router5
Comparison of plugin versions (master β current).
Version Comparison
| Master | Current | |
|---|---|---|
| Factory signature | loggerPlugin (constant PluginFactory) |
loggerPluginFactory(options?) |
| Options | None | LoggerPluginConfig (5 options) |
| Export | export default loggerPlugin |
export { loggerPluginFactory } |
| Structure | Single file index.ts | Modular structure (factory.ts, plugin.ts, types.ts, internal/*) |
1. Breaking Changes
Severity Levels:
- CRITICAL β Plugin will definitely break
- HIGH β Plugin will likely break
- MEDIUM β Plugin may break in some cases
- LOW β Backward compatible, but needs attention
Changes Table
| Severity | What Changed | Was | Now | Impact |
|---|---|---|---|---|
| CRITICAL | Export method | export default loggerPlugin |
export { loggerPluginFactory } |
Import will break |
| LOW | Message format | "Router started", "Transition started from state" |
"[logger-plugin] Router started", etc. (context) |
Log appearance will change |
Examples
// β Code that will break (import)
import loggerPlugin from "@real-router/logger-plugin";
// β
Code after migration
import { loggerPluginFactory } from "@real-router/logger-plugin";
router.usePlugin(loggerPluginFactory());
2. Implementation Changes
New Options
- usePerformanceMarks (
boolean, default:false): Create Performance API marks/measures - level (
LogLevel, default:"all"): Logging level - showTiming (
boolean, default:true): Show execution time - showParamsDiff (
boolean, default:true): Show params diff - context (
string, default:"logger-plugin"): Context for logger
Removed Options
- None (master had no options)
Lifecycle Hook Changes
| Hook | Master | Current | Change |
|---|---|---|---|
onStart |
β Not implemented (logging in constructor) | β Implemented | Added hook, Performance mark |
onStop |
β
console.info("Router stopped") |
β Restructured | + Performance mark/measure, context prefix |
onTransitionStart |
β Basic log | β Extended | + Timing, params diff, Performance marks, improved format |
onTransitionSuccess |
β
console.log("Transition success") |
β Extended | + Timing, Performance marks, states in object |
onTransitionCancel |
β
console.warn("Transition cancelled") |
β Extended | + Timing, Performance marks, states |
onTransitionError |
β
console.warn("...code") |
β Extended | + Timing, Performance marks, stack trace, console.error |
teardown |
β Not implemented | β Added | Closing groups, resetting timing |
New Features
- Performance API integration: Marks and measures for DevTools Performance tab
- Timing measurement: Transition execution time with adaptive units (ΞΌs/ms)
- Params diff: Showing parameter changes when navigating within same route
- Context prefix: All messages prefixed with
[logger-plugin] - Console groups management: Protection from double open/close
- Teardown hook: Proper resource cleanup
- Modular structure: Split into internal modules
Fixed Bugs
- Group balance: In master group was closed before
onTransitionStart(wrong), now correct lifecycle - Console.groupCollapsed: In master groupCollapsed was preferred, now group is used
- Missing onStart hook: In master "Router started" logging was in constructor, not in hook
Performance Improvements
- Lazy group detection: console.group support check once on creation
- Performance API conditional: Support check once, not on every call
3. Dependency Changes
| Dependency | Was | Now |
|---|---|---|
@real-router/core |
peer dependency | workspace:^ |
4. Migration Guide
Checklist
- Update import:
import { loggerPluginFactory } from "@real-router/logger-plugin" - Replace
router.usePlugin(loggerPlugin)withrouter.usePlugin(loggerPluginFactory()) - Account for log format change (context at message start)
- Account for new timing messages
- If Performance API needed, pass
usePerformanceMarks: true
Step-by-Step Migration
-
Update import
// Was import loggerPlugin from "@real-router/logger-plugin"; // Now import { loggerPluginFactory } from "@real-router/logger-plugin"; router.usePlugin(loggerPluginFactory()); -
Adapt log parsing (if used)
// Was // "Router started" // "Transition started from state" // Now // "[logger-plugin] Router started" // "[logger-plugin] Transition: home β users" -
Use new features (optional)
// Timing shown by default (showTiming: true) // Params diff shown by default (showParamsDiff: true) // Performance marks require explicit opt-in (usePerformanceMarks: true)
5. Summary
| Category | Status |
|---|---|
| Breaking Changes | CRITICAL (import) |
| New options | β 5 options |
| Removed options | β None |
| Hook changes | β Significant (all hooks extended) |
| New hooks | β onStart, teardown |
| Optimizations | β Lazy detection |
| Performance API | β Full integration |
Maximum severity: CRITICAL β Import change required