Skip to content

Commit

Permalink
Allow ActionLogger to handle non-Redux actions
Browse files Browse the repository at this point in the history
  • Loading branch information
Ashoat committed Apr 6, 2020
1 parent 96ee45a commit d96bab0
Show file tree
Hide file tree
Showing 9 changed files with 259 additions and 194 deletions.
4 changes: 2 additions & 2 deletions lib/reducers/entry-reducer.js
Expand Up @@ -73,7 +73,7 @@ import {
} from '../shared/entry-utils';
import { threadInFilterList } from '../shared/thread-utils';
import { getConfig } from '../utils/config';
import { reduxLogger } from '../utils/redux-logger';
import { actionLogger } from '../utils/action-logger';
import { values } from '../utils/objects';
import { sanitizeAction } from '../utils/sanitization';

Expand Down Expand Up @@ -738,7 +738,7 @@ function findInconsistencies(
calendarQuery,
pollResult: oldResult,
pushResult: newResult,
lastActions: reduxLogger.interestingActionSummaries,
lastActions: actionLogger.interestingActionSummaries,
time: Date.now(),
},
];
Expand Down
4 changes: 2 additions & 2 deletions lib/reducers/thread-reducer.js
Expand Up @@ -44,7 +44,7 @@ import {
} from '../actions/thread-actions';
import { saveMessagesActionType } from '../actions/message-actions';
import { getConfig } from '../utils/config';
import { reduxLogger } from '../utils/redux-logger';
import { actionLogger } from '../utils/action-logger';
import { sanitizeAction } from '../utils/sanitization';

function reduceThreadUpdates(
Expand Down Expand Up @@ -128,7 +128,7 @@ function findInconsistencies(
action: sanitizeAction(action),
pollResult: oldResult,
pushResult: newResult,
lastActions: reduxLogger.interestingActionSummaries,
lastActions: actionLogger.interestingActionSummaries,
time: Date.now(),
},
];
Expand Down
6 changes: 3 additions & 3 deletions lib/socket/socket.react.js
Expand Up @@ -72,7 +72,7 @@ import CalendarQueryHandler from './calendar-query-handler.react';
import ReportHandler from './report-handler.react';
import { updateActivityActionTypes } from '../actions/activity-actions';
import { unsupervisedBackgroundActionType } from '../reducers/foreground-reducer';
import { reduxLogger } from '../utils/redux-logger';
import { actionLogger } from '../utils/action-logger';

type Props = {|
detectUnsupervisedBackgroundRef?: (
Expand Down Expand Up @@ -676,8 +676,8 @@ class Socket extends React.PureComponent<Props, State> {
this.props.connection.status !== 'connected' ||
!this.messageLastReceived ||
this.messageLastReceived + serverRequestSocketTimeout >= Date.now() ||
(reduxLogger.mostRecentActionTime &&
reduxLogger.mostRecentActionTime + 3000 < Date.now())
(actionLogger.mostRecentActionTime &&
actionLogger.mostRecentActionTime + 3000 < Date.now())
) {
return false;
}
Expand Down
156 changes: 156 additions & 0 deletions lib/utils/action-logger.js
@@ -0,0 +1,156 @@
// @flow

import { rehydrateActionType } from '../types/redux-types';
import type { ActionSummary } from '../types/report-types';

import inspect from 'util-inspect';

import { saveDraftActionType } from '../actions/miscellaneous-action-types';
import { sanitizeAction } from './sanitization';

const uninterestingActionTypes = new Set([
saveDraftActionType,
'Navigation/COMPLETE_TRANSITION',
]);
const maxActionSummaryLength = 500;

class ActionLogger {
static n = 30;
lastNActions = [];
lastNStates = [];
currentReduxState = undefined;
currentOtherStates = {};

get preloadedState(): Object {
return this.lastNStates[0].state;
}

get actions(): Object[] {
return this.lastNActions.map(({ action }) => action);
}

get interestingActionSummaries(): ActionSummary[] {
return this.lastNActions
.filter(({ action }) => !uninterestingActionTypes.has(action.type))
.map(({ action, time }) => ({
type: action.type,
time,
summary: ActionLogger.getSummaryForAction(action),
}));
}

static getSummaryForAction(action: Object): string {
const sanitized = sanitizeAction(action);
let summary,
length,
depth = 3;
do {
summary = inspect(sanitized, { depth });
length = summary.length;
depth--;
} while (length > maxActionSummaryLength && depth > 0);
return summary;
}

prepareForAction() {
if (
this.lastNActions.length > 0 &&
this.lastNActions[this.lastNActions.length - 1].action.type ===
rehydrateActionType
) {
// redux-persist can't handle replaying REHYDRATE
// https://github.com/rt2zz/redux-persist/issues/743
this.lastNActions = [];
this.lastNStates = [];
}
if (this.lastNActions.length === ActionLogger.n) {
this.lastNActions.shift();
this.lastNStates.shift();
}
}

addReduxAction(action: Object, beforeState: Object, afterState: Object) {
this.prepareForAction();

if (this.currentReduxState === undefined) {
for (let i = 0; i < this.lastNStates.length; i++) {
this.lastNStates[i] = {
...this.lastNStates[i],
state: {
...this.lastNStates[i].state,
...beforeState,
},
};
}
}
this.currentReduxState = afterState;

const state = { ...beforeState };
for (let stateKey in this.currentOtherStates) {
state[stateKey] = this.currentOtherStates[stateKey];
}

const time = Date.now();
this.lastNActions.push({ action, time });
this.lastNStates.push({ state, time });
}

addOtherAction(
key: string,
action: Object,
beforeState: Object,
afterState: Object,
) {
this.prepareForAction();

const currentState = this.currentOtherStates[key];
if (currentState === undefined) {
for (let i = 0; i < this.lastNStates.length; i++) {
this.lastNStates[i] = {
...this.lastNStates[i],
state: {
...this.lastNStates[i].state,
[key]: beforeState,
},
};
}
}
this.currentOtherStates[key] = afterState;

const state = {
...this.currentState,
[key]: beforeState,
};

const time = Date.now();
this.lastNActions.push({ action, time });
this.lastNStates.push({ state, time });
}

get mostRecentActionTime(): ?number {
if (this.lastNActions.length === 0) {
return null;
}
return this.lastNActions[this.lastNActions.length - 1].time;
}

get currentState(): Object {
const state = this.currentReduxState ? { ...this.currentReduxState } : {};
for (let stateKey in this.currentOtherStates) {
state[stateKey] = this.currentOtherStates[stateKey];
}
return state;
}
}

const actionLogger = new ActionLogger();

const reduxLoggerMiddleware = (store: *) => (next: *) => (action: *) => {
const beforeState = store.getState();
const result = next(action);
const afterState = store.getState();
actionLogger.addReduxAction(action, beforeState, afterState);
return result;
};

export { actionLogger, reduxLoggerMiddleware };
96 changes: 0 additions & 96 deletions lib/utils/redux-logger.js

This file was deleted.

9 changes: 4 additions & 5 deletions native/crash.react.js
Expand Up @@ -33,13 +33,12 @@ import invariant from 'invariant';
import { connect } from 'lib/utils/redux-utils';
import { sendReportActionTypes, sendReport } from 'lib/actions/report-actions';
import sleep from 'lib/utils/sleep';
import { reduxLogger } from 'lib/utils/redux-logger';
import { actionLogger } from 'lib/utils/action-logger';
import { logOutActionTypes, logOut } from 'lib/actions/user-actions';
import { sanitizeAction, sanitizeState } from 'lib/utils/sanitization';
import { preRequestUserStateSelector } from 'lib/selectors/account-selectors';

import Button from './components/button.react';
import { store } from './redux/redux-setup';
import { persistConfig, codeVersion, getPersistor } from './redux/persist';

const errorTitles = ['Oh no!!', 'Womp womp womp...'];
Expand Down Expand Up @@ -156,9 +155,9 @@ class Crash extends React.PureComponent<Props, State> {
stack: data.error.stack,
componentStack: data.info && data.info.componentStack,
})),
preloadedState: sanitizeState(reduxLogger.preloadedState),
currentState: sanitizeState(store.getState()),
actions: reduxLogger.actions.map(sanitizeAction),
preloadedState: sanitizeState(actionLogger.preloadedState),
currentState: sanitizeState(actionLogger.currentState),
actions: actionLogger.actions.map(sanitizeAction),
});
this.setState({
errorReportID: result.id,
Expand Down

0 comments on commit d96bab0

Please sign in to comment.