From 18be128ad933d1fca6da05c060f7664ce0c819ae Mon Sep 17 00:00:00 2001 From: Daniel Almaguer Date: Wed, 22 Apr 2020 23:30:18 -0500 Subject: [PATCH] feat(logger): `createLogger` can optionally log actions (#987) --- dist/logger.d.ts | 4 ++ docs/guide/plugins.md | 11 +++++ src/plugins/devtool.js | 4 ++ src/plugins/logger.js | 92 ++++++++++++++++++++++++++++-------------- 4 files changed, 81 insertions(+), 30 deletions(-) diff --git a/dist/logger.d.ts b/dist/logger.d.ts index ec52e727e..5c7351d8c 100644 --- a/dist/logger.d.ts +++ b/dist/logger.d.ts @@ -10,6 +10,10 @@ export interface LoggerOption { filter?:

(mutation: P, stateBefore: S, stateAfter: S) => boolean; transformer?: (state: S) => any; mutationTransformer?:

(mutation: P) => any; + actionFilter?:

(action: P, state: S) => boolean; + actionTransformer?:

(action: P) => any; + logActions?: boolean; + logMutations?: boolean; } export default function createLogger(option?: LoggerOption): Plugin; diff --git a/docs/guide/plugins.md b/docs/guide/plugins.md index fe4939c0a..c89c1bfb3 100644 --- a/docs/guide/plugins.md +++ b/docs/guide/plugins.md @@ -109,6 +109,11 @@ const logger = createLogger({ // `mutation` is a `{ type, payload }` return mutation.type !== "aBlacklistedMutation" }, + actionFilter (action, state) { + // same as `filter` but for actions + // `action` is a `{ type, payload }` + return action.type !== "aBlacklistedAction" + }, transformer (state) { // transform the state before logging it. // for example return only a specific sub-tree @@ -119,6 +124,12 @@ const logger = createLogger({ // we can format it any way we want. return mutation.type }, + actionTransformer (action) { + // Same as mutationTransformer but for actions + return action.type + }, + logActions: true, // Log Actions + logMutations: true, // Log mutations logger: console, // implementation of the `console` API, default `console` }) ``` diff --git a/src/plugins/devtool.js b/src/plugins/devtool.js index dc6b04f73..d1b533fbf 100644 --- a/src/plugins/devtool.js +++ b/src/plugins/devtool.js @@ -19,4 +19,8 @@ export default function devtoolPlugin (store) { store.subscribe((mutation, state) => { devtoolHook.emit('vuex:mutation', mutation, state) }) + + store.subscribeAction((action, state) => { + devtoolHook.emit('vuex:action', action, state) + }) } diff --git a/src/plugins/logger.js b/src/plugins/logger.js index cadab8b29..ccf2b6537 100644 --- a/src/plugins/logger.js +++ b/src/plugins/logger.js @@ -7,49 +7,81 @@ export default function createLogger ({ filter = (mutation, stateBefore, stateAfter) => true, transformer = state => state, mutationTransformer = mut => mut, + actionFilter = (action, state) => true, + actionTransformer = act => act, + logActions = true, + logMutations = true, logger = console } = {}) { return store => { let prevState = deepCopy(store.state) - store.subscribe((mutation, state) => { - if (typeof logger === 'undefined') { - return - } - const nextState = deepCopy(state) - - if (filter(mutation, prevState, nextState)) { - const time = new Date() - const formattedTime = ` @ ${pad(time.getHours(), 2)}:${pad(time.getMinutes(), 2)}:${pad(time.getSeconds(), 2)}.${pad(time.getMilliseconds(), 3)}` - const formattedMutation = mutationTransformer(mutation) - const message = `mutation ${mutation.type}${formattedTime}` - const startMessage = collapsed - ? logger.groupCollapsed - : logger.group - - // render - try { - startMessage.call(logger, message) - } catch (e) { - console.log(message) + if (typeof logger === 'undefined') { + return + } + + if (logMutations) { + store.subscribe((mutation, state) => { + const nextState = deepCopy(state) + + if (filter(mutation, prevState, nextState)) { + const formattedTime = getFormattedTime() + const formattedMutation = mutationTransformer(mutation) + const message = `mutation ${mutation.type}${formattedTime}` + + startMessage(logger, message, collapsed) + logger.log('%c prev state', 'color: #9E9E9E; font-weight: bold', transformer(prevState)) + logger.log('%c mutation', 'color: #03A9F4; font-weight: bold', formattedMutation) + logger.log('%c next state', 'color: #4CAF50; font-weight: bold', transformer(nextState)) + endMessage(logger) } - logger.log('%c prev state', 'color: #9E9E9E; font-weight: bold', transformer(prevState)) - logger.log('%c mutation', 'color: #03A9F4; font-weight: bold', formattedMutation) - logger.log('%c next state', 'color: #4CAF50; font-weight: bold', transformer(nextState)) + prevState = nextState + }) + } - try { - logger.groupEnd() - } catch (e) { - logger.log('—— log end ——') + if (logActions) { + store.subscribeAction((action, state) => { + if (actionFilter(action, state)) { + const formattedTime = getFormattedTime() + const formattedAction = actionTransformer(action) + const message = `action ${action.type}${formattedTime}` + + startMessage(logger, message, collapsed) + logger.log('%c action', 'color: #03A9F4; font-weight: bold', formattedAction) + endMessage(logger) } - } + }) + } + } +} - prevState = nextState - }) +function startMessage (logger, message, collapsed) { + const startMessage = collapsed + ? logger.groupCollapsed + : logger.group + + // render + try { + startMessage.call(logger, message) + } catch (e) { + logger.log(message) + } +} + +function endMessage (logger) { + try { + logger.groupEnd() + } catch (e) { + logger.log('—— log end ——') } } +function getFormattedTime () { + const time = new Date() + return ` @ ${pad(time.getHours(), 2)}:${pad(time.getMinutes(), 2)}:${pad(time.getSeconds(), 2)}.${pad(time.getMilliseconds(), 3)}` +} + function repeat (str, times) { return (new Array(times + 1)).join(str) }