DEV Community

François-Emmanuel CORTES
François-Emmanuel CORTES

Posted on

[At Run Time] Adaptative Log Function

When debugging some buge coding project, you want sometimes to drop a console.log() calls to track some varaible and errors, to figure out what is happening during program execution, especially nearby potential tricky sections of it; something like:

function danger (a: number, b: number) {
    console.log ('### (title "h3") the dangerous function is here...')

    try {
        return a / b
    } catch (err) {
        console.log ('posssible divisoion by zero !')
        console.log ({a, b })

        throw new Error ('#DIVIDE_BY_ZERO')
    }
}
Enter fullscreen mode Exit fullscreen mode

This approach gives you the ability to see the error at its location.

But the more code grows and the more logging calls occurrences grows together... and when comes And that produces time-consuming task to remove these calls (manually or not): lot of work in perpsective, and risks to waste time introducing some garbage (characters typos) and need to fix it again.

Logger class (first idea)

The idea for now is to add a Logger/Debugger class to filter console.log calls and shutdown its messages when the production phase comes.

function danger (a: number, b: number) {
    const debug = Debug.getInstance ()

    debug.level (3).title ('the dangerous function is here...')

    try {
        return a / b
    } catch (err) {
        debug.level (2).title ('posssible divisoion by zero !')
        debug.level (3).dump ({a, b })

        throw new Error ('#DIVIDE_BY_ZERO')
    }
}    
Enter fullscreen mode Exit fullscreen mode

Note: the singelton instance exposes a level method that returns a fluent interface, backed by some closure and bounding pattern, and wrap console.log calls:

// Debug class
protected verbosity = 0

protected log (effective: number, something) {
    if (this.verbosity < effective ) {
        // here we effectively log in the browser
        console.log (something)
    }
}

protected title (level: number, text: string) {
   const message = '#'.repat (level) + ' ' + text
   this.log (level, message)
}

protected dump (level: number,something) {
   this.log (level, something)
}

public level (wandered: number) {
    return {
        title: this.title.bind (this, this.verbosiry),
        dump: this.dump.bind (this, this.verbosiry),            
    }
}
Enter fullscreen mode Exit fullscreen mode

No it's OK logginh process is filterd properly. Adapt it now ?

Adaptative ? OK for now !

Declare a setter for thos.verbosity value:

// default behaviour:  shutdown all logs (silent)
public adapt (wantered: number = 0) {
    this.verbosity = wandered
}
Enter fullscreen mode Exit fullscreen mode

USE CASE: dangerous functions

  • Phase of self-tests of program: log enough stuff;
  • Phase Production: log normally and minimally (0: silently, when possible);
  • Increase drastrically verbosity just before throwing errors:
  • if error is catched properly at a higher level in call stack , adapt level to 0, to turn it off again !
    function danger (a: number, b: number) {
        const debug = Debug.getInstance ()

        debug.level (3).title ('the dangerous function is here...')

        try {
            return a / b
        } catch (err) {
            // now we have all errors log:
            debug.adapt (10)
            debug.level (2).title ('posssible divisoion by zero !')
            debug.level (3).dump ({a, b })

            throw new Error ('#DIVIDE_BY_ZERO')
        }
    }    

    function process (iterations: number) {
        const debug = Debug.getInstance ()

        for (let a = 0; a < iterations; a++) {
            for (let b = 0; b < iterations; b++) {}        
                // print all results
                // debug.level (0).dump (danger (a,b ))

                // or log anyway, print, do whatever with results...
                console.log (danger (an b))
            }
    }

    // *** caller code (main routine) ***
    const debug = Debug.getInstance ()       

    // self tests
    debug.adapt (1)
    process (1)    

    // produiuction phase: NO MPGS
    debug.adapt (0)
    process (1000 * 1000)    

Enter fullscreen mode Exit fullscreen mode

Doing like this, we adapt the logging mechanism to see clearly what is happening diring tests phase and after dangerous runtime error occurrence, the rest of (normal) run time we don't pollute the briwser's console anymore, neither altering performances anymore.

Happy coding !

Top comments (0)