2012-08-15 12 views
5

En lugar de tener que crear un registrador personalizado para TRACE, p. Después de qué métodos se llamaron y qué clases se crearon, ¿existe una manera fácil de hacer todos los métodos bajo un registro de clase? Esto es para una aplicación node.js.registrar todos los métodos?

class MyClass 

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

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

exports.MyClass = MyClass 

myClass = new MyClass() 
myClass.doThat() 

Si fuera por mí, te vería mensajes de registro en lugar de 2 (por lo tanto tener que escribir menos código para rastrear lo que está pasando).

Respuesta

3

Recientemente tuve que implementar algo así para rastrear algunas cosas recursivas OO complicadas. Básicamente, quería hacer un método "rastreable" sin contaminarlo demasiado; así que tal vez la solución podría aplicarse aquí también.

En primer lugar, añadir una función que hace que otras funciones trazable:

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 

Entonces, para usarlo, basta con añadir una @trace antes de cada método que desea rastrear:

class MyClass 
    @trace methodA: -> 
    @methodB 42 

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

O añada @ trace solo una vez y luego sangría todos los métodos trazables un nivel más:

class MyClass 
    @trace 
    methodA: -> 
     @methodB 42 

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

Como puede ver trace está abusando de la sintaxis de CoffeeScript. method: -> 'foo' dentro de class MyClass se interpreta una definición de método. Pero @trace method: -> 'foo' se interpreta llamando a la función trace de MyClass (que es una instancia Function, a la que hemos agregado la función trace) pasándole un objeto literal con una clave method. En JavaScript sería algo así como this.trace({method: function() {return 'foo';}}).

La función trace simplemente tomará ese objeto e iterará sus claves (los nombres del método) y los valores (los métodos) y agregará funciones al prototipo MyClass que registra sus llamadas y llama a los métodos originales.

De todos modos, la salida de (new MyClass).methodA() será:

MyClass:methodA 
MyClass:methodB 
method b called with 42 

Esta solución no funciona para los constructores, sin embargo, ya que no son sólo los métodos normales.

Puede hacerse bastante elegante con esto. También puede registrar los argumentos pasados ​​a cada método, el valor de retorno e incluso agregar sangrías para llamadas anidadas si así lo desea (los rastros resultantes pueden ser muy útiles si necesita depurar un problema complejo = D).


Actualización: como un ejemplo más interesante, he aquí una mini-versión del ejemplo típico patrón compuesto, figuras y grupos de figuras geométricas: http://jsfiddle.net/2YuE7/ con una función de seguimiento más interesante. Todas las figuras entienden el método move.Si tenemos esta figura compuesta y llamamos move en él:

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 

El resultado de seguimiento es:

(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

Esto es muy fresco. La capacidad de registrar argumentos también era algo en lo que estaba pensando. ¡Gracias! –

+0

@FrankLoVecchio Cool. Actualicé la respuesta con un ejemplo que registra parámetros, devuelve valores y sangra los registros dependiendo del nivel de recursión = D – epidemian

+0

Esta va a ser una pregunta de StackOverflow muy útil :) –

0

Si desea hacerlo algo con edad Javascript llanura, he creado un servicio al que se puede pasar un objeto que devolverá un objeto con la misma API que registra cada método. Vea el ejemplo completo con el polyfill aplicada en http://jsfiddle.net/mcgraphix/pagkoLjb

La idea básica es:

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   
Cuestiones relacionadas