2010-11-29 4 views
11

Ich habe einige verschiedene Web-Dienste von meiner Website ausgesetzt. Hier ist ein Ziele, die ich erreichen möchte:log4net: Wie man die zu speichernden Daten anpasst

  1. Speichern Sie alle Daten in DB in einer Tabelle;
  2. Jeder Datensatz sollte ein Textfeld mit dem Namen "service/component" haben;
  3. Es ist notwendig, alle Einkommensparameter zu speichern, wenn irgendeine Methode aufgerufen wird;
  4. Es ist notwendig, alle Ergebnisparameter UND Fehlermeldungen zu speichern, wenn eine Ausnahme aufgetreten ist.

Meine ursprüngliche Absicht war es, log4net zu verwenden. Aber von diesen begehbaren (http://sadi02.wordpress.com/2008/09/15/how-to-store-log-in-database-using-log4net/, http://logging.apache.org/log4net/release/config-examples.html) sehe ich keinen einfachen Weg um benutzerdefinierte Daten in die Protokolltabelle hinzuzufügen.

Ist es möglich, log4net für solche Zwecke zu verwenden? Wie kann ich das Protokoll der Protokolltabelle ändern, um benutzerdefinierte Daten zu speichern? Soll ich den Quellcode der log4net-Bibliothek ändern? Wahrscheinlich wäre es besser, eine benutzerdefinierte Funktionalität zum Speichern solcher Daten zu schreiben?

Danke.

Antwort

2

Keine der vorgeschlagenen Antworten funktioniert für mich. Das Problem ist, dass ich mehrere benutzerdefinierte Felder haben muss. Für mich erscheint es zu kompliziert, verschiedene Instanzen von Loggern zu erstellen oder Spaltenwerte jedes Mal über die 'Eigenschaften' einzurichten.

Ich werde gehen (eigentlich bereits implementiert) benutzerdefinierte Logger, die Daten in DB.

1

In der log4net-Dokumentation erfahren Sie, wie Sie Ihre benutzerdefinierten Daten in einer Datei protokollieren können. Wenn dies der Fall ist, sollten Sie in der Lage sein, dieselben Daten in der Datenbank zu protokollieren. Fügen Sie einfach weitere Spalten in Ihrer Tabelle, mehr Spalten im Knoten <command text> des AdoNetAppender und weitere <parameter> Knoten hinzu.

Ich denke, dass Sie etwas Arbeit haben werden, um Ihre eingehenden und ausgehenden Parameter zu protokollieren. Brauchen Sie sie in separaten Spalten angemeldet (wahrscheinlich nicht einfach sauber zu tun)? Ist es in Ordnung, wenn sie zusammen mit der Nachricht protokolliert werden?

Zum Beispiel, wenn Sie die folgende Methode, die Sie setzen in der Anmeldung werden soll:

public void DoSomething(int x, int y) 
{ 
    log.Info("Inside DoSomething"); 
} 

Was wollen Sie Ihre Ausgabe aussehen? Möchten Sie, dass die "Standard" log4net-Informationen in separaten Spalten (Zeitstempel, Loggername, Level, Nachricht) erscheinen? Was ist mit den Parametern? Sollte x und y erscheinen in separaten Spalten (wahrscheinlich nicht sehr einfach zu tun, es sei denn jede Methode die gleiche Anzahl von Parametern) oder wäre es in Ordnung, wenn die Parameter wie folgt protokolliert wurden:

public void DoSomething(int x, int y) 
{ 
    ILog log = LogManager.GetLogger("abc"); 
    log.InfoFormat("Parameters: x = {0}, y = {1}", x, y); 
    log.Info("Inside DoSomething"); 
} 

Die Log-Anweisungen werden Meldungen erzeugen das wird ungefähr so ​​aussehen:

11/29/2010 16:36:00 | abc | INFO | Parameters: x = 10, y = 20 
11/29/2010 16:36:00 | abc | INFO | Inside DoSomething 

Ich habe die | verwendet Zeichen, um zu zeigen, wie die Felder mit einem Musterlayout aussehen würden, das den Zeitstempel, den Protokollierernamen, die Protokollebene und die Nachricht anzeigt. Wenn Sie eine AOP-Lösung wie PostSharp betrachten, kann Ihnen das helfen, weil Sie relativ einfach Enter/Exit-Logging hinzufügen können, ohne Ihren Anwendungsquellcode mit Logging-Anweisungen zu "verschmutzen". Innerhalb des Logging-Aspekts hätten Sie Zugriff auf die Parameter der Methode.

Ich könnte etwas fehlen, aber ich vermute, dass wenn Sie Ihre Methode Parameter als einzelne Spalten in der Datenbank pflegen wollen, dann werden Sie es schwer zu tun finden. Wenn Sie damit zufrieden sind, alle Parameter (manuell) für jede Methode als eine einzelne Spalte (im Wesentlichen eine formatierte Zeichenfolge) zu kombinieren, wird das einfacher.Ein Preis, den Sie zahlen müssen, ist, dass Sie alle Parameter explizit protokollieren müssen (es sei denn, Sie gehen auf die AOP-Route).

Wenn Sie log4net verwenden, sollten Sie auch NLog verwenden. Es wird Ihnen nicht unbedingt bei den oben beschriebenen Problemen helfen, aber ich denke, dass es ein würdiger Konkurrent für log4net ist.

[EDIT]

Um die „Komponentennamen“ von log4net protokolliert zu erhalten, sollten Sie Ihre Loggern für Ihre Komponenten nennen. Wenn Sie LogManager.GetLogger (Name) aufrufen, können Sie einen beliebigen Namen (oder Typ) übergeben. Ein übliches Muster ist in jeder Klasse Code wie diese hat:

public class MyClass 
{ 
    private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 

    public void DoSomething(int x) 
    { 
    logger.InfoFormat("Inside DoSomething. x = {0}", x); 
    } 
} 

Dies wird einen Logger mit den vollständig qualifizierten Klassennamen (Namespace + Klassenname) genannt bekommen. Wenn Sie dies in jeder Klasse tun, können Sie die Protokollierung (Ebene, Appender usw.) pro Klasse steuern. So können Sie die Protokollierung für Class1 problemlos in Info umwandeln und für Class2 Off usw. protokollieren. Dies gibt Ihnen das Potenzial für die größtmögliche Kontrolle Ihrer Protokollierung.

Nun sind Sie in Ihrer Konfigurationsdatei nicht verpflichtet, jeden Logger (d. H. Jeden vollständig qualifizierten Klassennamen) explizit aufzuführen. Sie könnten einfach den Root-Logger konfigurieren, und dann würden diese Einstellungen auf jeden Logger angewendet werden. Sie können die Protokollierung nach Namespace steuern. Zum Beispiel, wenn Sie für CompanyX arbeiten und Sie explizite Namespace Regeln haben, Ihre Namespaces aussehen könnte:

CompanyX 
CompanyX.DataAccess 
CompanyX.DataAccess.Read 
CompanyX.DataAccess.Write 
CompanyX.GUI 
CompanyX.Forms 
CompanyX.Controls 

Innerhalb jeder Namespace, können Sie verschiedene Klasse (wie verschiedene Datenleser, Hilfsklassen, Daten Autoren, etc). Wenn Ihre Klassen wie folgt organisiert sind und Ihre Klassen Logger wie oben erhalten, können Sie die Protokollierung für alle Klassen in CompanyX oder alle Logger in CompanyX.DataAccess oder CompanyX.DataAccess.Read usw. problemlos konfigurieren. Sie können sogar die gesamte Abmeldung deaktivieren , aber schalte es für diese problematische Klasse ein, die dir Probleme bereitet.

Sie können Ihre Logger auch mit beliebigen Namen versehen (d. H. Sie müssen den Klassennamen nicht verwenden, wenn Sie nicht möchten). Sie könnten Funktionsbereiche in Ihren App (s) definieren und Logger basierend darauf erhalten:

Und so weiter. Ich sehe nicht, dass dies einen großen Vorteil gegenüber der Verwendung des vollständig qualifizierten Klassennamens bietet. Wenn Ihre Namespaces gut organisiert sind, haben Sie die Möglichkeit, Ihre Protokollierung zu konfigurieren, um maximale Flexibilität bei minimalem Aufwand zu erreichen. Ein anderes Wort auf NLog ... NLog ist sehr ähnlich zu log4net. Es hat die nützliche Funktion in der Lage, automatisch einen Logger für die aktuelle Klasse zurück:

Logger logger = NLog.LogManager.GetCurrentClassLogger(); 

Das zumindest eine gewisse Eingabe auf Ihrer Seite speichert. NLog hat gerade ein neues Release herausgebracht (derzeit in der Betaversion).

Ich weiß nicht, ob das alles geholfen hat, aber ich hoffe es hat es getan!

Viel Glück!

+0

Es ist in Ordnung, alle Parameter in 1 Feld zu haben, aber (wie ich im Kommentar zu einer anderen Antwort erwähnt habe) möchte ich Komponentenname in einer separaten Spalte haben (ohne den globalen Kontext für jeden Anruf zu ändern). Außerdem möchte ich 3 zusätzliche Spalten haben: income_data, outcome_data, error_message. Wahrscheinlich könnte ich einige verschiedene Logger-Instanzen konfigurieren (1 pro Komponente)? Und in diesem Fall muss ich nicht jedes Mal die globalen Einstellungen ändern. Entschuldigung, ich bin neu bei log4net. – Budda

+0

Ja, wahrscheinlich möchten Sie mindestens einen Logger pro Komponente haben. Ich habe einige Beispiele in meiner Antwort hinzugefügt. – wageoghe

14

Entsprechend dieser discussion ist der Prozess ziemlich einfach.

Der erste Schritt ist es, den Befehl Text in der appender Deklaration in Ihre Konfigurationsdatei zu aktualisieren:

<commandText value="INSERT INTO Log4Net ([Date],[Thread],[Level],[Logger],[Message],[Exception],[MyColumn]) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception,@MyColumn)"/>   

Der nächste Schritt ist und eine neue Parameter Definition für die benutzerdefinierte Spalte hinzufügen:

<parameter> 
    <parameterName value="@MyColumn "/> 
    <dbType value="String" /> 
    <size value="255" /> 
    <layout type="log4net.Layout.PatternLayout"> 
     <conversionPattern value="%property{MyColumn}" /> 
    </layout> 
</parameter> 

Schließlich können Sie den Wert durch die GlobalContext Eigenschaften von log4net Zugang:

log4net.GlobalContext.Properties["MyColumn"] = "MyValue"; 
log.Debug("My message"); 

Sie können dies für so viele Felder tun, wie Sie benötigen.

+0

Bin ich richtig verstanden, dass ich vor jedem Schreiben den richtigen Wert von "MyColumn" einrichten sollte? Zum Beispiel muss meine Website 3 verschiedene "Komponenten" unterstützen. Ich möchte Komponentenname in einer separaten Spalte haben, in diesem Fall sollte ich "MyComponent" Eigenschaft des globalen Kontext vor jedem Aufruf einrichten? Ich glaube nicht, dass es das ist, was ich brauche (auch ich muss mit Nebenläufigkeit umgehen) ... – Budda

+0

Wahrscheinlich könnte ich einige verschiedene Logger-Instanzen konfigurieren (1 pro Komponente)? Habe ich Recht mit dieser Annahme? Und in diesem Fall muss ich nicht jedes Mal die globalen Einstellungen ändern. Entschuldigung, ich bin neu bei log4net. – Budda

+0

@Budda Ja, Sie müssten die Werte für jede benötigte "MyColumn" -Instanz nach Bedarf wiederholen. Für die Komponenten müssten Sie für jede Instanz eine einrichten, aber denken Sie daran, dass alle Appender dieselben Protokolldaten verwenden, so dass Sie leicht einen DB-Appender-Prozess MyColumn1 und ggf. den zweiten Appender-Prozess MyColumn2 haben könnten. –

Verwandte Themen