2012-08-15 11 views
5

Invece di dover creare un logger personalizzato per TRACE, ad es. seguendo quali metodi sono stati chiamati e quali classi sono state istanziate, c'è un modo semplice per rendere tutti i metodi sotto un log di classe stessi? Questo è per un'applicazione node.js.registra ogni metodo?

class MyClass 

    constructor:() -> 
    console.log 'MyClass:constructor' 

    doThat:() -> 
    console.log 'MyClass:doThat' 

exports.MyClass = MyClass 

myClass = new MyClass() 
myClass.doThat() 

Se fosse per me, che ci si veda messaggi di log invece di 2 (avendo così di scrivere meno codice per tracciare quello che sta accadendo).

risposta

3

Recentemente ho avuto bisogno di implementare qualcosa di simile per rintracciare complicate cose riconducibili all'OO. Fondamentalmente, volevo rendere un metodo "tracciabile" senza inquinarlo troppo; quindi forse la soluzione potrebbe essere applicata anche qui.

In primo luogo, aggiungere una funzione che rende le altre funzioni tracciabile:

Function::trace = do -> 
    makeTracing = (ctorName, fnName, fn) -> 
    (args...) -> 
     console.log "#{ctorName}:#{fnName}" 
     fn.apply @, args 
    (arg) -> 
    for own name, fn of arg 
     @prototype[name] = makeTracing @name, name, fn 

Quindi, per utilizzarlo, è sufficiente aggiungere un @trace prima di ogni metodo che si desidera rintracciare:

class MyClass 
    @trace methodA: -> 
    @methodB 42 

    @trace methodB: -> 
    console.log "method b called with #{n}" 

Oppure aggiungi @ traccia solo una volta e quindi indentare tutti i metodi tracciabili un altro livello:

class MyClass 
    @trace 
    methodA: -> 
     @methodB 42 

    methodB: (n) -> 
     console.log "method b called with #{n}" 

Come potete vedere, trace è un po 'un abusare della sintassi di CoffeeScript. method: -> 'foo' all'interno di class MyClass viene interpretata una definizione di metodo. Ma @trace method: -> 'foo' viene interpretato chiamando la funzione trace di MyClass (che è un'istanza Function, a cui è stata aggiunta la funzione trace) passando un oggetto letterale con una chiave method. In JavaScript sarebbe qualcosa come this.trace({method: function() {return 'foo';}}).

La funzione trace prenderà solo quell'oggetto e itererà le sue chiavi (i nomi dei metodi) e valori (i metodi) e aggiungerà funzioni al prototipo MyClass che registra le loro chiamate e, a sua volta, chiama i metodi originali.

In ogni caso, l'uscita del (new MyClass).methodA() sarà:

MyClass:methodA 
MyClass:methodB 
method b called with 42 

Questa soluzione non funziona per i costruttori, però, in quanto non sono solo i metodi normali.

È possibile ottenere abbastanza fantasia con questo. È inoltre possibile registrare gli argomenti passati a ciascun metodo, il valore restituito e persino aggiungere il rientro per le chiamate annidate se lo si desidera (le tracce risultanti possono quindi essere molto utili se è necessario eseguire il debug di un problema complesso = D).


Aggiornamento: come un esempio più interessante, ecco una mini-versione del tipico esempio composite, figure geometriche e gruppi di figure: http://jsfiddle.net/2YuE7/ con una funzione di traccia più interessante. Tutte le cifre comprendono il metodo move.Se abbiamo questa figura composita e chiamiamo move su di esso:

f = new Composite [ 
    new Rectangle 5, 10, 3, 4 
    new Composite [ 
    new Circle 0, 0, 2 
    new Circle 0, 0, 4 
    new Circle 0, 0, 6 
    ] 
] 

f.move 2, 3 

L'output di analisi è:

(Composite[Rectangle[5,10,3,4],Composite[Circle[0,0,2],Circle[0,0,4],Circle[0,0,6]]]).move(2, 3) 
| (Rectangle[5,10,3,4]).move(2, 3) 
| -> Rectangle[7,13,3,4] 
| (Composite[Circle[0,0,2],Circle[0,0,4],Circle[0,0,6]]).move(2, 3) 
| | (Circle[0,0,2]).move(2, 3) 
| | -> Circle[2,3,2] 
| | (Circle[0,0,4]).move(2, 3) 
| | -> Circle[2,3,4] 
| | (Circle[0,0,6]).move(2, 3) 
| | -> Circle[2,3,6] 
| -> Composite[Circle[2,3,2],Circle[2,3,4],Circle[2,3,6]] 
-> Composite[Rectangle[7,13,3,4],Composite[Circle[2,3,2],Circle[2,3,4],Circle[2,3,6]]] 
+0

Questo è molto cool. La possibilità di registrare argomenti era anche qualcosa a cui stavo pensando. Grazie! –

+0

@FrankLoVecchio Cool. Ho aggiornato la risposta con un esempio che registra i parametri, restituisce i valori e fa rientrare i registri in base al livello di ricorsione = D – epidemian

+0

Questa sarà una domanda StackOverflow molto utile :) –

0

Se si vuole fare in modo qualcosa con pianura vecchio javascript, ho creato un servizio a cui è può passare un oggetto che restituirà un oggetto con la stessa API che registra ogni metodo. Vedere l'esempio completo con la polyfill applicata al http://jsfiddle.net/mcgraphix/pagkoLjb

L'idea di base è:

var api = { 
    notAMethod: "blah", 
    foo: function() { 
    console.log("in foo", arguments); 
    }, 

    bar: function(arg) { 
    this.foo(arg); 
    return this.notAMethod; 
    } 
}; 

//wrap the api with a logging version 
//to watch property changes and keep them in sync, you need the polyfill for Object.watch 
//  from https://gist.github.com/eligrey/384583 

var createLogger = function(api) { 
    var loggingApi = {}; 

      for (var prop in api) { 
       if (typeof api[prop] !== 'function') { 
        loggingApi[prop] = api[prop]; 
        loggingApi.watch(prop, function(prop, oldVal, newVal){ 
         api[prop] = newVal 
         return newVal; 
        }); 


       } else { 

        loggingApi[prop] = function() { 
         console.log(prop + "() called with args: ", arguments); 
         var returnVal = api[prop].apply(api, arguments); 
         console.log(prop + "() returned: " + returnVal); 
         return returnVal; 
        } 
       } 
      } 
     return loggingApi; 
}; 
api.foo('Shhhh... don\'t log me') //no logging 
createLogger(api).foo(); //with logging   
Problemi correlati