2009-08-28 15 views
9

Fondamentalmente voglio scrivere un logger/tracciante cliente che registra anche il nome della classe e del metodo che chiama il logger/tracciante. Questo dovrebbe essere veloce in modo che non influenzi le prestazioni dell'applicazione, fortemente digitato e pulito. Qualcuno ha buone idee?Qual è il modo più performante per registrare il nome di classe e metodo?

Ecco i pochi che ho avuto, ma mi preoccupo per le prestazioni a causa di riflessione: (? Troppo in alto)

  • StackTrace/StackFrame

  • MethodInfo.GetCurrentMethod() (ancora troppo lento? e non molto pulita) metodo

  • passaggio come delegato (C# può farlo in modo implicito e non ho accesso al MethodInfo, ma non molto pulita)

Apprezzo i commenti di chiunque.

UPDATE:

Mi è piaciuta la pulizia generale di StackFrame così ho fatto una domanda più specifica here per quanto riguarda le prestazioni di StackFrame e ho ottenuto alcuni buoni di risposta compresi i test di performance. Si scopre che MethodInfo.GetCurrentMethod() è il più veloce (richiede circa 1 microsecondo sul mio computer) e new StackFrame(1) può essere richiesto su richiesta (richiede circa 15-20 microsecondi sul mio computer). Ho buttato il metodo come opzione delegato poiché è troppo disordinato quando il metodo ha diversi parametri.

CONCLUSIONE:

Ho guardato tutte le opzioni e la migliore è quello di scrivere un plug-in personalizzato per PostSharp che inietta il nome del metodo come stringa in MSIL durante la compilazione quando si applica un attributo personalizzato come [Trace] ad esso. È l'opzione più veloce e più gestibile a mio avviso. Ciò consente anche molte più cose come passare i nomi e gli argomenti dei parametri senza alcun tipo di riflessione e le eccezioni di cattura e registrazione automaticamente. Questo my related question per ulteriori informazioni.

+0

posso chiedere, perché non si desidera utilizzare log4net? – nWorx

+0

Anche a me non piace fare affidamento su altri componenti. E anche nel caso di log4net, è troppo complesso. –

+2

Hermann, questo è generalmente indicato nel nostro settore come "sindrome non inventata qui" ed è meglio evitarlo. Ecco un link di Wikipedia con ulteriori informazioni su questa afflizione: http://en.wikipedia.org/wiki/Not_Invented_Here –

risposta

3

In poche parole, il modo più veloce è quello di farlo in modo statico al momento della compilazione:

public void DoSomething() 
{ 
    TraceCall("DoSomething"); 
} 

public void TraceCall(string methodName) 
{ 
    if (!tracingEnabled) { return; } 
    // Log the call 
} 

La domanda allora è essenzialmente la stessa tua domanda precedente; qual è il modo migliore per farlo in una fastion manutenibile e accurata? Le opzioni di runtime di cui abbiamo discusso in precedenza hanno un impatto sulle prestazioni relativamente grave, ma il compromesso è che possono essere facilmente implementate.

Come è stato menzionato nel thread precedente, questo sta iniziando a orientarsi verso la programmazione orientata agli aspetti; PostSharp è una di queste librerie che può aiutare a trovare l'equilibrio delle prestazioni compilate staticamente con una semplice manutenzione.

+0

Hai ragione. Spero che non impieghi troppo sforzo per implementarlo con PostSharp. Immagino che dipenda da ciascun individuo i bisogni, ma non definirei 20 microsecondi un grave colpo di prestazioni. –

+0

@Hermann: a meno che tu non stia scrivendo qualcosa che deve gestire il throughput di Google, 20ms è del tutto trascurabile. I test che abbiamo fatto nell'altra domanda mostravano che se avevi bisogno di avviare le chiamate di log per 100.000 metodi, aggiungerebbe - al massimo - 1,5 secondi. Indipendentemente dal fatto che alcuni metodi siano sostanzialmente più veloci di altri, tutti i metodi sono marginali alla fine della giornata. – STW

2

Quando si è già all'interno del metodo (o se si sta intercettando il metodo), non penso che si possa fare molto meglio di MethodInfo.GetCurrentMethod - che non è troppo terribilmente veloce - se si vuole rimanere di tipo -sicuro.

Dato che si desidera eseguire questa operazione per la registrazione, si è considerato di farlo in un'operazione asincrona in modo da non rallentare il thread principale?

A seconda del carico già presente nell'applicazione, potrebbe essere utile o meno.

+0

Sì, stavo pensando anche a questo. Ma cosa succede quando l'applicazione è occupata? Non rimanderebbe la registrazione e non si perderebbe quando l'applicazione si blocca? –

+0

Dipende da come si implementa l'operazione asincrona. Se lo lanci semplicemente sul ThreadPool, allora sì, sei corretto e l'ordine non è garantito. Tuttavia, potresti anche scriverlo su MSMQ, che può fornirti registrazioni ininterrotte e durature. –

+1

L'opzione async allevierebbe solo la scrittura effettiva nel log (che potrebbe comunque essere utile). La chiamata effettiva "GetCurrentMethod" imporrebbe comunque la penalizzazione delle prestazioni sul thread principale. – STW

0

Il modo migliore per farlo è in fase di compilazione: C++ utilizzava tradizionalmente i simboli del preprocessore ____FILE____ e ____LINE____ nelle macro per fare ciò. Sfortunatamente il compilatore C# non offre macro o un equivalente a ____FILE____ e ____LINE____ al momento.

Ciò significa in effetti che l'unica opzione è registrare queste informazioni in fase di runtime, il che significa che è noioso aggiungere la traccia manuale a ciascun metodo che si desidera registrare o utilizzare l'immagine riflessa come descritto.

0

Penso che Log4PostSharp farebbe il lavoro molto bene.

+0

Non voglio usare un altro logger, soprattutto non qualcosa basato su log4net, ma io _really) mi piace l'idea di iniettare il codice MSIL. Dovrò cercare se posso usarlo in qualche modo. –

+0

Lettura della risposta di Stu - ci vorrebbero ca. un'ora per sviluppare l'equivalente di __FILE__ e __LINE__ usando PostSharp (o __TYPE__ e __METHOD__). Bene, 1 ora per me. –

+0

Daremo un'occhiata a PostSharp. Grazie Gael! –

0

Se si è interessati alla velocità, è necessario creare il messaggio di registro effettivo utilizzando Event Tracing for Windows. ETW è una libreria di logging ad alta velocità implementata come driver accessibile sia dalla modalità kernel che dalla modalità utente. La traccia può essere attivata e disattivata dinamicamente. La registrazione aggiunge pochissime spese generali all'applicazione. Ho usato ETW per implementare la tracciatura in applicazioni server ad alto throughput. Controlla NTrace.

4

Il modo più veloce è quello di farlo al momento della compilazione, è vero, ma il modo più conveniente di farlo in .NET è attraverso utilizzando i CallerMemberName, CallerFilePath e altri servizi compilatore attributi incroduced in .NET 4.5:

public void TraceMethodCall([CallerMemberName]string methodName) 
{ 
} 
Problemi correlati