2014-06-06 12 views
6

Ich bin es gewohnt, in Java zu denken, und ich versuche, mich um node.js. Mein Programm muss Informationen protokollieren, wenn etwas schief geht, und ich muss feststellen, dass ich eine Menge Code in mein node.js-Programm eingeben muss, um zu bekommen, was ich kostenlos in Java bekommen würde."Call-Stack" für Rückrufe in node.js

Meine Frage läuft darauf hinaus:

  • ist es eine einfachere/Nicht-Text Weise stapelt artige Informationen in einer Kette von Rückrufen zu bekommen? und/oder
  • bin ich schuldig, node.js nicht richtig verstanden zu haben und zu versuchen, asynchrone node.js zu zwingen, synchronen Java ähnlicher zu sein?

Java Beispiel

Hier ist ein noddy Java-Programm, das versucht (und nicht) zu einer Mongo Datenbank zu verbinden: 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"); 
    } 

} 

..., die diese Informationen hilfreich Stapel-Ausgang gibt:

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) 

(Insbesondere die letzten 4 Zeilen zeigen Sie mir zu der Zeit in meinem eigenen Code "was los war" der Mongo Fehler aufgetreten .)

Node.js Beispiel

Hier ist mein Versuch, mein Programm in node.js neu schreiben:

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); 
    }); 
} 

..., die diesen Ausgang gibt:

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]] 

Aber diese Ausgabe zu erhalten, habe ich in meinem Programm in vielen Standardcode setzen, die ein Schmerz Polizei als mein Programm sein wird wird größer und ich habe ein ganzes Entwicklungsteam.

Kann ich diese stack-artige Ausgabe auf andere Weise erhalten? Ist es unknotenartig, diese Art von Ausgabe zu erwarten?

+0

Versprechen sein könnte, was Sie suchen; Sie vermitteln den typischen Erfolg und Misserfolg von (asynchronen) Prozessen auf konsistente Weise. –

Antwort

2

Promises sind genau das, was Sie suchen (bringen Sie die Stapelfunktionen Asynchron-Code zurück)

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) { 

}); 

Gibt:

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 

Sie können so catch (benannt verwenden, weil es wie ein Werk echte catch-Anweisung) an einem Ort:

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

Auch Bluebird spezifische Funktionen hinzugefügt zu fangen:

Prädizierter Fänge werden ebenfalls unterstützt, da es nur eine Methode:

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

}); 

Prädikats kann ein Fehler Konstruktor oder eine Prädikatfunktion sein

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

Ich denke, diese "aus dem vorherigen Ereignis" -Funktion Ihrer Bibliothek ist, was Sie hier werben sollten. OP beschwert sich darüber, dass er "log" ("irgendwas ist schief gegangen bei ...") überall aufschreiben muss, oder? – Bergi

+0

@Bergi einverstanden ist, werde ich die Log-Version entfernen – Esailija

+0

Sie auch markieren wollen könnten, dass dies nicht eine inhärente Eigenschaft von Versprechungen, sondern eine Implementierung Merkmal einiger Bibliotheken. – Bergi

0

Wie wäre Stack-Trace aus dem Fehler mit:

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); 
    }); 
} 

Ausgabe

[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) 

Jetzt ist es nicht so ausführlich wie das in Java, es gibt keine Funktionsnamen, aber es hilft bei der Identifizierung der Ausführungskette.

+0

... es sei denn, die Methoden, die Sie in Ihrem Stack-Trace wollen ('a', 'b', 'c') verwenden Funktionen höherer Ordnung, die Rückrufe zu erzeugen. In diesem Fall würden Sie nur die Zeilennummern der Generatorfunktionen erhalten. – Bergi

0

Longjohn scheint für immer lange 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

Hier wird ein Tag jetzt sehr beliebt zu sein ist eine Liste anderer solcher Module, die bei der Identifizierung hilfreich sein könnten was Sie brauchen

https://nodejsmodules.org/tags/stack

Beispielcode:

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); 

}); 

Ausgabe im Textformat mit Langhans:

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) 

Ausgabe im Textformat ohne Langhans:

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)