Каковы наилучшие методы управления идентификаторами событий?

Я пытаюсь выяснить, как управлять идентификаторами событий. До этого момента я каждый раз помещал каждый идентификатор события в каждый метод с каждым шагом в способе, пронумерованном последовательно. Это не позволяет эффективно фильтровать события в журнале событий. Чтобы использовать фильтр в журнале событий, кажется, что каждое зарегистрированное событие должно иметь свой собственный уникальный идентификатор.

Я мог бы хранить их все в таблице с описанием, связанным с ними, но затем, когда мой код выполняется, я регистрирую "магические" бессмысленные коды событий.

Я сделал поиск Google, но я, похоже, не понимаю, как правильно использовать ключевые слова, чтобы понять эту проблему.

Заранее спасибо

Ответы

Ответ 1

Первая мысль - и я еще не все это продумал, но это кажется разумной возможностью:

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

Затем вы можете создать класс менеджера событий, который переносит список событий, предоставляющий метод, который запрашивает список в соответствии с параметром, который вы передаете, например:

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

Это позволяет упростить управление определениями событий, которые могут управляться независимо для каждого 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.")
)

И вы можете получить доступ к событиям, используя назначенный вами значащий идентификатор:

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

или

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

Это, вероятно, упростит управление вашими событиями, вы больше не будете называть свои события по волшебным числам, просто управлять всеми своими событиями в одном месте - своим классом EventManager, и вы все равно можете фильтровать журнал событий по магическим номерам требуется отфильтровать.

Ответ 2

Как и предложение Бена, возможно, стоит использовать уровень косвенности - но вместо того, чтобы использовать int для кода, я бы использовал фактическое перечисление, поэтому для примера Бена:

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
}

Или, альтернативно (и более объектно-ориентированным способом) используйте шаблон "умный 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
    }
}

Затем вы можете позвонить:

LogEvent.BuildingCommandObject.Log("stuff");

С небольшим количеством работы вы можете предоставить это безопасным способом с различными событиями журнала, имеющими другой интерфейс, чтобы сделать его безопасным (во время компиляции) с точки зрения того, сколько параметров у каждого есть. На самом деле я уверен, что вы могли бы сделать это с помощью интерфейсов и частного вложенного класса, но это 4 утра, и я слишком устал, чтобы написать это atm:)

Ответ 3

Я знаю, что это старый вопрос, но, возможно, вы искали способ сделать что-то вроде этого, когда вы используете пользовательские идентификаторы событий для разных целей и вызываете их в соответствующих местах вашего кода:

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

И тогда вы бы назвали этот класс следующим, когда вы выбросили свое исключение:

ErrorLog.ErrorRoutine(ErrorLog.NOTIFY_ALPHA);

Что касается лучших практик, я бы сказал, что хорошо иметь всю обработку ошибок в своем собственном классе, если это будет как обычай (или, более того, например, при связывании предупреждений и информации EventLogEntryTypes или дополнительной информации, чем консервные сообщения дают), чем этот. Имея индивидуальные идентификаторы, вы можете найти их сообщения, подобные этому, облегчит вам жизнь, пытаясь разобраться, какое сообщение нужно вызвать, когда и где.