Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to detect debug mode #9617

Closed
IonicaBizau opened this issue Nov 15, 2016 · 35 comments
Closed

How to detect debug mode #9617

IonicaBizau opened this issue Nov 15, 2016 · 35 comments
Labels
question Issues that look for answers.

Comments

@IonicaBizau
Copy link
Contributor

In 7.0.0, looks like the typeof v8debug always returns undefined. How to detect if the process is running in the debug mode?

@cjihrig
Copy link
Contributor

cjihrig commented Nov 15, 2016

Check out the discussion in #7102.

@IonicaBizau
Copy link
Contributor Author

@cjihrig That's useful to know, but I'd like to have a solution without that flag: just another way to know if the process is in the debug mode (maybe some environment variable which is set by the debugger or something like that)?

Thanks!

@bnoordhuis
Copy link
Member

Why would you care whether the process is being debugged or not? To answer your question, there is no real way to determine if the debugger is active (that is future proof.)

@IonicaBizau
Copy link
Contributor Author

@bnoordhuis There are some features I want to disable in the debug mode to make the debugging easier. That's pretty much it.

@bnoordhuis
Copy link
Member

You can only divine it indirectly. For example, vm.runInDebugContext('Debug').scripts() throws an 'illegal access' exception unless the debugger is active. It only works with some node.js versions and will likely stop working altogether in the future.

@mscdex mscdex added debugger question Issues that look for answers. labels Nov 15, 2016
@mscdex
Copy link
Contributor

mscdex commented Nov 15, 2016

Another possible way to check for debug mode (asynchronously) is to simply try to bind to the debug port:

function isDebugging(cb) {
  require('net').createServer().on('error', function(err) {
    if (err.code === 'EADDRINUSE')
      cb(null, true);
    else
      cb(err);
  }).listen(process.debugPort, function() {
    this.close();
    cb(null, false);
  });
}

@IonicaBizau
Copy link
Contributor Author

@mscdex Thanks! I'd prefer a sync version, tho. Actually, isn't possible just to set an environment variable or a global (like before) when debugging?

@mscdex
Copy link
Contributor

mscdex commented Nov 15, 2016

@IonicaBizau Well, if you are adventurous and don't mind relying on a "private" API, here is a synchronous version of my above solution....

function isDebugging() {
  var TCP = process.binding('tcp_wrap').TCP;
  var tcp = new TCP();
  var r;
  function doBind() {
    var err = tcp.bind6('::', process.debugPort);
    if (err)
      err = tcp.bind('0.0.0.0', process.debugPort);
    return err;
  }
  doBind();
  r = doBind();
  if (r) {
    tcp.close();
    return false;
  }
  return true;
}

@bnoordhuis
Copy link
Member

I think this has been answered. Closing.

@IonicaBizau
Copy link
Contributor Author

@mscdex Thanks for that! 👍

@IonicaBizau
Copy link
Contributor Author

@mscdex That code returns true even another process is being debugged. Is there any way to tell if the current process is debugged?

@zurgul
Copy link

zurgul commented Aug 30, 2017

It seems more simple way is to check execArgv. In DEBUG mode there should be 'debug' or 'inspect' word in argument's list.

const argv = process.execArgv.join();
const isDebug = argv.includes('inspect') || argv.includes('debug'));

@eugeneo
Copy link
Contributor

eugeneo commented Aug 30, 2017

See https://nodejs.org/api/inspector.html

Note that there is no special "debug mode". What you may detect is whether or not inspector WebSocket server is running. Another is if there's any inspector session connected (currently you can create the session through the WebSocket connection or by using the JS API). Currently you can detect ongoing session by trying to connect another one and then catching this exception - but this will most likely stop working down the line once concurrent sessions are supported.

@zurgul
Copy link

zurgul commented Aug 30, 2017

@eugeneo Right, if inspection is initiated programmatically my method is useless, however if the project isn't a public library, so developers are fully in control of how debug can be initiated, then execArgv check would be sufficient.

@AMorgaut
Copy link

AMorgaut commented Jan 30, 2019

As said @zurgul, checking process.execArgv doesn't work if the process switched to debug mode after a regular launch:

  • if it receives a 'SIGUSR1' signal
  • via process._debugProcess(pid)

I also thought about sending a request to:

  • http://localhost:${process.debugPort}/json/version
  • or http://localhost:${process.debugPort}/json

but a 200 OK response might come from another node process.

The only reliable solution to me is the one mentioned by @mscdex
here a promise variant (then usable with async/await) I wrote to authorize some actions (like running an eval) only if we are in debug mode

const REJECT = new Error('Action refused, The UI process is not in debug mode');
const authorize = () => new Promise((resolve, reject) => net.createServer()
    .on(
        'error',
        ({ code }) => ((code === 'EADDRINUSE') ? resolve() : reject(REJECT))
    )
    .listen(process.debugPort, function () {
        this.close();
        reject(REJECT);
    })
);

It would be awesome if we could have a process.debugSession or process.debugId returning the debugger session id when active and null otherwise

@dandv
Copy link
Contributor

dandv commented Mar 17, 2019

Why would you care whether the process is being debugged or not?

One use case I ran into was to set the timeout for tests to infinity if I'm stepping through the code, instead of the test timing out after the 5-second default timeout limit.

Should this issue be reopened?

@AMorgaut
Copy link

AMorgaut commented Mar 21, 2019

Why would you care whether the process is being debugged or not?

In my context, I have a side inspect protocol that must accept requests only if the process is in debug/inspect mode.

@dandv I'd love to see it reopened, I think the cost would be minimal to have it natively

@nicszerman
Copy link

There should definitely be a standard easy-to-use method to detect whether the process is running on debug mode or not. The most reliable solution at the moment seems to be to pass a flag initially, and spawn child processes with this flag if it also is present in the parent. This is annoying and should be unnecessary. There should also be an option when spawning children that enables inspect if and only if the parent is also in inspect mode.

@alexkozy
Copy link
Member

pptr uses inspector module to detect that process is running under inspection: code.
As @eugeneo mentioned it detects that some debugger can connect to process but not that debugger is connected right now.

@benjamingr
Copy link
Member

I think we should do this - any strong opinions ?

@bnoordhuis
Copy link
Member

The question "how to detect debug mode" is wrong though. The debugger (inspector) is always enabled.

A better question is "is a client attached" but that's still kind of the wrong thing to ask because a client might be tracing or profiling but not debugging.

"Has the Debugger.enable protocol command been executed by a client yet" comes closest but even that doesn't necessarily mean the client is actively debugging - it might for example only be interested in uncaught exceptions.

@nicszerman
Copy link

@bnoordhuis there is some method of debugging that 99% of users use (myself included). I think that what's important is that there is a native way to easily detect that

@bnoordhuis
Copy link
Member

So what definition of debugging is that? When stepping? When breakpoints are set? When the script is paused?

(You wouldn't be able to detect that last one, of course!)

As to your 99% argument: it's only a matter of time before people start opening issues complaining our naive new API doesn't work for their legitimate use cases. "Good enough" often isn't.

@nicszerman
Copy link

nicszerman commented Aug 15, 2019 via email

@bnoordhuis
Copy link
Member

Not if in the docs you state that this works only if ...

I can tell you from almost 10 years of experience as a Node.js maintainer that it never works that way.

It's not by any means a reason not to implement a feature

A badly designed feature? For me that'd be plenty of reason.

The point still stands that the ask is poorly defined. You never answered what constitutes your definition of "debug mode."

Neither is it clear to me when it's relevant to know that. If it's to work around timing sensitive code, then make it less timing sensitive. What other reasons are there?

@benjamingr
Copy link
Member

@nicszerman I understand you want this to happen but listen to Ben here. It is important that we detect the right thing and we expose an API that is not misleading:

  • inspector.url only tells us if a debugger port is open. That is either node was launched with --inspect or for example a user started Node without it and fired a SIGUSR1
  • Binding to the port will only tell us if no one else bound to the port - that will only tell us if someone is listening to the debugger not if anyone has actually started sending messages or sent a Debugger.enable.
  • A user may send Debugger.enable or SIGUSR1 followed by it at any point for any reason.

What I'd like see core expose (names and functionality obviously subject to bikeshed):

  • inspector.isEnabled() - basically inspector.url() === undefined but without people relying on that so we can change/move inspector.url more easily and for a clearer method.
  • inspector.on('enabled' when inspector isEnabled changes to true - for example when a user fires SIGUSR1 or calls inspector.open.
  • inspector.on('attached' - not sure how to do this technically (do we get a notification when someone connects to the socket?) .
  • inspector.on('debugging' when someone fires a Debugger.enable or Debugger.disable

This will only expose the capabilities from core and let users decide what's best for their apps on their own rather than us exposing an incomplete API that hides capabilities.

@nodejs/inspector @bnoordhuis wdyt?

@bnoordhuis
Copy link
Member

That's certainly closer to what I had in mind.

There is a practical snag however. Right now our inspector glue code doesn't interpret protocol messages at all, it just passes them to and from the inspector backend (i.e., V8.)

We don't want to be in the business of parsing/interpreting them because that's very fragile. The protocol changes frequently and even the wire format is in flux. Chromium is switching from JSON to a binary format for efficiency reasons.

In order for your proposal to work, V8's C++ inspector API would need to grow a number of new methods and callbacks. That requires cooperation from the V8 team and someone willing to do the work.

Whether the effort involved is proportional to the payoff remains to be seen. I'm not volunteering at any rate. ^^

@benjamingr
Copy link
Member

@nodejs/v8 @hashseed is this something you are willing to expose? ^

@bnoordhuis as far as I know the binary stuff has stopped because it didn't actually improve performance but I am sure I am not updated.

@hashseed
Copy link
Member

hashseed commented Aug 19, 2019

I would certainly be possible for every inspector domain to expose an isEnabled command which returns true or false. However, I fail to see the use case here. It sounds to me that that approach would provide way too much information or granularity than what is asked here.

@benjamingr
Copy link
Member

@hashseed basically, I want to have a different behavior when the debugger is enabled (for example in order to emit less optimized but easier to debug code).

@bin-y
Copy link

bin-y commented Jul 5, 2020

My use case of this feature is that I want to use a different log level when debugger is present. Detecting debuggers by bind or argv works but not universal. Hope there will be an official way to do it.

@bnoordhuis
Copy link
Member

@bin-y That sounds reasonable.

A generic isDebugEnabled() check might be too expensive to wrap around every log statement but a way to detect that console.log() and friends are being redirected to the inspector should be feasible and is probably good enough for your use case?

Can you open a new issue and link back to this one?

@bin-y
Copy link

bin-y commented Jul 5, 2020

Hi @bnoordhuis

A generic isDebugEnabled() check might be too expensive to wrap around every log statement

I agree with your opinion and I was not meant to do that. I didn't notice the inspector.url way by the time I sent the commit. I'm now configuring log level only once on the initializing stage of my script by using inspector.url to check debuggers.

but a way to detect that console.log() and friends are being redirected to the inspector should be feasible and is probably good enough for your use case?

Can you open a new issue and link back to this one?

If I need to change log level dynamically in the future, I'll try your idea by checking console._stdout.constructor or open a new issue about this. Thanks.

@leonardoraele
Copy link

Any news on this topic? My use case is that I want mocha test timeout to be Infinity when I'm debugging it. (default is 2 seconds) For now, I'm using the inspector.url() === undefined solution.

@dandv
Copy link
Contributor

dandv commented Aug 17, 2021

@leonardoraele I had the same debug timeout request back in 2019.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Issues that look for answers.
Projects
None yet
Development

No branches or pull requests