ngrx-store-logger
Advanced tools
Comparing version 0.2.0 to 0.2.1
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var logger = console; | ||
var INIT_ACTION = "@ngrx/store/init"; | ||
var repeat = function (str, times) { return (new Array(times + 1)).join(str); }; | ||
var pad = function (num, maxLength) { return repeat("0", maxLength - num.toString().length) + num; }; | ||
var formatTime = function (time) { return "@ " + pad(time.getHours(), 2) + ":" + pad(time.getMinutes(), 2) + ":" + pad(time.getSeconds(), 2) + "." + pad(time.getMilliseconds(), 3); }; | ||
var timer = typeof performance !== "undefined" && typeof performance.now === "function" ? performance : Date; | ||
var INIT_ACTION = '@ngrx/store/init'; | ||
var repeat = function (str, times) { return new Array(times + 1).join(str); }; | ||
var pad = function (num, maxLength) { | ||
return repeat("0", maxLength - num.toString().length) + num; | ||
}; | ||
var formatTime = function (time) { | ||
return "@ " + pad(time.getHours(), 2) + ":" + pad(time.getMinutes(), 2) + ":" + pad(time.getSeconds(), 2) + "." + pad(time.getMilliseconds(), 3); | ||
}; | ||
var timer = typeof performance !== "undefined" && typeof performance.now === "function" | ||
? performance | ||
: Date; | ||
var getLogLevel = function (level, action, payload, type) { | ||
switch (typeof level) { | ||
case "object": | ||
return typeof level[type] === "function" ? level[type].apply(level, payload) : level[type]; | ||
return typeof level[type] === "function" | ||
? level[type].apply(level, payload) : level[type]; | ||
case "function": | ||
@@ -23,3 +30,5 @@ return level(action); | ||
var started = logEntry.started, startedTime = logEntry.startedTime, action = logEntry.action, error = logEntry.error; | ||
var prevState = logEntry.prevState.nextState ? logEntry.prevState.nextState : '(Empty)'; | ||
var prevState = logEntry.prevState.nextState | ||
? logEntry.prevState.nextState | ||
: '(Empty)'; | ||
var took = logEntry.took, nextState = logEntry.nextState; | ||
@@ -32,5 +41,9 @@ var nextEntry = logBuffer[key + 1]; | ||
var formattedAction = actionTransformer(action); | ||
var isCollapsed = (typeof collapsed === "function") ? collapsed(function () { return nextState; }, action) : collapsed; | ||
var isCollapsed = typeof collapsed === "function" | ||
? collapsed(function () { return nextState; }, action) | ||
: collapsed; | ||
var formattedTime = formatTime(startedTime); | ||
var titleCSS = colors.title ? "color: " + colors.title(formattedAction) + ";" : null; | ||
var titleCSS = colors.title | ||
? "color: " + colors.title(formattedAction) + ";" | ||
: null; | ||
var title = "action " + (timestamp ? formattedTime : "") + " " + formattedAction.type + " " + (duration ? "(in " + took.toFixed(2) + " ms)" : ""); | ||
@@ -104,3 +117,5 @@ try { | ||
var log = {}; | ||
var ua = typeof window !== 'undefined' && window.navigator.userAgent ? window.navigator.userAgent : ''; | ||
var ua = typeof window !== 'undefined' && window.navigator.userAgent | ||
? window.navigator.userAgent | ||
: ''; | ||
var ms_ie = false; | ||
@@ -110,3 +125,3 @@ //fix for action display in IE | ||
var new_ie = ua.indexOf('Trident/'); | ||
if ((old_ie > -1) || (new_ie > -1)) { | ||
if (old_ie > -1 || new_ie > -1) { | ||
ms_ie = true; | ||
@@ -122,3 +137,3 @@ } | ||
nextState: null, | ||
error: null, | ||
error: null | ||
}; | ||
@@ -132,3 +147,3 @@ } | ||
nextState: function () { return '#4CAF50'; }, | ||
error: function () { return '#F20404'; }, | ||
error: function () { return '#F20404'; } | ||
}; | ||
@@ -173,3 +188,2 @@ } | ||
}; | ||
; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "ngrx-store-logger", | ||
"version": "0.2.0", | ||
"version": "0.2.1", | ||
"description": "Advanced logging middleware for @ngrx/store", | ||
@@ -14,10 +14,3 @@ "main": "./dist/index.js", | ||
}, | ||
"keywords": [ | ||
"redux", | ||
"ngrx", | ||
"store", | ||
"logger", | ||
"middleware", | ||
"rxjs" | ||
], | ||
"keywords": ["redux", "ngrx", "store", "logger", "middleware", "rxjs"], | ||
"author": "Brian Troncone", | ||
@@ -30,3 +23,3 @@ "license": "MIT", | ||
"peerDependencies": { | ||
"@ngrx/store": "^4.0.0" | ||
"@ngrx/store": "^4.0.0 || ^5.0.0" | ||
}, | ||
@@ -33,0 +26,0 @@ "devDependencies": { |
@@ -7,3 +7,3 @@ # ngrx-store-logger | ||
## Dependencies | ||
`ngrx-store-logger` depends on [@ngrx/store](https://github.com/ngrx/store) and [Angular 2](https://github.com/angular/angular). | ||
`ngrx-store-logger` depends on [@ngrx/store](https://github.com/ngrx/store) and [Angular 2+](https://github.com/angular/angular). | ||
@@ -14,30 +14,31 @@ ## Usage | ||
``` | ||
**UPDATED FOR NGRX 4** | ||
1. Import `ngrx-store-logger` | ||
2. Wrap in an exported function | ||
3. Include in your meta-reducers in `StoreModule.forRoot` call. | ||
1. Import `compose` and `combineReducers` from `@ngrx/store` and `@ngrx/core/compose` | ||
2. Invoke the `storeLogger` function from ngrx-store-logger, passing appropriate options. | ||
3. Add `combineReducers` after `storeLogger` and invoke composed function with application reducers as an argument to `provideStore`. | ||
```ts | ||
import {bootstrap} from '@angular/platform-browser-dynamic'; | ||
import {TodoApp} from './todo-app'; | ||
import {provideStore, combineReducers} from "@ngrx/store"; | ||
import {compose} from "@ngrx/core/compose"; | ||
import {storeLogger} from "ngrx-store-logger"; | ||
import {todos, visibilityFilter} from './reducers'; | ||
import { NgModule } from '@angular/core'; | ||
import { BrowserModule } from '@angular/platform-browser'; | ||
import { StoreModule, ActionReducer } from '@ngrx/store'; | ||
import { storeLogger } from 'ngrx-store-logger'; | ||
import { reducers } from './reducers'; | ||
export function main() { | ||
return bootstrap(TodoApp, [ | ||
//taking all logging defaults | ||
//todos and visibilityFilter are just sample reducers | ||
provideStore( | ||
compose( | ||
storeLogger(), | ||
combineReducers | ||
)({todos, visibilityFilter}) | ||
), | ||
]) | ||
.catch(err => console.error(err)); | ||
export function logger(reducer: ActionReducer<State>): any { | ||
// default, no options | ||
return storeLogger()(reducer); | ||
} | ||
document.addEventListener('DOMContentLoaded', main); | ||
export const metaReducers = environment.production ? [] : [logger]; | ||
@NgModule({ | ||
imports: [ | ||
BrowserModule, | ||
StoreModule.forRoot( | ||
reducers, | ||
{metaReducers} | ||
) | ||
] | ||
}) | ||
export class MyAppModule {} | ||
``` | ||
@@ -104,2 +105,2 @@ | ||
*Note*: Whitelist has predence over blacklist. If both are defined, only whitelist will be considered | ||
*Note*: Whitelist takes precedence over blacklist. If both are defined, only whitelist will be considered |
423
src/index.ts
declare var console; | ||
const logger = console; | ||
const INIT_ACTION = "@ngrx/store/init"; | ||
const INIT_ACTION = '@ngrx/store/init'; | ||
const repeat = (str, times) => (new Array(times + 1)).join(str); | ||
const pad = (num, maxLength) => repeat(`0`, maxLength - num.toString().length) + num; | ||
const formatTime = (time) => `@ ${pad(time.getHours(), 2)}:${pad(time.getMinutes(), 2)}:${pad(time.getSeconds(), 2)}.${pad(time.getMilliseconds(), 3)}`; | ||
const timer = typeof performance !== `undefined` && typeof performance.now === `function` ? performance : Date; | ||
const repeat = (str, times) => new Array(times + 1).join(str); | ||
const pad = (num, maxLength) => | ||
repeat(`0`, maxLength - num.toString().length) + num; | ||
const formatTime = time => | ||
`@ ${pad(time.getHours(), 2)}:${pad(time.getMinutes(), 2)}:${pad( | ||
time.getSeconds(), | ||
2 | ||
)}.${pad(time.getMilliseconds(), 3)}`; | ||
const timer = | ||
typeof performance !== `undefined` && typeof performance.now === `function` | ||
? performance | ||
: Date; | ||
const getLogLevel = (level, action, payload, type) => { | ||
switch (typeof level) { | ||
case `object`: | ||
return typeof level[type] === `function` ? level[type](...payload) : level[type]; | ||
case `function`: | ||
return level(action); | ||
default: | ||
return level; | ||
} | ||
switch (typeof level) { | ||
case `object`: | ||
return typeof level[type] === `function` | ||
? level[type](...payload) | ||
: level[type]; | ||
case `function`: | ||
return level(action); | ||
default: | ||
return level; | ||
} | ||
}; | ||
const printBuffer = options => logBuffer => { | ||
const {actionTransformer, collapsed, colors, timestamp, duration, level} = options; | ||
logBuffer.forEach((logEntry, key) => { | ||
const { started, startedTime, action, error } = logEntry; | ||
const prevState = logEntry.prevState.nextState ? logEntry.prevState.nextState : '(Empty)'; | ||
let { took, nextState } = logEntry; | ||
const nextEntry = logBuffer[key + 1]; | ||
if (nextEntry) { | ||
nextState = nextEntry.prevState; | ||
took = nextEntry.started - started; | ||
} | ||
const { | ||
actionTransformer, | ||
collapsed, | ||
colors, | ||
timestamp, | ||
duration, | ||
level | ||
} = options; | ||
logBuffer.forEach((logEntry, key) => { | ||
const { started, startedTime, action, error } = logEntry; | ||
const prevState = logEntry.prevState.nextState | ||
? logEntry.prevState.nextState | ||
: '(Empty)'; | ||
let { took, nextState } = logEntry; | ||
const nextEntry = logBuffer[key + 1]; | ||
if (nextEntry) { | ||
nextState = nextEntry.prevState; | ||
took = nextEntry.started - started; | ||
} | ||
const formattedAction = actionTransformer(action); | ||
const isCollapsed = (typeof collapsed === `function`) ? collapsed(() => nextState, action) : collapsed; | ||
const formattedAction = actionTransformer(action); | ||
const isCollapsed = | ||
typeof collapsed === `function` | ||
? collapsed(() => nextState, action) | ||
: collapsed; | ||
const formattedTime = formatTime(startedTime); | ||
const titleCSS = colors.title ? `color: ${colors.title(formattedAction)};` : null; | ||
const title = `action ${timestamp ? formattedTime : ``} ${formattedAction.type} ${duration ? `(in ${took.toFixed(2)} ms)` : ``}`; | ||
const formattedTime = formatTime(startedTime); | ||
const titleCSS = colors.title | ||
? `color: ${colors.title(formattedAction)};` | ||
: null; | ||
const title = `action ${timestamp ? formattedTime : ``} ${ | ||
formattedAction.type | ||
} ${duration ? `(in ${took.toFixed(2)} ms)` : ``}`; | ||
try { | ||
if (isCollapsed) { | ||
if (colors.title) logger.groupCollapsed(`%c ${title}`, titleCSS); | ||
else logger.groupCollapsed(title); | ||
} else { | ||
if (colors.title) logger.group(`%c ${title}`, titleCSS); | ||
else logger.group(title); | ||
} | ||
} catch (e) { | ||
logger.log(title); | ||
} | ||
try { | ||
if (isCollapsed) { | ||
if (colors.title) logger.groupCollapsed(`%c ${title}`, titleCSS); | ||
else logger.groupCollapsed(title); | ||
} else { | ||
if (colors.title) logger.group(`%c ${title}`, titleCSS); | ||
else logger.group(title); | ||
} | ||
} catch (e) { | ||
logger.log(title); | ||
} | ||
const prevStateLevel = getLogLevel(level, formattedAction, [prevState], `prevState`); | ||
const actionLevel = getLogLevel(level, formattedAction, [formattedAction], `action`); | ||
const errorLevel = getLogLevel(level, formattedAction, [error, prevState], `error`); | ||
const nextStateLevel = getLogLevel(level, formattedAction, [nextState], `nextState`); | ||
const prevStateLevel = getLogLevel( | ||
level, | ||
formattedAction, | ||
[prevState], | ||
`prevState` | ||
); | ||
const actionLevel = getLogLevel( | ||
level, | ||
formattedAction, | ||
[formattedAction], | ||
`action` | ||
); | ||
const errorLevel = getLogLevel( | ||
level, | ||
formattedAction, | ||
[error, prevState], | ||
`error` | ||
); | ||
const nextStateLevel = getLogLevel( | ||
level, | ||
formattedAction, | ||
[nextState], | ||
`nextState` | ||
); | ||
if (prevStateLevel) { | ||
if (colors.prevState) logger[prevStateLevel](`%c prev state`, `color: ${colors.prevState(prevState)}; font-weight: bold`, prevState); | ||
else logger[prevStateLevel](`prev state`, prevState); | ||
} | ||
if (prevStateLevel) { | ||
if (colors.prevState) | ||
logger[prevStateLevel]( | ||
`%c prev state`, | ||
`color: ${colors.prevState(prevState)}; font-weight: bold`, | ||
prevState | ||
); | ||
else logger[prevStateLevel](`prev state`, prevState); | ||
} | ||
if (actionLevel) { | ||
if (colors.action) logger[actionLevel](`%c action`, `color: ${colors.action(formattedAction)}; font-weight: bold`, formattedAction); | ||
else logger[actionLevel](`action`, formattedAction); | ||
} | ||
if (actionLevel) { | ||
if (colors.action) | ||
logger[actionLevel]( | ||
`%c action`, | ||
`color: ${colors.action(formattedAction)}; font-weight: bold`, | ||
formattedAction | ||
); | ||
else logger[actionLevel](`action`, formattedAction); | ||
} | ||
if (error && errorLevel) { | ||
if (colors.error) logger[errorLevel](`%c error`, `color: ${colors.error(error, prevState)}; font-weight: bold`, error); | ||
else logger[errorLevel](`error`, error); | ||
} | ||
if (error && errorLevel) { | ||
if (colors.error) | ||
logger[errorLevel]( | ||
`%c error`, | ||
`color: ${colors.error(error, prevState)}; font-weight: bold`, | ||
error | ||
); | ||
else logger[errorLevel](`error`, error); | ||
} | ||
if (nextStateLevel) { | ||
if (colors.nextState) logger[nextStateLevel](`%c next state`, `color: ${colors.nextState(nextState)}; font-weight: bold`, nextState); | ||
else logger[nextStateLevel](`next state`, nextState); | ||
} | ||
if (nextStateLevel) { | ||
if (colors.nextState) | ||
logger[nextStateLevel]( | ||
`%c next state`, | ||
`color: ${colors.nextState(nextState)}; font-weight: bold`, | ||
nextState | ||
); | ||
else logger[nextStateLevel](`next state`, nextState); | ||
} | ||
try { | ||
logger.groupEnd(); | ||
} catch (e) { | ||
logger.log(`—— log end ——`); | ||
} | ||
}); | ||
logBuffer.length = 0; | ||
try { | ||
logger.groupEnd(); | ||
} catch (e) { | ||
logger.log(`—— log end ——`); | ||
} | ||
}); | ||
logBuffer.length = 0; | ||
}; | ||
const isAllowed = (action, filter) => { | ||
if (!filter) { | ||
return true; | ||
} | ||
if (filter.whitelist && filter.whitelist.length) { | ||
return filter.whitelist.indexOf(action.type) !== -1; | ||
} | ||
return filter.blacklist && filter.blacklist.indexOf(action.type) === -1; | ||
if (!filter) { | ||
return true; | ||
} | ||
if (filter.whitelist && filter.whitelist.length) { | ||
return filter.whitelist.indexOf(action.type) !== -1; | ||
} | ||
return filter.blacklist && filter.blacklist.indexOf(action.type) === -1; | ||
}; | ||
export const storeLogger = (opts: LoggerOptions = {}) => (reducer: Function) => { | ||
let log = {}; | ||
const ua = typeof window !== 'undefined' && window.navigator.userAgent ? window.navigator.userAgent : ''; | ||
let ms_ie = false; | ||
//fix for action display in IE | ||
const old_ie = ua.indexOf('MSIE '); | ||
const new_ie = ua.indexOf('Trident/'); | ||
export const storeLogger = (opts: LoggerOptions = {}) => ( | ||
reducer: Function | ||
) => { | ||
let log = {}; | ||
const ua = | ||
typeof window !== 'undefined' && window.navigator.userAgent | ||
? window.navigator.userAgent | ||
: ''; | ||
let ms_ie = false; | ||
//fix for action display in IE | ||
const old_ie = ua.indexOf('MSIE '); | ||
const new_ie = ua.indexOf('Trident/'); | ||
if ((old_ie > -1) || (new_ie > -1)) { | ||
ms_ie = true; | ||
} | ||
if (old_ie > -1 || new_ie > -1) { | ||
ms_ie = true; | ||
} | ||
let colors: LoggerColorsOption; | ||
if (ms_ie) { | ||
// Setting colors functions to null when it's an IE browser. | ||
colors = { | ||
title: null, | ||
prevState: null, | ||
action: null, | ||
nextState: null, | ||
error: null, | ||
} | ||
} else { | ||
colors = { | ||
title: null, | ||
prevState: () => '#9E9E9E', | ||
action: () => '#03A9F4', | ||
nextState: () => '#4CAF50', | ||
error: () => '#F20404', | ||
} | ||
} | ||
const defaults: LoggerOptions = { | ||
level: 'log', | ||
collapsed: false, | ||
duration: true, | ||
timestamp: true, | ||
stateTransformer: state => state, | ||
actionTransformer: actn => actn, | ||
filter: { | ||
whitelist: [], | ||
blacklist: [] | ||
}, | ||
colors: colors | ||
let colors: LoggerColorsOption; | ||
if (ms_ie) { | ||
// Setting colors functions to null when it's an IE browser. | ||
colors = { | ||
title: null, | ||
prevState: null, | ||
action: null, | ||
nextState: null, | ||
error: null | ||
}; | ||
} else { | ||
colors = { | ||
title: null, | ||
prevState: () => '#9E9E9E', | ||
action: () => '#03A9F4', | ||
nextState: () => '#4CAF50', | ||
error: () => '#F20404' | ||
}; | ||
} | ||
const options = Object.assign({}, defaults, opts); | ||
const {stateTransformer} = options; | ||
const buffer = printBuffer(options); | ||
const defaults: LoggerOptions = { | ||
level: 'log', | ||
collapsed: false, | ||
duration: true, | ||
timestamp: true, | ||
stateTransformer: state => state, | ||
actionTransformer: actn => actn, | ||
filter: { | ||
whitelist: [], | ||
blacklist: [] | ||
}, | ||
colors: colors | ||
}; | ||
return function(state, action) { | ||
let preLog = { | ||
started: timer.now(), | ||
startedTime: new Date(), | ||
prevState: stateTransformer(log), | ||
action | ||
}; | ||
const options = Object.assign({}, defaults, opts); | ||
const { stateTransformer } = options; | ||
const buffer = printBuffer(options); | ||
let nextState = reducer(state, action); | ||
return function(state, action) { | ||
let preLog = { | ||
started: timer.now(), | ||
startedTime: new Date(), | ||
prevState: stateTransformer(log), | ||
action | ||
}; | ||
let postLog = { | ||
took: timer.now() - preLog.started, | ||
nextState: stateTransformer(nextState) | ||
}; | ||
log = Object.assign({}, preLog, postLog); | ||
//ignore init action fired by store and devtools | ||
if(action.type !== INIT_ACTION && isAllowed(action, options.filter)) { | ||
buffer([log]); | ||
} | ||
let nextState = reducer(state, action); | ||
return nextState; | ||
let postLog = { | ||
took: timer.now() - preLog.started, | ||
nextState: stateTransformer(nextState) | ||
}; | ||
log = Object.assign({}, preLog, postLog); | ||
//ignore init action fired by store and devtools | ||
if (action.type !== INIT_ACTION && isAllowed(action, options.filter)) { | ||
buffer([log]); | ||
} | ||
return nextState; | ||
}; | ||
}; | ||
export interface LoggerOptions { | ||
/** | ||
* 'log' | 'console' | 'warn' | 'error' | 'info'. Default: 'log' | ||
*/ | ||
level?: any; | ||
/** | ||
* Should log group be collapsed? default: false | ||
*/ | ||
collapsed?: boolean; | ||
/** | ||
* Print duration with action? default: true | ||
*/ | ||
duration?: boolean; | ||
/** | ||
* Print timestamp with action? default: true | ||
*/ | ||
timestamp?: boolean; | ||
filter?: LoggerFilterOption; | ||
/** | ||
* Transform state before print default: state => state | ||
*/ | ||
stateTransformer?: (state: Object) => Object; | ||
/** | ||
* Transform action before print default: actn => actn | ||
*/ | ||
actionTransformer?: (actn: Object) => Object; | ||
colors?: LoggerColorsOption; | ||
}; | ||
/** | ||
* 'log' | 'console' | 'warn' | 'error' | 'info'. Default: 'log' | ||
*/ | ||
level?: any; | ||
/** | ||
* Should log group be collapsed? default: false | ||
*/ | ||
collapsed?: boolean; | ||
/** | ||
* Print duration with action? default: true | ||
*/ | ||
duration?: boolean; | ||
/** | ||
* Print timestamp with action? default: true | ||
*/ | ||
timestamp?: boolean; | ||
filter?: LoggerFilterOption; | ||
/** | ||
* Transform state before print default: state => state | ||
*/ | ||
stateTransformer?: (state: Object) => Object; | ||
/** | ||
* Transform action before print default: actn => actn | ||
*/ | ||
actionTransformer?: (actn: Object) => Object; | ||
colors?: LoggerColorsOption; | ||
} | ||
export interface LoggerFilterOption { | ||
/** | ||
* Only print actions included in this list - has priority over blacklist | ||
*/ | ||
whitelist?: string[]; | ||
/** | ||
* Only print actions that are NOT included in this list | ||
*/ | ||
blacklist?: string[]; | ||
/** | ||
* Only print actions included in this list - has priority over blacklist | ||
*/ | ||
whitelist?: string[]; | ||
/** | ||
* Only print actions that are NOT included in this list | ||
*/ | ||
blacklist?: string[]; | ||
} | ||
export interface LoggerColorsOption { | ||
title: (action: Object) => string; | ||
prevState: (prevState: Object) => string; | ||
action: (action: Object) => string; | ||
nextState: (nextState: Object) => string; | ||
error: (error: any, prevState: Object) => string; | ||
title: (action: Object) => string; | ||
prevState: (prevState: Object) => string; | ||
action: (action: Object) => string; | ||
nextState: (nextState: Object) => string; | ||
error: (error: any, prevState: Object) => string; | ||
} |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
504
104
29384