Call stack for callbacks in node.js

I'm used to thinking in Java, and I'm trying to get around node.js. My program should log information when something goes wrong, and I believe that I need to add a lot of templates in my node.js program to get what I got for free in Java.

My question comes down to:

  • Is there an easier / non-contour way to get stack-like information in a callback chain? and / or
  • Am I to blame for not being able to understand node.js correctly and trying to make asynchronous node.js look more like synchronous Java?

Java example

Here's a noddy Java program that tries (and fails) to connect to the Mongo database: import java.net.UnknownHostException;

import com.mongodb.Mongo; public class Test { public static void main(final String[] args) throws UnknownHostException { final Mongo mongo = a(); } private static Mongo a() throws UnknownHostException { return b(); } private static Mongo b() throws UnknownHostException { return c(); } private static Mongo c() throws UnknownHostException { return new Mongo("non-existent host"); } } 

... which gives this useful stack output:

 Exception in thread "main" java.net.UnknownHostException: non-existent host at java.net.Inet6AddressImpl.lookupAllHostAddr(Native Method) at java.net.InetAddress$1.lookupAllHostAddr(Unknown Source) at java.net.InetAddress.getAddressesFromNameService(Unknown Source) at java.net.InetAddress.getAllByName0(Unknown Source) at java.net.InetAddress.getAllByName(Unknown Source) at java.net.InetAddress.getAllByName(Unknown Source) at java.net.InetAddress.getByName(Unknown Source) at com.mongodb.ServerAddress.updateInetAddress(ServerAddress.java:204) at com.mongodb.ServerAddress.<init>(ServerAddress.java:73) at com.mongodb.ServerAddress.<init>(ServerAddress.java:46) at com.mongodb.Mongo.<init>(Mongo.java:138) at Test.c(Test.java:20) at Test.b(Test.java:16) at Test.a(Test.java:12) at Test.main(Test.java:8) 

(In particular, the last 4 lines show me โ€œwhat is happeningโ€ in my own code at the time the Mongo error occurred.)

Node.js Example

Here is my attempt to rewrite my program in node.js:

 a(function (err, mongo) { if (err) { console.log("Something went wrong in main"); console.log(err); } }); function a(callback) { b(function (err, mongo) { if (err) { console.log("Something went wrong in a()"); return callback(err); } return callback(null, mongo); }); } function b(callback) { c(function (err, mongo) { if (err) { console.log("Something went wrong in b()"); return callback(err); } return callback(null, mongo); }); } function c(callback) { var MongoClient = require('mongodb').MongoClient; return MongoClient.connect('mongodb://non-existent host/', function (err, mongo) { if (err) { console.log("Something went wrong in c()"); return callback(err); } return callback(null, mongo); }); } 

... which gives this result:

 Something went wrong in c() Something went wrong in b() Something went wrong in a() Something went wrong in main [Error: failed to connect to [non-existent host:27017]] 

But to get this result, I have to impose a lot of code templates throughout my program, which will hurt the police as my program gets bigger and I have a whole development team.

Is it possible to get this output as a stack in another way? Do you like this conclusion?

+6
source share
3 answers

Promises is exactly what you are looking for (return stack functions to asynchronous code)

 var Promise = require("bluebird"); var mongodb = require("mongodb"); // enable long stack traces, bluebird specific Promise.longStackTraces(); // promisify mongodb so that it returns promises, also bluebird specific Promise.promisifyAll(mongodb); // raise stack limit, feature of v8/node.js Error.stackTraceLimit = 100; function c() { var MongoClient = require("mongodb").MongoClient; return MongoClient.connectAsync('mongodb://non-existent host/') } function b() { return c() } function a() { return b() } a().then(function(connection) { }); 

gives:

 Possibly unhandled Error: failed to connect to [non-existent host:27017] at null.<anonymous> (/home/petka/bluebird/node_modules/mongodb/lib/mongodb/connection/server.js:546:74) at EventEmitter.emit (events.js:106:17) at null.<anonymous> (/home/petka/bluebird/node_modules/mongodb/lib/mongodb/connection/connection_pool.js:150:15) at EventEmitter.emit (events.js:98:17) at Socket.<anonymous> (/home/petka/bluebird/node_modules/mongodb/lib/mongodb/connection/connection.js:533:10) at Socket.EventEmitter.emit (events.js:95:17) at net.js:830:16 From previous event: at Function.connectAsync (eval at makeNodePromisifiedEval (/home/petka/bluebird/js/main/promisify.js:199:12), <anonymous>:7:21) at c (/home/petka/bluebird/throwaway.js:10:28) at b (/home/petka/bluebird/throwaway.js:14:16) at a (/home/petka/bluebird/throwaway.js:18:16) at Object.<anonymous> (/home/petka/bluebird/throwaway.js:21:5) at Module._compile (module.js:456:26) at Object.Module._extensions..js (module.js:474:10) at Module.load (module.js:356:32) at Function.Module._load (module.js:312:12) at Function.Module.runMain (module.js:497:10) at startup (node.js:119:16) at node.js:902:3 

You can use catch (called so because it works like a real catch statement) in one place:

  a().catch(function(e) { //handle e }); 

In addition, special bluebird functions have been added to catch:

Fixed catches are also supported as this is just a method:

  a().catch(SyntaxError, function(e) { }); 

A predicate can be an error constructor or a predicate function

  // define a predicate for IO errors function IOError(e) { return "code" in Object(e); } 
+2
source

How to use stack trace from error:

 function trace(err) { console.log(err); var stack = new Error().stack; console.log(stack); } a(function (err, mongo) { if (err) trace(err) }); function a(callback) { b(function (err, mongo) { if (err) return callback(err); else return callback(null, mongo); }); } function b(callback) { c(function (err, mongo) { if (err) return callback(err); else return callback(null, mongo); }); } function c(callback) { var MongoClient = require('mongodb').MongoClient; return MongoClient.connect('mongodb://nohost/', function (err, mongo) { if (err) return callback(err); else return callback(null, mongo); }); } 

Output

 [Error: failed to connect to [non-existent host:27017]] Error at trace (/myfolder/a.js:4:14) at /myfolder/a.js:11:2 at /myfolder/a.js:17:10 at /myfolder/a.js:26:10 at /myfolder/a.js:36:10 at /myfolder/node_modules/mongodb/lib/mongodb/mongo_client.js:406:11 at process._tickCallback (node.js:339:11) 

Now it is not as detailed as the one you got in Java, it does not give function names, but it helps to identify the execution chain.

0
source

longjohn seems to be very popular for several days now to get long stack traces in node.js

http://blog.nodejitsu.com/npmawesome-full-stack-traces-with-longjohn/

http://www.mattinsler.com/post/26396305882/announcing-longjohn-long-stack-traces-for-node-js

Here is a list of other such modules that may be useful in determining what you need.

https://nodejsmodules.org/tags/stack

Code example:

 var longjohn = require('longjohn') var stackTrace = require('stack-trace'); longjohn.empty_frame = 'ASYNC CALLBACKS :'; a(); function a() { b(); }; function b() { c(); } function c() { setTimeout(function() { throw new Error("My Custom Error"); }, 1000); } process.on('uncaughtException', function(err) { //in JSON format with the help of stack-trace module; console.error(stackTrace.parse(err)); //in plain text format console.error(err.stack.trim()); process.exit(1); }); 

Text output with longjohn:

 Error: My Custom Error at [object Object].<anonymous> (/Users/nav/Documents/workspace/stack_trace/hello-world-server.njs:19:9) at listOnTimeout (timers.js:110:15) ASYNC CALLBACKS : at c (/Users/nav/Documents/workspace/stack_trace/hello-world-server.njs:17:2) at b (/Users/nav/Documents/workspace/stack_trace/hello-world-server.njs:12:2) at a (/Users/nav/Documents/workspace/stack_trace/hello-world-server.njs:8:2) at Object.<anonymous> (/Users/nav/Documents/workspace/stack_trace/hello-world-server.njs:4:1) at Module._compile (module.js:456:26) at Module._extensions..js (module.js:474:10) at Module.load (module.js:356:32) at Module._load (module.js:312:12) 

Text output without longjohn:

 Error: My Custom Error at null._onTimeout (/Users/nav/Documents/workspace/stack_trace/hello-world-server.njs:19:9) at Timer.listOnTimeout [as ontimeout] (timers.js:110:15) 
0
source

Source: https://habr.com/ru/post/970433/


All Articles