2009-01-13 4 views
5

Ich erkläre typischerweise die folgende in jeder Klasse:log4net-Strategie für named Logger?

private static readonly log4net.ILog log = log4net.LogManager.GetLogger(
      System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 

und innerhalb jeder Klasse die statische Element verwenden auf verschiedenen Ebenen zu protokollieren (info, debug, etc.)

ich, dass irgendwo gesehen und haben Ich denke, dass das Setup flexibel genug ist, um nach Namespaces zu filtern und einzelne Typen zu protokollieren, wenn ich Probleme bei der Fehlerbehebung beheben möchte und was nicht.

Aber ich hatte selten diese "Ebene" der Feinprotokollierung zu verwenden. Also würde ich gerne sehen, was andere benutzen. Verwenden Sie das obige, da ich das Gefühl habe, dass viele genau das verwenden, oder erstellen Sie benannte Logger wie "debug", "trace", "error", "moduleA" usw. und teilen Sie den Logger unter verschiedenen Typen , Versammlungen?

Antwort

-1

In letzter Zeit, habe ich so etwas wie dieses:

public static class Logger 
{ 
    private static bool isLoaded = false;  

    public static ILog Log 
    { 
     get 
     { 
      System.Reflection.MethodBase method; 
      method = new System.Diagnostics.StackTrace().GetFrame(1).GetMethod(); 
      StringBuilder loggerName = new StringBuilder(); 
      loggerName.AppendFormat("{0}.{1}(", method.ReflectedType.FullName, method.Name); 

      ParameterInfo[] parameters = method.GetParameters(); 
      string[] parametersStr = new string[parameters.Length]; 

      if (parameters.Length > 0) 
      { 
       for (int i = 0; i < parameters.Length; i++) 
       { 
        parametersStr[i] = parameters[i].ToString(); 
       } 
       loggerName.Append(String.Join(", ", parametersStr)); 
      } 

      loggerName.Append(")"); 

      return GetLogger(loggerName.ToString()); 
     } 
    } 


    private static ILog GetLogger(string loggerName) 
    { 
     if (!isLoaded) 
     { 
      log4net.Config.XmlConfigurator.Configure(); 
     } 
     return LogManager.GetLogger(loggerName); 
    } 
} 

es mir ohne die Schaffung seiner Instanz in jeder Klasse verwenden log4net lässt ich es verwenden müssen, und ich immer noch Klassennamen und ein Verfahren erhalten, wo ich die Aktion angemeldet .

Verwendungsbeispiel:

Logger.Log.DebugFormat("Response [{0}]", xmlResponse); 
+0

Ausgezeichnet. Vielen Dank. – Chasler

+2

Haben Sie einen Profiler auf diesem laufen? Die Ausführungsgeschwindigkeit dieser Bestie ist riesig. Und selbst wenn Sie den DEBUG-Protokollierungsgrad in der Produktion ändern wollten, entstehen Ihnen die gleichen Kosten. Ich kann den Punkt etwas sehen, wenn Sie wirklich den Methodennamen im Logger brauchen, aber dann wieder, wenn z. Ausnahmen auftreten, würden Sie diesen Namen in der Ausnahme stacktrace sowieso bekommen ... –

+1

Ziemlich sicher, dass dies durch das neue CallerName-Attribut ersetzt wird - siehe http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices. callermembernameattribute% 28v = vs.110% 29.aspx – keithl8041

2

Die Kosten es Ihre originelle Art und Weise zu tun, ist eine Instanz der ILog Implementierung und die Zeit es braucht, zu laufen „System.Reflection.MethodBase.GetCurrentMethod() DeclaringType.“ An Anfang.

Ich erinnere mich daran, ein paar Jahre zurück zu schauen, und unsere Startkosten lagen in der Größenordnung von 1 Sekunde pro 10000 Klassen und weniger als ein Megabyte pro 10k-Klassen.

Bei so niedrigen Kosten habe ich angesichts der unglaublichen Flexibilität, die log4net bietet, nie zurückgeschaut.

Hinweis: Ich kann hier nicht auf der anderen Lösung nichts sagen, da ich neu bin .. aber diese Linie.

Methode = new System.Diagnostics.StackTrace() GetFrame (1) .GetMethod ();

Ist teuer, vor allem, wenn für jede Protokollmeldung aufgerufen.

0

Ein Werkzeug, das Sie mit der Protokollierung verwenden können, ist PostSharp (http://www.postsharp.org/). Es gibt eine kostenpflichtige und eine kostenlose (Express) Version. Ich habe es nur verwendet, um Methodengrenzen zu protokollieren, aber ich weiß, dass Sie es auch für die Fehlerbehandlung verwenden können. Zwischen den beiden würde das die meisten Ihrer Protokollierungsanforderungen erledigen, ohne Code in jeder Klasse zu schreiben.

11

Ich verwende grundsätzlich

public class MyClass 
{ 
    private static readonly ILog log = Log.Get<MyClass>(); 
} 

wo Log.Get eine Klasse, die diese intern im Grunde tut

return LogManager.GetLogger(typeof(T)); 

Die Startkosten als Reiniger imo noch kleiner ist als die Reflexion Weg als gut.

Update: nach meiner Erfahrung in späteren Jahren mit Abhängigkeitsinjektion, Komponententests und Fälschungen, kann ich nicht mehr sagen, dass ich den oben skizzierten Ansatz dulden.Das Problem mit dem Ansatz (sowohl meiner als auch dem des OP) ist, dass der Code explizites Wissen über hat, wie die Protokollinstanz erstellt wird.

Eine Seite, diese erhöhte Kopplung macht es schwieriger zu testen: Es gibt keine einfache Möglichkeit, die ILog Instanz mit einem gefälschten zu ersetzen. Auf einer anderen Seite führen Änderungen, die an meiner Klasse Log vorgenommen werden, zu Änderungen in allen Klassen, die es verwenden.

Ich gehe deshalb die Route der die ILog Instanz, in der Regel über Konstruktor Injektion Injektion und auslagern die wie einen Logger-my DI framework of choice zu konstruieren:

public class MyClass 
{ 
    readonly ILog _log; 

    public class MyClass(ILog log) 
    { 
     _log = log; 
    } 
} 

Dies ermöglicht eine ordnungsgemäße Entkopplung. Der Code muss nicht mehr wissen, wie Logger erstellt werden. Die meisten Frameworks zur Abhängigkeitsinjektion verfügen über Mittel, um den Typ, der injiziert wird, zu betrachten und ihn dann zum Erstellen der Protokollinstanz zu verwenden. Hier ist ein approach for log4net and Autofac.

+0

Welchen Vorteil hat dies mit 'LogManager.GetLogger (typeof (MyClass))' wenn man die 'ILog' Instanz bekommt? – MarioVW

+1

Kürzere, sauberere Code. Aber ich sollte diese Antwort überarbeiten, weil ich heute Dependency Injection verwende und das DI-Framework den Logger konstruieren lasse. –