pinia-plugin-logger
v1.3.0
Published
Logger for Pinia
Maintainers
Readme
🧩 Features
🍍 Simple and flexible action logger for Pinia
🚦 Includes/excludes/filter actions to log
💡 Supports custom logger and log style
🏷 Store name and timestamp in log title
⏱️ Action duration tracking for performance monitoring
� Deep clone support for accurate nested object tracking
�🛡 Error logging with clear visibility
🗂 Store-level logger configuration possible
🎨 Visual state change indicators (✅/⚪/❌)
🔧 State transformer for sensitive data masking
🕹Guide
Install
$ npm install --save pinia-plugin-logger📍 Plugin Usage
import { createPinia } from "pinia";
import piniaPluginLogger from "pinia-plugin-logger";
const pinia = createPinia();
const logger = piniaPluginLogger({
enabled: true, // Activate the logger
expanded: true, // Expand the console group
showStoreName: true, // Show the store name in the console
showTimestamp: true, // Show the timestamp in the console
showDuration: true, // Show action execution time
showErrors: true, // Show errors in the console
deepClone: false, // Use deep clone for state snapshots
maxDepth: Infinity, // Maximum depth for state logging
includeActions: [], // Only log these actions (if defined)
excludeActions: [], // Exclude these actions from logging
filter: () => true, // Custom filter function
logger: console, // Custom logger object
stateTransformer: undefined, // Transform state before logging
});
pinia.use(logger);
export default pinia;💡 Store Level Usage
import { defineStore } from "pinia";
export const useCounterStore = defineStore("counter", {
state: () => ({
count: 0,
user: {
name: "Guest",
preferences: { theme: "light" }
}
}),
actions: {
increment() {
this.count++;
},
async fetchData() {
// Async action with duration tracking
await fetch('/api/data');
}
},
logger: {
enabled: true,
expanded: false,
showDuration: true,
deepClone: true,
includeActions: ["increment", "fetchData"],
},
});🛠 Options
| Option | Type | Default | Description | | ---------------- | --------------------- | ---------- | -------------------------------------------------- | | enabled | boolean | true | Activate the logger plugin | | expanded | boolean | true | Expand the console group | | showStoreName | boolean | true | Show the store name in the log title | | showTimestamp | boolean | true | Show time of action in the log title | | showDuration | boolean | false | Show action execution time | | showErrors | boolean | true | Show error logs in the console | | deepClone | boolean | false | Use deep clone for state snapshots (performance impact) | | maxDepth | number | Infinity | Maximum depth for state logging | | includeActions | string[] | [] | Only log actions in this list | | excludeActions | string[] | [] | Exclude actions in this list | | filter | function | () => true | Custom filter function for action logging | | logger | object | console | Custom logger object (log/group support) | | stateTransformer | (state: any) => any | undefined | Transform state before logging (e.g., mask sensitive data) | | logLevel | 'debug' | 'info' | 'warn' | 'error' | 'debug' | Log level (for future use) |
📦 Example Console Output
// Basic action with state change
action 🍍 [counter] increment @15:42:13:123 (2ms) ✅
prev state { count: 0, history: [] }
action { type: 'increment', store: 'counter', duration: '2ms' }
next state { count: 1, history: [1] }
// Async action with duration tracking
action 🍍 [user] fetchUser @15:43:22:212 (1045ms) ✅
prev state { loading: false, data: null }
action { type: 'fetchUser', args: { id: 1 }, store: 'user', duration: '1045ms' }
next state { loading: false, data: { id: 1, name: 'John' } }
// Action with error
action 🍍 [user] fetchUser @15:43:23:221 (523ms) ❌
prev state { loading: true, data: null }
action { type: 'fetchUser', args: { id: 1 }, store: 'user', duration: '523ms', error: Error: Failed to fetch }
next state { loading: false, data: null }
// Action without state change
action 🍍 [settings] validateInput @15:44:10:456 (1ms) ⚪
prev state { valid: true }
action { type: 'validateInput', store: 'settings', duration: '1ms' }
next state { valid: true }
ℹ️ No state changesVisual Indicators
- ✅ Green: State changed successfully
- ⚪ Gray: No state changes
- ❌ Red: Error occurred
🎯 Advanced Usage
Deep Clone for Nested Objects
const logger = piniaPluginLogger({
deepClone: true, // Enable deep cloning
maxDepth: 5, // Limit depth to 5 levels
});Benefits: Accurately tracks changes in nested objects, arrays, Maps, and Sets. Trade-off: Slightly slower performance (recommended for development only).
State Transformer for Sensitive Data
const logger = piniaPluginLogger({
stateTransformer: (state) => {
// Mask sensitive information
if (state.user?.password) {
return {
...state,
user: { ...state.user, password: '***' }
};
}
return state;
}
});Conditional Logging
const logger = piniaPluginLogger({
// Only in development
enabled: import.meta.env.DEV,
// Only log specific actions
includeActions: ['increment', 'fetchUser'],
// Or exclude specific actions
excludeActions: ['debugAction'],
// Custom filter
filter: (action) => {
// Only log when count > 10
return action.store.$state.count > 10;
}
});Performance Monitoring
const logger = piniaPluginLogger({
showDuration: true,
filter: (action) => {
// Log only slow actions (> 100ms)
const startTime = Date.now();
action.after(() => {
const duration = Date.now() - startTime;
return duration > 100;
});
}
});📂 Examples
Check out the example app for a complete demonstration of all features:
cd examples/vue-app
pnpm install
pnpm run devFeatures demonstrated:
- Basic counter with state tracking
- Async actions with duration measurement
- Nested object mutations (deep clone)
- Error handling
- History tracking
⚠️ Production Usage
Important: Disable the logger in production to avoid performance overhead.
const logger = piniaPluginLogger({
enabled: import.meta.env.DEV, // Only in development
});Or use conditional plugin registration:
const pinia = createPinia();
if (import.meta.env.DEV) {
pinia.use(piniaPluginLogger());
}🏗 TypeScript Support
This plugin comes with full TypeScript support:
import type { PiniaLoggerOptions } from 'pinia-plugin-logger';
const loggerOptions: PiniaLoggerOptions = {
enabled: true,
deepClone: true,
// ... with autocomplete and type checking
};🤝 Contributing
Contributions are always welcome! Please feel free to open an issue or submit a pull request.
