1 | # Logger for Redux
|
2 | [![Build Status](https://travis-ci.org/fcomb/redux-logger.svg?branch=master)](https://travis-ci.org/fcomb/redux-logger)
|
3 |
|
4 | ![redux-logger](http://i.imgur.com/LDgv4tp.png)
|
5 |
|
6 | ## Install
|
7 | `npm i --save redux-logger`
|
8 |
|
9 | ## Usage
|
10 | ```javascript
|
11 | import { applyMiddleware, createStore } from 'redux';
|
12 | import thunk from 'redux-thunk';
|
13 | import promise from 'redux-promise';
|
14 | import createLogger from 'redux-logger';
|
15 |
|
16 | const logger = createLogger();
|
17 | const store = createStore(
|
18 | reducer,
|
19 | applyMiddleware(thunk, promise, logger)
|
20 | );
|
21 |
|
22 | // Note passing middleware as the third argument requires redux@>=3.1.0
|
23 | ```
|
24 | Logger **must be** last middleware in chain, otherwise it will log thunk and promise, not actual actions ([#20](https://github.com/fcomb/redux-logger/issues/20)).
|
25 |
|
26 | ## API
|
27 |
|
28 | `redux-logger` exposes single constructor function for creating logger middleware.
|
29 |
|
30 | ```
|
31 | createLogger(options?: Object) => LoggerMiddleware
|
32 | ```
|
33 |
|
34 | ### Options
|
35 | ```js
|
36 | {
|
37 | level = 'log': 'log' | 'console' | 'warn' | 'error' | 'info', // console's level
|
38 | duration = false: Boolean, // Print the duration of each action?
|
39 | timestamp = true: Boolean, // Print the timestamp with each action?
|
40 | colors: ColorsObject, // Object with color getters. See the ColorsObject interface.
|
41 | logger = window.console: LoggerObject, // Implementation of the `console` API.
|
42 | logErrors = true: Boolean, // Should the logger catch, log, and re-throw errors?
|
43 | collapsed, // Takes a boolean or optionally a function that receives `getState` function for accessing current store state and `action` object as parameters. Returns `true` if the log group should be collapsed, `false` otherwise.
|
44 | predicate, // If specified this function will be called before each action is processed with this middleware.
|
45 | stateTransformer, // Transform state before print. Eg. convert Immutable object to plain JSON.
|
46 | actionTransformer, // Transform state before print. Eg. convert Immutable object to plain JSON.
|
47 | errorTransformer // Transform state before print. Eg. convert Immutable object to plain JSON.
|
48 | }
|
49 | ```
|
50 |
|
51 | ### Options
|
52 |
|
53 | #### __level (String)__
|
54 | Level of `console`. `warn`, `error`, `info` or [else](https://developer.mozilla.org/en/docs/Web/API/console).
|
55 |
|
56 | *Default: `log`*
|
57 |
|
58 | #### __duration (Boolean)__
|
59 | Print duration of each action?
|
60 |
|
61 | *Default: `false`*
|
62 |
|
63 | #### __timestamp (Boolean)__
|
64 | Print timestamp with each action?
|
65 |
|
66 | *Default: `true`*
|
67 |
|
68 | #### __colors (Object)__
|
69 | Object with color getter functions: `title`, `prevState`, `action`, `nextState`, `error`. Useful if you want to paint
|
70 | message based on specific state or action. Set any of them to `false` if you want to show plain message without colors.
|
71 |
|
72 | * `title(action: Object) => color: String`
|
73 | * `prevState(prevState: Object) => color: String`
|
74 | * `action(action: Object) => color: String`
|
75 | * `nextState(nextState: Object) => color: String`
|
76 | * `error(error: Any, prevState: Object) => color: String`
|
77 |
|
78 | #### __logger (Object)__
|
79 | Implementation of the `console` API. Useful if you are using a custom, wrapped version of `console`.
|
80 |
|
81 | *Default: `window.console`*
|
82 |
|
83 | #### __logErrors (Boolean)__
|
84 | Should the logger catch, log, and re-throw errors? This makes it clear which action triggered the error but makes "break
|
85 | on error" in dev tools harder to use, as it breaks on re-throw rather than the original throw location.
|
86 |
|
87 | *Default: `true`*
|
88 |
|
89 | #### __collapsed = (getState: Function, action: Object) => Boolean__
|
90 | Takes a boolean or optionally a function that receives `getState` function for accessing current store state and `action` object as parameters. Returns `true` if the log group should be collapsed, `false` otherwise.
|
91 |
|
92 | *Default: `false`*
|
93 |
|
94 | #### __predicate = (getState: Function, action: Object) => Boolean__
|
95 | If specified this function will be called before each action is processed with this middleware.
|
96 | Receives `getState` function for accessing current store state and `action` object as parameters. Returns `true` if action should be logged, `false` otherwise.
|
97 |
|
98 | *Default: `null` (always log)*
|
99 |
|
100 | #### __stateTransformer = (state: Object) => state__
|
101 | Transform state before print. Eg. convert Immutable object to plain JSON.
|
102 |
|
103 | *Default: identity function*
|
104 |
|
105 | #### __actionTransformer = (action: Object) => action__
|
106 | Transform action before print. Eg. convert Immutable object to plain JSON.
|
107 |
|
108 | *Default: identity function*
|
109 |
|
110 | #### __errorTransformer = (error: Any) => error__
|
111 | Transform error before print.
|
112 |
|
113 | *Default: identity function*
|
114 |
|
115 | ### Recipes
|
116 | #### log only in dev mode
|
117 | ```javascript
|
118 | import thunk from 'redux-thunk';
|
119 |
|
120 | const middlewares = [thunk];
|
121 |
|
122 | if (process.env.NODE_ENV === `development`) {
|
123 | const createLogger = require(`redux-logger`);
|
124 | const logger = createLogger();
|
125 | middlewares.push(logger);
|
126 | }
|
127 |
|
128 | const store = compose(applyMiddleware(...middlewares))(createStore)(reducer);
|
129 | ```
|
130 |
|
131 | #### transform `Symbol()` action type to string
|
132 | ```javascript
|
133 | import createLogger from 'redux-logger';
|
134 |
|
135 | const logger = createLogger({
|
136 | actionTransformer: (action) => ({
|
137 | ...action,
|
138 | type: String(action.type),
|
139 | });
|
140 | });
|
141 | ```
|
142 |
|
143 | #### log everything except actions with type `AUTH_REMOVE_TOKEN`
|
144 | ```javascript
|
145 | createLogger({
|
146 | predicate: (getState, action) => action.type !== AUTH_REMOVE_TOKEN
|
147 | });
|
148 | ```
|
149 |
|
150 | #### collapse actions with type `FORM_CHANGE`
|
151 | ```javascript
|
152 | createLogger({
|
153 | collapsed: (getState, action) => action.type === FORM_CHANGE
|
154 | });
|
155 | ```
|
156 |
|
157 | #### transform Immutable objects into JSON
|
158 | ```javascript
|
159 | import {Iterable} from 'immutable';
|
160 |
|
161 | const stateTransformer = (state) => {
|
162 | if (Iterable.isIterable(state)) return state.toJS();
|
163 | else return state;
|
164 | };
|
165 |
|
166 | const logger = createLogger({
|
167 | stateTransformer,
|
168 | });
|
169 | ```
|
170 |
|
171 | #### log batched actions
|
172 | Thanks to [@smashercosmo](https://github.com/smashercosmo)
|
173 | ```javascript
|
174 | import createLogger from 'redux-logger';
|
175 |
|
176 | const actionTransformer = action => {
|
177 | if (action.type === 'BATCHING_REDUCER.BATCH') {
|
178 | action.payload.type = action.payload.reduce((result, next) => {
|
179 | const prefix = result ? result + ' => ' : '';
|
180 | return prefix + next.type;
|
181 | }, '');
|
182 |
|
183 | return action.payload;
|
184 | }
|
185 |
|
186 | return action;
|
187 | };
|
188 |
|
189 | const level = 'info';
|
190 |
|
191 | const logger = {};
|
192 |
|
193 | for (const method in console) {
|
194 | if (typeof console[method] === 'function') {
|
195 | logger[method] = console[method].bind(console);
|
196 | }
|
197 | }
|
198 |
|
199 | logger[level] = function levelFn(...args) {
|
200 | const lastArg = args.pop();
|
201 |
|
202 | if (Array.isArray(lastArg)) {
|
203 | return lastArg.forEach(item => {
|
204 | console[level].apply(console, [...args, item]);
|
205 | });
|
206 | }
|
207 |
|
208 | console[level].apply(console, arguments);
|
209 | };
|
210 |
|
211 | export default createLogger({
|
212 | level,
|
213 | actionTransformer,
|
214 | logger
|
215 | });
|
216 | ```
|
217 |
|
218 | ### License
|
219 | MIT
|