2009-10-28 10 views
15

Estoy tratando de encontrar la manera de administrar mis identificaciones de eventos. Hasta este punto he estado poniendo cada identificación de evento en cada método de forma manual con cada paso en un método numerado secuencialmente. Esto no me permite filtrar eventos de manera efectiva en el registro de eventos. Para utilizar el filtro en el registro de eventos, parece que cada evento registrado debe tener su propia identificación única.¿Cuáles son las mejores prácticas para la gestión de id. De evento?

Pude almacenarlos todos en una tabla con la descripción vinculada a ellos, pero luego cuando se ejecuta mi código, estoy registrando códigos de eventos sin sentido "mágicos".

Hice una búsqueda en Google, pero parece que no conozco las palabras clave correctas para utilizar para llegar al fondo de este problema.

Gracias de antemano

+0

Nunca se usaron identificadores de eventos al iniciar sesión en el registro de eventos. Acabo de poner suficiente información sobre lo que estaba sucediendo en ese punto y la dejé explotar ... – Will

+0

@Will - Entonces, ¿cómo se filtra el registro de eventos cuando se trata de encontrar elementos relevantes? Por ejemplo, si tengo un componente que actualmente está iniciando una sesión exhaustiva pero estoy buscando un evento específico, la única manera en que puedo filtrar es filtrando en la identificación del evento. – BobTheBuilder

+0

@Will - la idea aquí es evaluar la frecuencia de ocurrencia de un evento en particular sin tener que cavar a través del registro elemento por elemento para encontrar los relevantes. – BobTheBuilder

Respuesta

7

primer pensamiento - y no he pensado en su totalidad a través de este todavía, pero parece como una posibilidad razonable:

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() 
    { 
    } 
} 

, entonces puede tener una clase de gestor de eventos que envuelve su lista de eventos que proporcionan un método que consulta la lista según el parámetro que pasa - por ejemplo:

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); 
    } 
} 

Esto permite una administración simplificada de ev definiciones que se pueden gestionar de forma independiente para cada 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.") 
) 

Y se puede acceder a los eventos utilizando el identificador significativa que ha asignado:

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); 

Esto probablemente simplificar su gestión de eventos, ya no eres llamando a su eventos por números mágicos, es fácil administrar todos tus eventos en un solo lugar: tu clase de EventManager y aún puedes filtrar tu registro de eventos por los números mágicos que debes filtrar.

+0

"Y puede acceder a los eventos usando un identificador significativo mientras sigue pasando el" - ¿pasando el qué? – BobTheBuilder

+0

Refactorizaría _eventList para usar ImmutableDictionary. Esto eliminaría la necesidad de utilizar una consulta LINQ lenta. Puede que no parezca lento, pero su complejidad computacional es O (n), mientras que ImmutableDictionary garantiza O (1) acceso de lectura. Además, no veo un caso de uso para eliminar eventos. Permitir la eliminación de eventos creará registros de registro de eventos huérfanos sin clave. No llame a AddRange; solo pasa en el diccionario. Además, el formateador debe ser un formateador genérico de primera clase (formato de cadena) en lugar de una cadena, por lo que es claro para el consumidor qué tipo de argumento pasar al formateador. –

10

Como sugerencia de Ben, es probable que vale la pena utilizar un nivel de indirección - pero en lugar de utilizar un int para el código, que haría uso de una enumeración real, por lo que, por ejemplo, de 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 
} 

O, alternativamente, (y de una manera más orientada a objetos) utiliza el patrón "enumeración inteligente"):

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 
    } 
} 

a continuación, puede llamar a:

LogEvent.BuildingCommandObject.Log("stuff"); 

Con un poco de trabajo, puede exponer esto de manera segura con diferentes eventos de registro que tienen una interfaz diferente para que sea seguro (en tiempo de compilación) en términos de cuántos parámetros tiene cada uno.De hecho, estoy seguro de que podría hacerlo utilizando interfaces y una clase privada anidada, pero son las 4am y estoy demasiado cansado para escribirlo en la atmósfera :)

0

Sé que esta es una pregunta antigua, pero tal vez en busca de una manera de hacer algo como esto, en el que utiliza identificadores de sucesos personalizados para diferentes propósitos, y llamarlos en sus lugares apropiados en el código:

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; 
     } 
    } 
} 

y entonces lo que llamar a esta clase como esta, cuando usted lanzó su excepción:

ErrorLog.ErrorRoutine(ErrorLog.NOTIFY_ALPHA); 

En cuanto a las mejores prácticas van, I wo Dice que es bueno tener todo el manejo de errores en su propia clase si será como personalizado (o más, como cuando se vinculan advertencias e información EventLogEntryTypes o información adicional que los mensajes enlatados) que este. Tener identificaciones individuales para mirar sus mensajes de este modo facilitará su vida al tratar de determinar qué mensaje llamar, cuándo y dónde.

Cuestiones relacionadas