Recently, I've found a straightforward debugging method that has turned out to be quite handy.
This approach offers a simple and effective way to debug RxJs code in Angular apps, and it applies to any RxJs-based project as well.
While we might see more sophisticated debugging tools for RxJs in the future, if you're starting an Angular project now and need a practical way to track what's happening while keeping your code understandable, this technique fits the bill.
You can safely use this in production. It serves as a solid safeguard against memory leaks and other issues that tend to sneak in, as we'll demonstrate shortly.
The RxJs tap operator
Logging is a side-effect, and the RxJs operator specifically designed for that is the tap operator. You can use it to debug RxJs like this:
If you need to modify the value before logging, you can define a function with arrow syntax. Alternatively, if you just pass the console.log function directly to the tap operator, it will log the values flowing through the observable chain as-is.
The limitation of using the tap operator in this manner
The main drawback is that there's no built-in way to disable logging in a production environment. You might want to keep logging always active, but the output can become too verbose.
It would be ideal to have this detailed information available only during development, and to enable it in production only when absolutely necessary.
To solve this, we'll create a custom RxJs operator that we'll implement from scratch, which we'll call the debug operator.
The RxJs debug operator
Here's a sample of Angular RxJs code that's being monitored with this new operator we're about to build:
And this is what shows up in the console:
Loading participant from backend Object {id: 1, name: "Alice"}
This is exactly what we're aiming for: a single line in the console with a descriptive message at the start, followed by the data emitted by the observable right after it on the same line.
Note that alongside the debugging message text, we can also specify the logging level for the message. For instance, messages at level INFO will appear in production, whereas those at DEBUG or TRACE level will be limited to development.
However, you can also activate DEBUG messages in production if the situation calls for it. The debug operator is not a standard part of RxJs, so how do we go about implementing it?
A straightforward implementation of the debug operator
Here's how we can build the custom RxJs debug operator:
So, what's happening here? Essentially, the debug operator is a function that takes in an observable and returns another Observable, just like any other operator.
Internally, it leverages the tap operator for console logging, but with a key difference: the logging is conditional on the minimum logging level being met.
You can set the overall logging level for the application using the setRxJsLoggingLevel function, which defaults to INFO.
A strong safeguard against common issues
As your codebase grows in complexity, tracking the various observable chains can become challenging without logging. It's wise to incorporate debug logging from the very beginning and consistently review the console output during development.
If any anomalies arise, such as:
- a subscription that should have been disposed of but is still active (which could cause a memory leak)
- multiple subscriptions when only one was anticipated
These kinds of problems can be identified and addressed early by monitoring the log during development and continuously verifying our assumptions about how the program actually operates.
Feel free to share in the comments below what other approaches you typically use for debugging RxJs code.
I trust you found this post helpful. Be sure to check out the resources below for more articles and materials on Angular.
We encourage you to subscribe to our newsletter to stay updated on future posts like this one.
And if you're interested in diving deeper into RxJs, we suggest exploring the RxJs In Practice Course course, which covers a wide range of useful patterns and operators in greater depth.
For those aiming to apply RxJs specifically within Angular applications, the Reactive Angular Course is recommended, as it explores various common reactive design patterns for building Angular apps.
If you're new to Angular, take a look at the Angular for Beginners Course:
<h2>Other posts on Angular</h2>
<p>If you enjoyed this post, have also a look also at other popular posts that you might find interesting: </p>
- Angular Router - How To Build a Navigation Menu with Bootstrap 4 and Nested Routes
- Angular Router - Extended Guided Tour, Avoid Common Pitfalls
- Angular Components - The Fundamentals
- How to build Angular apps using Observable Data Services - Pitfalls to avoid
- Introduction to Angular Forms - Template Driven vs Model Driven
- Angular ngFor - Learn all Features including trackBy, why is it not only for Arrays ?
- Angular Universal In Practice - How to build SEO Friendly Single Page Apps with Angular
- How does Angular Change Detection Really Work ?
- Typescript 2 Type Definitions Crash Course - Types and Npm, how are they linked ? @types, Compiler Opt-In Types: When To Use Each and Why ?
