2009-10-28 15 views
15

Sto cercando di capire come gestire i miei ID evento. Fino a questo punto ho inserito ogni id di evento in ciascun metodo manualmente con ogni fase di un metodo numerato in sequenza. Ciò non mi consente di filtrare in modo efficace gli eventi nel registro eventi. Per utilizzare il filtro nel registro eventi, sembra che ogni evento registrato abbia il proprio ID univoco.Quali sono le best practice per la gestione dell'ID evento?

Potrei memorizzarli tutti in una tabella con la descrizione collegata a loro, ma poi mentre il mio codice viene eseguito, sto registrando "magici" codici evento privi di significato.

Ho fatto una ricerca su Google, ma mi sembra che non sappia quali sono le parole chiave corrette da utilizzare per arrivare alla fine di questo problema.

Grazie in anticipo

+0

Non utilizzato mai ID evento quando si accede al registro eventi. Ho appena inserito abbastanza informazioni su ciò che stava accadendo a quel punto e le ho lasciato copiare ... – Will

+0

@Will - Quindi, come si filtra il registro degli eventi quando si cerca di trovare gli articoli rilevanti? Ad esempio, se ho un componente che sta registrando in modo verboso, ma sto cercando un evento specifico, l'unico modo in cui posso filtrare è il filtro sull'ID evento. – BobTheBuilder

+0

@Will - l'idea qui è di valutare la frequenza di occorrenza di un particolare evento senza dover scavare nel registro articolo per articolo per trovare quelli rilevanti. – BobTheBuilder

risposta

7

Primo pensiero - e ho pensato che questo non del tutto ancora finito, ma sembra una possibilità ragionevole:

public class LogEvent 
{ 
    /* This is the event code you reference from your code 
    * so you're not working with magic numbers. It will work 
    * much like an enum */ 
    public string Code; 

    /* This is the event id that's published to the event log 
    * to allow simple filtering for specific events */ 
    public int Id; 

    /* This is a predefined string format that allows insertion 
    * of variables so you can have a descriptive text template. */ 
    public string DisplayFormat; 

    /* A constructor to allow you to add items to a collection in 
    * a single line of code */ 
    public LogEvent(int id, string code, string displayFormat) 
    { 
     Code = code; 
     Id = id; 
     DisplayFormat = displayFormat; 
    } 
    public LogEvent(int id, string code) 
     : this(id, code, null) 
    { 
    } 
    public LogEvent() 
    { 
    } 
} 

si può quindi avere una classe di event manager che avvolge l'elenco degli eventi che forniscono un metodo che interroga la lista in base al parametro si passa - per esempio:

public class EventManager 
{ 
    private List<LogEvent> _eventList; 
    public LogEvent this[string eventCode] 
    { 
     get 
     { 
      return _eventList.Where(i => i.Code.Equals(eventCode)).SingleOrDefault(); 
     } 
    } 
    public LogEvent this[int id] 
    { 
     get 
     { 
      return _eventList.Where(i => i.Id.Equals(id)).SingleOrDefault(); 
     } 
    } 
    public void AddRange(params LogEvent[] logEvents) 
    { 
     Array.ForEach(logEvents, AddEvent); 
    } 
    public void Add(int id, string code) 
    { 
     AddEvent(new LogEvent(id, code)); 
    } 
    public void Add(int id, string code, string displayFormat) 
    { 
     AddEvent(new LogEvent(id, code, displayFormat)); 
    } 
    public void Add(LogEvent logEvent) 
    { 
     _events.Add(logEvent); 
    } 
    public void Remove(int id) 
    { 
     _eventList.Remove(_eventList.Where(i => i.id.Equals(id)).SingleOrDefault()); 
    } 
    public void Remove(string code) 
    { 
     _eventList.Remove(_eventList.Where(i => i.Code.Equals(code)).SingleOrDefault()); 
    } 
    public void Remove(LogEvent logEvent) 
    { 
     _eventList.Remove(logEvent); 
    } 
} 

Questo permette una gestione semplificata di ev definizioni ent che possono essere gestite indipendentemente per ogni TraceSource.

var Events = new EventManager(); 
Events.AddRange(
    new LogEvent(1, "BuildingCommandObject", "Building command object from {0}."), 
    new LogEvent(2, "CommandObjectBuilt", "Command object built successfully."), 
    new LogEvent(3, "ConnectingToDatabase", "Connecting to {0}."), 
    new LogEvent(4, "ExecutingCommand", "Executing command against database {0}".), 
    new LogEvent(5, "CommandExecuted", "Command executed succesfully."), 
    new LogEvent(6, "DisconnectingFromDatabase", "Disconnecting from {0}."), 
    new LogEvent(7, "Disconnected", "Connection terminated.") 
) 

E si può accedere agli eventi utilizzando l'identificatore di significato che è stato assegnato:

var evt = Events["ConnectingToDatabase"]; 
TraceSource.TraceEvent(TraceEventType.Information, evt.Id, evt.DisplayFormat, otherParams); 

o

var evt = Events[1024]; 
Console.WriteLine("Id: {1}{0}Code: {2}{0}DisplayFormat{3}", 
    Environment.NewLine, evt.Id, evt.Code, evt.DisplayFormat); 

questo probabilmente semplificare la gestione degli eventi, non si è più chiamare il tuo sei eventi per numeri magici, è semplice gestire tutti i tuoi eventi in un unico posto: la tua classe EventManager e puoi ancora filtrare il registro degli eventi per i numeri magici che richiede di filtrare.

+0

"E puoi accedere agli eventi usando un identificatore significativo mentre passi ancora" - passando il cosa? – BobTheBuilder

+0

Rifarei _eventList per utilizzare ImmutableDictionary. Ciò eliminerebbe la necessità di utilizzare una query LINQ lenta. Potrebbe non sembrare lento, ma la sua complessità computazionale è O (n), mentre ImmutableDictionary garantisce O (1) accesso in lettura. Inoltre, non vedo un caso d'uso per rimuovere eventi. Consentendo la rimozione di eventi creerai record di log eventi orfani senza chiave. Non chiamare AddRange; basta passare nel dizionario. Inoltre, il formattatore dovrebbe essere un formatter generico di prima classe (formato stringa) anziché una stringa, quindi è chiaro all'utente quale tipo di argomento deve passare nel formattatore. –

10

Come suggerimento di Ben, è probabilmente la pena utilizzando un livello di indirezione - ma invece di utilizzare un int per il codice, userei un enum reale, in modo per esempio di Ben:

public enum EventId 
{ 
    [Format("Building command object from {0}.")] 
    BuildingCommandObject = 1, 
    [Format("Command object build successfully.")] 
    CommandObjectBuilt = 2, 
    [Format("Connecting to {0}.")] 
    ConnectingToDatabase = 3, 
    [Format("Executing command against database {0}.")] 
    ExecutingCommand = 4, 
    [Format("Command executed successfully.")] 
    CommandExecuted = 5, 
    [Format("Disconnecting from {0}.")] 
    DisconnectingFromDatabase = 6, 
    [Format("Connection terminated")] 
    Disconnected = 7 
} 

Oppure, in alternativa (e in un object-oriented di moda più) utilizzare il modello "intelligente enum"):

public class LogEvent 
{ 
    public static readonly LogEvent BuildingCommandObject = new LogEvent(1, 
     "Building command object from {0}"); 
    // etc 

    private readonly int id; 
    private readonly string format; 

    // Add the description if you want 
    private LogEvent(int id, string format) 
    { 
     this.id = id; 
     this.format = format; 
    } 

    public void Log(params object[] data) 
    { 
     string message = string.Format(format, data); 
     // Do the logging here 
    } 
} 

È quindi possibile chiamare:

LogEvent.BuildingCommandObject.Log("stuff"); 

Con un po 'di lavoro, è possibile che sia in grado di esporlo in modo sicuro con eventi di registro diversi con un'interfaccia diversa per renderlo sicuro (in fase di compilazione) in termini di quanti parametri ciascuno ha.In effetti sono sicuro che potresti farlo usando le interfacce e una classe nidificata privata, ma sono le 4 di mattina e sono troppo stanco per scriverlo :)

0

So che questa è una vecchia domanda, ma forse eri tu alla ricerca di un modo per fare qualcosa di simile, in cui si utilizza ID evento su misura per scopi diversi, e li chiamano nei loro luoghi appropriati nel codice:

public class ErrorLog 
{ 
    //Notifications 
    public const int NOTIFY_ALPHA = 2000; 
    public const int NOTIFY_BETA = 2001; 
    public const int NOTIFY_GAMMA = 2002; 

    public static string[] errMessage = 
     {"Critical Error.",   //2000 
     "File not found.",   //2001 
     "Unknown Event Action Encountered - "  //2002 
     }; 

    public static string GetErrMsg(int errNum) 
    { 
     return (errMessage[errNum-2000]); 
    } 

    private static bool ErrorRoutine(int eventLogId) 
    { 
     try 
     { 
      string eventAppName = "My Application"; 
      string eventLogName = "My Apps Events"; 
      string msgStr = GetErrMsg(eventLogId); // gets the message associated with the ID from the constant you passed in 

      if (!EventLog.SourceExists(eventAppName)) 
       EventLog.CreateEventSource(eventAppName, eventLogName); 

      EventLog.WriteEntry(eventAppName, msgStr, EventLogEntryType.Error, eventLogId); 

      return true; 
     } 
     catch (Exception) 
     { 
      return false; 
     } 
    } 
} 

e allora si sarebbe chiamare questa classe come questa, quando hai lanciato la tua eccezione:

ErrorLog.ErrorRoutine(ErrorLog.NOTIFY_ALPHA); 

Per quanto riguarda le migliori pratiche, dovrei dire che è bene avere tutta la gestione degli errori nella propria classe se sarà come personalizzato (o anche di più, come quando si collegano gli avvisi e le informazioni EventLogEntryTypes o informazioni aggiuntive rispetto ai messaggi predefiniti) rispetto a questo. Avere ID individuali è possibile guardare i loro messaggi in questo modo renderà la vita più facile quando si cerca di risolvere il messaggio da chiamare, quando e dove.

Problemi correlati