Skip to content

util.debuglog callback argument behavior and purpose appears to be documented incorrectly #56676

Open
@GB609

Description

@GB609

Affected URL(s)

https://nodejs.org/docs/latest/api/util.html#utildebuglogsection-callback

Description of the problem

The usage example of the callback function for util.debuglog is not sufficiently documented imho.
Moreover, when looking at the code, it also seems to even work differently than described.

The example for the callback does the following:

const util = require('node:util');
let debuglog = util.debuglog('internals', (debug) => {
  // Replace with a logging function that optimizes out
  // testing if the section is enabled
  debuglog = debug;
});

What debuglog effectively does is:

function debuglog(set, cb){
  realLogFunction = (...args){
     init() //sets up the set name and an enabled boolean value

     // creates a noop function when enabled=false
     realLogFunction = debugLogImpl(enabled) 
     if(typeof cb == "function"){
       // this is the part where the documentation is lacking
       cb(realLogFunction) //code depends on side-effects of the callback?
     }
     // this line is only effective the very first time, when still in the factory
     // likely to not 'swallow' the first log line that lazily inits the real logger
     realLogFunction(...args)
  }

  //left out for brewity, but works on the same principle as realLogFunction
  let innerEnabledCheck ()=>{...}
  
  logDelegate = (...) => {
    //some switch on argument length, but effectively always results in the next line, with a varying
    //amount of arguments passed on.
    realLogFunction(args)
  }
  logDelegate.enabled = innerEnabledCheck() //left out for brewity
  return logDelegate;
}

The first time logDelegate is called, the enabled test is already optimized out and logDelegate will call the now-changed realLogFunction generated from debugLogImpl.
What actually happens when the callback is used as in the documentation's example, is that the outside variable, (debuglog in the example) which points to logDelegate, will be replaced by realLogFunction.

Thus, what is 'optimized out' is the switch in logDelegate when the callback is used as shown in the example, but at the price of also losing the enabled getter. 'Testing if the section is enabled' is always automatically and implicitly optimized out in the inner factory method.

Metadata

Metadata

Assignees

No one assigned

    Labels

    docIssues and PRs related to the documentations.utilIssues and PRs related to the built-in util module.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions