Getting Started with Logging in React

updated on 12 April 2022

We all start with writing a bunch of console.log statements in our work-in-progress React components. But then, you find yourself tracking these guys down because it’s not great to have users see all the console logs in a production app.

Here, we’ll see that with a little structure we can start transforming a bad habit into a powerful best practice.

Log everything or clean console?
Log everything or clean console?

1. Our Little React Sandbox

Let’s quickly create a React app to play with, using yarn, create-react-app  and Typescript:

yarn create react-app --template typescript react-logging-start
cd react-logging-start
yarn start

We can now start playing around in src/App.tsx and add our usual   console.log()statements.

These should appear in your browser’s developer console:

Developer Console Logs from App.tsx
Developer Console Logs from App.tsx

In this case, it would be simple to remove or comment out the console.log() line before pushing the code to production, but this can become tedious as your application grows.

So what should we do? Let’s see how we can keep the log statements but suppress the outputs by building a simple wrapper around theconsoleobject.

2. Our Own Logging Wrapper

Let’s start by simply replicating the console functions.

Ah, but now we’ve lost the correct source file mapping in the browser console:

Developer Console Logs from App.tsx
Developer Console Logs from App.tsx

To preserve the correct source file lines, we can reuse the console functions themselves.

Now, we’re back to where we started:

Developer Console Logs from App.tsx
Developer Console Logs from App.tsx
But why?
But why?

Wait, wait, wait! There’s a reason we did all that work.

Now, we can customize our own console logger to do what we need.

 3. Let’s Level Up Our Logging Game

The first thing we can do is to make our ConsoleLogger configurable, we can tell it to output all logs, only the warnand errorlogs, or the error logs only.

We can see that setting the leveloption to error will make it drop log and warn messages while using the warn  level will make it drop log messages only.

The log level option is also optional, in which case the loglevel is used, i.e. all messages are outputted to the browser console.

Now we can try it by editing src/App.tsx and setting the level option. Using the warn level, there should now be only two logs printed in the console: 
const logger = new ConsoleLogger({ level: 'warn' });

“But I still need to find and replace all those ConsoleLogger thingies before pushing to production!”

Ah, yes… But you can also create a global logger options object to help you:

Now, you can see the difference when running the app:

yarn start  # Will show all logs
REACT_APP_APP_ENV='production' yarn start  # Will show only 'warn' and
'error' logs
# Remember to build the production App with:
REACT_APP_APP_ENV='production' yarn build

If you’ve managed to stay on the ride with me up till now, you know you can already use  logger.log() everywhere and know it will be removed in the production builds.

Note: You can replace process.env.REACT_APP_APP_ENV  with process.env.NODE_ENV  to have log levels configured by create-react-app (see docs).

4. Exporting the logger

One last step we can do is to export the logger so that we can simply import it and reuse it in all the components of our React application.

As you can see, we can now add import { logger } from './logger'; 
everywhere we want to use our logger, without the need to create a new instance each and every time.

Conclusion

Wow, you made it!

celebrate-wrv9i

I understand your enthusiasm 😂️. While this may not look like much right now, it’s still a nice start towards good logging hygiene.

With our quick setup we can now replace all the console.log() statements we have with logger.log() and we won’t have to track them down before building a production app. This encourages you to still use logging statements while developing.

Next Steps

What can you do from here?

  • As your application grows, you may find that keeping all log() statements in development is becoming too verbose. You can disable the log  level in development too and use it only in the components you’re working on (by creating a new   logger instance).
  • If you'd like to catch issues and errors before they hit production, you can try Meticulous to automatically test your code. 
  • You can add logging to Sentry or other monitoring platforms in production. This will allow you to capture warning  and error  events even when they don’t crash your application.

Authored by Johann-Michael Thiebaut, engineer at Meticulous.

Read more