2010-10-14 20 views
5

La mia app (locale, windows/mono) registra eventi importanti su un file di testo. In caso di arresto improvviso/guasto/uscita forzata, nessun dato dovrebbe rimanere non scritto (per quanto è possibile). Così attualmente io uso un semplice approccio append-to-text-file:Qual è l'approccio migliore per la registrazione?

Public Shared Sub LogAppEvent(ByVal EventData As String) 
    Dim Config As ConfigHandler = ConfigHandler.GetSingleton() 
    Dim AppLog As New IO.StreamWriter(Config.GetUserFilesRootDir() & ConfigOptions.AppLogName, True) 
    AppLog.WriteLine(String.Format("[{0}] {1}", Date.Now.ToString(), EventData)) 
    AppLog.Close() 
End Sub 

Questo è altamente sub-ottimale, ma registrare gli eventi sono piuttosto rari. Consiglieresti di passare alla classe di registrazione System.Diagnostics?

O forse suggeriresti un'altra soluzione?

risposta

14

Se un approccio di base come questo è funzionalmente sufficiente per le tue esigenze, puoi seguirlo. Tuttavia, è possibile porsi alcune domande per accertarsi che:

  • È possibile che gli eventi vengano registrati contemporaneamente da più thread? Questa funzione non è threadsafe

  • È necessaria la notifica di errore?

  • Esiste il rischio che i file di registro crescano senza limiti senza potatura automatizzata?

  • Vorresti trarre vantaggio da una registrazione più estesa in modo da avere maggiori informazioni sugli eventi che portano a un errore?

  • Vuoi beneficiare di maggiori dettagli sugli errori (analisi dello stack, particolari eccezioni, ecc)

  • Il vostro programma eseguito su più computer? In tal caso, come ti arrivano i log?

  • Esiste qualche utilità/valore in strumenti che consentano di analizzare i file di registro (singolarmente o di trovare modelli come errori comuni in molti file di registro)?

Se si decide di avere altri requisiti, ci sono una serie di quadri di registrazione gratuiti come NLog or log4net che possono aiutare a registrare i log più dettagliati, e ci sono diversi prodotti commerciali come GIBRALTAR e SmartInspect disponibili che possono aiutare con gestione e analisi dei log.

+1

+1 per il punto di sicurezza del thread, sebbene solo il thread principale trasmetta eventi di registro. Grazie per la tua risposta completa. –

2

Nlog e log4Net sono scelte popolari per l'accesso ai progetti .net.

+0

Entrambi sono suggerimenti eccellenti. Adoro le loro configurazioni. –

+0

regole di log4Net !!! – user279521

1

Sì, è possibile considerare System.Diagnostics. Finché non stai scrivendo un gran numero di eventi, il vantaggio del registro eventi di Windows è che gli amministratori hanno un posto dove cercare tutti gli eventi da tutte le applicazioni.

Ecco po 'di codice VB.NET che può aiutare se dovessi decidere di seguire questa strada:

Imports System.Diagnostics 

Public Function WriteToEventLog(ByVal Entry As String, _ 
    Optional ByVal AppName As String = "VB.NET Application", _ 
    Optional ByVal EventType As _ 
    EventLogEntryType = EventLogEntryType.Information, _ 
    Optional ByVal LogName As String = "Application") As Boolean 

'************************************************************* 
'PURPOSE: Write Entry to Event Log using VB.NET 
'PARAMETERS: Entry - Value to Write 
'   AppName - Name of Client Application. Needed 
'    because before writing to event log, you must 
'    have a named EventLog source. 
'   EventType - Entry Type, from EventLogEntryType 
'    Structure e.g., EventLogEntryType.Warning, 
'    EventLogEntryType.Error 
'   LogName: Name of Log (System, Application; 
'    Security is read-only) If you 
'    specify a non-existent log, the log will be 
'    created 

'RETURNS: True if successful, false if not 

'EXAMPLES: 
'1. Simple Example, Accepting All Defaults 
' WriteToEventLog "Hello Event Log" 

'2. Specify EventSource, EventType, and LogName 
' WriteToEventLog("Danger, Danger, Danger", "MyVbApp", _ 
'      EventLogEntryType.Warning, "System") 
' 
'NOTE:  EventSources are tightly tied to their log. 
'   So don't use the same source name for different 
'   logs, and vice versa 
     '****************************************************** 

     Dim objEventLog As New EventLog() 

     Try 
      'Register the App as an Event Source 
      If Not objEventLog.SourceExists(AppName) Then 

       objEventLog.CreateEventSource(AppName, LogName) 
      End If 

      objEventLog.Source = AppName 

      'WriteEntry is overloaded; this is one 
      'of 10 ways to call it 
      objEventLog.WriteEntry(Entry, EventType) 
      Return True 
     Catch Ex As Exception 
      Return False 

     End Try 

    End Function 
+0

Grazie per questo aiuto dettagliato. Cercherò di includerlo nella mia app. –

+0

System.Diagnostics può scrivere in altri posti rispetto al registro eventi. –

13

Come accennato in precedenza, NLog e log4net sono entrambi buoni quadri di registrazione. Come sopra menziona Jeff, System.Diagnostics è anche una scelta ragionevole (per qualcosa di più della semplice registrazione al registro eventi). Cercando di aggiungere un valore alla mia risposta, piuttosto che solo ripetere a pappagallo ciò che è già stato detto, è possibile migliorare la registrazione System.Diagnostics utilizzando TraceSources e utilizzando lo Ukadc.Diagnostics library from codeplex gratuito.

Con TraceSources è possibile creare "logger denominati", in modo simile a come è possibile farlo in NLog e log4net. Queste TraceSources possono essere configurate per il log a determinati livelli (variabili per TraceSource) e possono essere inviate a varie destinazioni (TraceListeners). Tutti i TraceSources possono accedere allo stesso listener o alcuni possono accedere ad alcuni listener mentre altri si collegano ad altri listener. Qualsiasi TraceSource può anche essere inviata a più TraceListeners.

Ecco come utilizzare TraceSources nel codice (si presuma che TraceSource "abc" sia stato configurato nel file app.config per registrare "Info" e messaggi con priorità più alta ed è stato configurato per accedere al file "log". testo").

public class MyClass 
{ 
    static TraceSource ts = new TraceSource("abc"); //Common idiom for NLog and log4net, not sure if as common for TraceSource 

    public void Func1(int x) 
    { 
    ts.Information("Entering Func1"); 
    ts.Verbose("x = {0}", x); //Won't log if "abc" is configured to log Info and HIGHER messgaes 
    ts.Information("Exiting Func1"); 
    } 
} 

Un enorme vantaggio di Ukadc.Diagnostics, oltre TraceSources "semplice", è che è possibile configurare la formattazione dell'output NLog/stile log4net così si può avere molto più controllo su ciò che i campi appaiono nel vostro output di registrazione e quello che formato.

Tre cose che sono abbastanza utili da NLog/log4net che non sono disponibili in System.Diagnostics sono:

  1. Possibilità di registrare automaticamente le informazioni sito di chiamata (metodo/funzione)

  2. registrazione supplementare contesto (GDC - proprietà globali di registrazione, MDC - proprietà di registrazione del thread in linguaggio NLog/log4net). System.Diagnostics ha Trace.CorrelationManager.LogicalOperationStack, che è simile a NDC.

  3. Taglialegna gerarchica.

logger Hierarichical significa che si potrebbe configurare un logger "antenato" e qualsiasi "discendente" logger erediteranno quelle impostazioni. Ad esempio, si supponga di avere una classe il cui nome di tipo completo (nome spazio) completo sia Namespace1.Namespace2.Class. Con NLog/log4net è possibile configurare le informazioni di registrazione (livello, destinazione) per "Namespace1" e se si è richiesto un programma di registrazione basato sul nome completo di qualsiasi tipo in Namespace1, esso erediterà le impostazioni di Namespace1. È possibile ottenere qualcosa di simile a questo utilizzando TraceSources esaminando come astrazione Castle implemented their TraceSource-based logging. In particolare, guarda la funzione Initialize. È piuttosto facile lavorare (nel proprio involucro sottile attorno a TraceSource) e, come vantaggio collaterale, rende la configurazione di TraceSources un po 'più semplice dato che non è necessario configurare ogni singola TraceSource singolarmente. Si noti che è possibile aggiungere facilmente la possibilità di avere una configurazione "root" configurando una TraceSource chiamata "" e aggiungendo del codice nello schema Castle per l'impostazione predefinita alla configurazione "" se non si trovano veri antenati. Ad esempio, è possibile configurare "*" per accedere, ad esempio Verbose, e quindi configurare in modo specifico determinate TraceSources (per classe o per spazio dei nomi) da disattivare o su un livello diverso. Senza logger gerarchici, fare lo stesso con TraceSources avrebbe richiesto di configurare ogni singola TraceSource per accedere a "Verbose" che si desidera a verbose.

Mentre ho parlato molto dei logger per classi e spazi dei nomi, NLog, log4net e TraceSources consentono anche di definire i nomi dei logger come stringhe arbitrarie. Come tale, è freddo definire una gerarchia logger per area funzionale piuttosto che dal namespace/classe:

Database 
Database.Connect 
Database.Query 
Database.Update 
Database.SQL 
Amazon 
Amazon.Books 
Amazon.Books.Fiction 
Amazon.Books.Nonfiction 
Amazon.Electronics 
Amazon.Electronics.Video 
Amazon.Electronics.Music 
Amazon.Electronics.Computer 

Quindi, si potrebbe attivare la registrazione "Amazon" e tutti log Amazon roba (senza dover configurare esplicitamente ogni "child" TraceSource) e roba di database non lo farebbero. Oppure, puoi disattivare Amazon e Amazon.Electronics e solo Amazon.Books (e i suoi figli) registreranno.

Infine, se si utilizza NLog o log4net, vale la pena ricordare che NLog ha appena realizzato una nuova versione, NLog 2.0, (in versione beta).

+0

Grazie per la tua risposta approfondita =) Eppure la mia dimensione dell'app sarebbe stata quasi moltiplicata per 5 se avessi iniziato a usare NLog :) È un'app molto leggera, quindi non ha davvero bisogno * di * registrazione avanzata. Eppure grazie per la tua grande risposta, che userò per un altro progetto. –

+1

Ottima risposta. Molto accurato, e ha un esempio di codice. Bravo! Questa informazione è proprio quello che stavo cercando. –

0

Uso variabili e timer pubblici aggiungendo nuove righe al file txt.

E.g.

Public Class Form1 

    Public WriteToLog = "" 

    Dim LogFilePath As String = My.Application.Info.DirectoryPath & "\applog.txt" 

.... 

    Public Function Log_to_txt(ByVal text As String) 

     Dim CurDate As String 
     CurDate = Format(Now, "General Date") 

     WriteToLog = WriteToLog & "[" & CurDate & "] " & text & vbCrLf 

     Return True 

    End Function 

... 

Log_to_txt("Application started...") 

... 

    Private Sub WriteToLogTimer_Tick(sender As Object, e As EventArgs) Handles WriteToLogTimer.Tick 

     Dim CatchLog As String = WriteToLog 

     WriteToLog = "" 

     Try 

      My.Computer.FileSystem.WriteAllText(LogFilePath, CatchLog, True) 

     Catch ex As IOException 

     End Try 

    End Sub 
Problemi correlati