Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Redux Logging in Production

DZone's Guide to

Redux Logging in Production

Redux is a great help when it comes to debugability. Learn how to set up LogRocket in a production application as a Redux tool.

· Performance Zone ·
Free Resource

Maintain Application Performance with real-time monitoring and instrumentation for any application. Learn More!

One of the greatest strengths of Redux is debugability. By logging actions and state during an app’s execution, developers can easily understand code errors, race conditions, network errors, and other sources of bugs.

In local development, it is standard practice to use tools like redux-logger or redux-devtools for time-travel debugging and viewing Redux actions. But the benefits of using Redux logs to easily fix bugs are most significant in production.

To do this, some developers build home-grown solutions or leverage existing backend logging tools, but making this work is not trivial. Redux data must be collected and uploaded efficiently, without compromising application performance, and on the backend, this data (which is quite sizable) must be stored and made easily searchable for debugging issues.

LogRocket is the first production Redux logging tool for web apps. It has a highly optimized JavaScript SDK and Redux middleware, and can easily scale to support apps with millions of users. In addition to recording Redux data, LogRocket also records network requests, console logs, JavaScript errors, and full DOM video. Having this context in addition to Redux logs is crucial when fixing bugs since it essentially has all of the information you’d find in the Chrome dev-tools when developing locally.

In this post, I’ll take a quick look at setting up LogRocket in a production app. Then, I’ll discuss how to leverage Redux to maximize app debuggability.

Setting Up LogRocket

Setting up LogRocket is easy and only requires adding a few lines of code to your app:

  1. Install with NPM: npm i --save logrocket.

  2. Create a free account and take note of your application ID.

  3. Initialize LogRocket in your app:

    import LogRocket from 'logrocket';
    
    // Initialize LogRocket with your app ID
    LogRocket.init(<your_application_id>);
  4. Add the Redux middleware.

    import { applyMiddleware, createStore } from 'redux';
    
    const store = createStore(
      reducer, // your app reducer
      applyMiddleware(middlewares, LogRocket.reduxMiddleware()),
    );

That’s it for the basic setup. This is all you need to get started with LogRocket! Later, I’ll discuss customizing LogRocket by doing things like action blacklisting, data scrubbing, and video configuration.

Viewing Logs From User Sessions

Image title

LogRocket groups logs from each user session into a “session,” accessible with a unique URL. You can get a session link in your app by calling LogRocket.getSessionURL() with a callback like this:

LogRocket.getSessionURL(url => {
  console.log(url)
});

This will print a link to the JavaScript console for the current session when you run your app. Later, I’ll show how you to integrate LogRocket into error-tracking and support workflows, but for now, just clicking this link in the console will let you see the logs for your current session when you run your app.

Image title

The Redux log viewer shows all of the Redux actions that occurred in the app during this session. Clicking on a Redux action lets you explore application state before and after the action to see the effect it had on your store.

Image title

Sometimes, Redux logs alone aren’t enough to understand a bug — especially when dealing with user-reported issues. LogRocket’s DOM replay helps here by letting you see exactly what a user saw in your app.

Since this video is actually a reconstruction of the DOM (and not a real video) you can inspect HTML/CSS to understand visual bugs or play at 2x speed to gain a quick understanding of what a user did on the app when handling support issues.

Image title

LogRocket captures both network requests and responses and lets you dig into specific requests and see the headers and body. The waterfall chart shows timings, making it easy to see which requests were slow, or if a potential race condition occurred.

Advanced Configuration

DOM Scrubbing

If your app has sensitive data like a password or credit card input, you can add the class _lr-hide to any DOM nodes to prevent that data from ever leaving the browser.

Action Scrubbing

Sometimes, an app may have actions that are repeated very frequently and that are not of use when debugging. You can scrub these by providing an actionSanitizer function in the Redux middleware. Any action for which this function returns null won’t be logged.

LogRocket.reduxMiddleware({
  actionSanitizer: function (action) {
    if (action.type === 'ignoreThis') {
      return null;
    }
    return action;
  },
});

State Sanitization

Similar to action scrubbing, you can prevent certain subtrees of your Redux store from being logged like this:

LogRocket.reduxMiddleware({
  stateSanitizer: function (state) {
    return {
      ...state,
      removeThisKey: undefined,
    };
  },
});

Integrating Redux Logging Into Your Workflow

Redux logs often hold the key to solving crashes and user-reported issues, so it can be helpful to integrate redux logging with error reporting and support tools.

Error Reporting

Most error-reporting tools have an API for attaching arbitrary context to bug reports. We can make use of this by attaching a LogRocket recording URL to each bug report, so when we are notified of a bug, we can play back the Redux actions to figure out what happened.

As an example, in Sentry (a popular crash-reporting tool) the integration looks like this, and most other crash reporting tools have similar APIs.

Raven.setDataCallback(function (data) {
  data.extra.sessionURL = LogRocket.sessionURL;
  return data;
});

Support

All too often, users will report issues but not give enough context to figure out exactly what happened.

If you are using a chat support tool like Intercom, you can integrate LogRocket directly so that it adds a note with a recording URL whenever a user starts chatting.

Image title

Or, if you are integrating with a more general analytics tool, you can add recording URLs with a tracking API like this:

LogRocket.getSessionURL(function (sessionURL) {
  analytics.track('LogRocket recording', sessionURL);
});

Making the Most of Production Redux Logging

Production logging is immediately useful in most Redux apps, but by architecting your app with logging in mind, you can ensure that logs are maximally useful when debugging issues.

Try to Keep Most State in Redux

I don’t want to get into the debate on local vs. Redux state here, but when deciding whether a given piece of state should be in Redux, ask yourself if seeing that state could be helpful when debugging issues. If the answer is yes, consider putting that state in Redux so that it will be logged with crash reports and user issues.

Use Data Fetching Libraries That Leverage Redux

Libraries like apollo-client for GraphQL, and redux-query for REST both facilitate fetching data from the network via Redux. They use Redux as a persistence layer, meaning that when debugging issues, you can inspect your Redux logs to see what data these clients have fetched.

If you’d prefer a simpler approach, you can roll your own data fetching “framework” by simply dispatching explicit actions when querying and receiving data from the network.

Use Redux to Handle Sources of Non-Determinism

When accessing data from APIs like websockets, local storage, IndexedDB, or even Date(), consider dispatching Redux actions with the result, so that you can easily debug these in the future. For example, when listening on a websocket, dispatch a Redux action on every message- that way you can see the data in your Redux logs.

Leverage Other Console Apis

Console methods like console.time(), console.count() and console.group() let you add rich data to your logs like React component render counts, transaction timings and component lifecycle logs. If you’re interested in learning more, I wrote a post about this here.

Build and Upload Source Maps to LogRocket

LogRocket supports source maps which you can upload via a CLI. By doing this you can see symbolicated stack traces for JavaScript errors, Redux actions, console logs and network requests, which lets you see where particular actions were triggered in your code.

Conclusion

React and Redux are often lauded as tools for building maintainable applications — a significant component of which is debuggability. Logging Redux data in production gives such insight since bugs and other user-reported issues can be easily debugged by inspecting Redux state, network requests, and the DOM.

When architecting a Redux app, consider practices (such as the few I outlined above) that leave a clearer audit trail to increase debuggability.

Finally, I’d like to note that fixing bugs is just one application of Redux logging. In the next part of this series, I will write about how to build an analytics pipeline with your Redux data.

Collect, analyze, and visualize performance data from mobile to mainframe with AutoPilot APM. Learn More!

Topics:
react ,redux ,logging ,debug ,tutorial ,performance

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}