Create a custom RxJS Operator – Debug Operator

Sometimes in reactive programming its difficult to understand logic or code when we are using multiple operators, it’s not always easy to read through the observable chain, so in order to better understand the program and to troubleshoot the code we often use the tap operator to log statements to the console.

For example: Say, we have a search input on the page and we want to look at the search values user is inputting. For this, we certainly use the tap operator to log the search string right?. See below.

fromEvent<any>(this.input.nativeElement, 'keyup')
        .pipe(
            tap(search => console.log('search input:', search))
        );

This is fine, but, what if we want to log different statement?, we are going to use the tap operator again, and again maybe on other observables!!. This is not very productive and impossible to scale.

For this purpose we can actually create a custom operator to log statements to the console and also do much more. See below.

export const debug = (message: string) => 
    (source: Observable<any>) => source
        .pipe(
            tap(val => {
                console.log(message + ': ', val);
            }));

Here, we have created a custom operator called debug and it simply logs the message and value.

This operator can also be easily scaled to take different log levels and log statements accordingly, i.e, conditionally output the message depending on the logging level. See below.

// Define the logging levels
export enum LoggingLevel {
    INFO,
    DEBUG,
    ERROR
}

// log the message based on the logging level
export const debug = (level: number, message: string) => 
    (source: Observable<any>) => source
        .pipe(
            tap(val => {
                if (level === LoggingLevel.INFO) {
                    console.log(message + ': ', val);
                } else if (level === LoggingLevel.DEBUG) {
                    console.warn(message + ': ', val);
                } else if (level === LoggingLevel.ERROR) {
                    console.error(message + ': ', val);
                }
            }));

Here, we have defined multiple logging levels and for each log level we are logging different type of statement to the console.

Finally apply the debug operator on the input search. See below.

fromEvent<any>(this.input.nativeElement, 'keyup')
        .pipe(
            // For console.log
            debug(LoggingLevel.INFO, 'search'),
            // For console.warn
            debug(LoggingLevel.DEBUG, 'warning'),
            // For console.error
            debug(LoggingLevel.ERROR, 'error'),
        );

Now, as you type in the input search you should see the logging statements on the console, like below.

Our custom RxJS debug operator is working!!.

Published by Kumar Gandhi K

Hi! I’m Kumar and I live in Bangalore (IN) with my family. By profession I’m a Web Developer experienced in a vast variety of frameworks and technologies, like, HTML, CSS, JavaScript, Angular, Bootstrap… Using these i have built or sometimes maintained mid market and enterprise level applications. I worked for few software companies over the years and on few domains like finance, field-service and storage. I also did consulting job at one point. I am loyal and hard (or for better word smart) working individual. In my free time I read books, in fact I buy a lot of books hoping that some day I might find all the time in the world to read them and I also enjoy watching TV.

Leave a comment