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')
}
}
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')
}
}
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),
}
}
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
}
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)
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 !