Is there a way to tell which EventLog caused the EntryWritten event in C#?
Asked Answered
H

5

6

I'm working on a web application that shows event logs data, similar to Event Viewer. The application also has to provide a way for users to subscribe to event logs and receive notifications when an entry is written to subscribed logs, using a web service.

I'm using this code to subscribe to an event log in the web service:

EventLog eventLog = new EventLog(observer.logName, observer.machineName);
eventLog.EnableRaisingEvents = true;
eventLog.EntryWritten += new EntryWrittenEventHandler(eventLog_EntryWritten);
eventList.Add(eventLog);

I'm trying to use observers as subscribers to event logs, and when an EventWritten event is handled, call the Update method of one observer. The problem is, I don't know how to differentiate event logs, since they all use the same event handler. I'm doing this because the number of event logs differs from one machine to another. Also, I want observers to handle only one type of EventLog, ie. one observer would send an e-mail when an event is written to the Application log.

I use this line of code to get all logs on the current computer:

remoteEventLogs = EventLog.GetEventLogs(machineName);

EventWritten event handler has this object sender parameter, but Visual Studio shows its type as EventLogInternal, which I can't use, and I can't cast the sender to EventLog to get EventLog.Log property. If I try to cast it, like this:

void eventLog_EntryWritten(object sender, EntryWrittenEventArgs e)
    {
        var log = (EventLog)sender;
    }

I get an exception saying I can't cast an EventLogInternal to EventLog.

Is there a way to know which EventLog fires the event?

Thanks

Helminthic answered 18/5, 2011 at 22:43 Comment(0)
T
3

Another option would be to use reflection along these lines:

string log = (string)sender.GetType().GetProperty("Log").GetValue(sender, null);

since sender in this case actually has the Log property.

Tuition answered 17/6, 2011 at 0:16 Comment(1)
nice temporarily hack. could be issue with new .Net frameworkNan
V
4

I think the problem is, that the whole concept of the EventLog class is that it assumes it works upon a single Log - which it does. So neither the EventWrittenEventArgs nor the EventEntry class sport a member that contains the Log-name, as it is implicitly given by the associated EventLog-instance. Bad is of course, that you cannot get to it inside the EventWritten-handler.

You could create a wrapper around System.Diagnostics.EventLog, like so:

class MyEventLog : EventLog
{
    public MyEventLog(string logName, string machineName)
        : base(logName, machineName)
    {
        base.EnableRaisingEvents = true;
        base.EntryWritten += MyEventLog_EntryWritten;
    }

    void MyEventLog_EntryWritten(object sender, EntryWrittenEventArgs e)
    {
        Console.WriteLine("Entry in {0} log.", base.Log);

        // Your code
    }
}

Then use MyEventLogin places where you normally would use EventLog. Probably give it a better name though.

You could also factor out the "Your Code" part by providing an Action<string, EntryWrittenEventArgs> property that is being called from inside MyEventLog_EntryWritten and can be set to your "external" handler function.

Vanthe answered 19/5, 2011 at 5:16 Comment(3)
Haven't thought of making a wrapper around EventLog, I'll give it a try. Thanks a lotHelminthic
This doesn't allow you to access the log name from within the event handler or I'm missing something.Authorize
base.Log will give you the Name of the log. Or you could store it in a member variable in the constructor and access that from within the event handler (which is a member function).Vanthe
T
3

Another option would be to use reflection along these lines:

string log = (string)sender.GetType().GetProperty("Log").GetValue(sender, null);

since sender in this case actually has the Log property.

Tuition answered 17/6, 2011 at 0:16 Comment(1)
nice temporarily hack. could be issue with new .Net frameworkNan
E
2

I think that what you are looking for can be found in the EntryWrittenEventArgs.

The MSDN shows there is a property called Entry that shows you all kinds of information about what just got logged. There are some properties that might help you in the EventLogEntry class, such as MachineName or UserName.

Here is a link to the Args class http://msdn.microsoft.com/en-us/library/system.diagnostics.entrywritteneventargs.aspx

Here is a link to the Entry class http://msdn.microsoft.com/en-us/library/system.diagnostics.eventlogentry.aspx

I don't see a direct link to the specific event log, but if you poke around in that class with the debugger the Entry object might give you enough information to look it up.

I hope this helps some.

Ethyne answered 18/5, 2011 at 23:52 Comment(1)
Yeah, the problem is, the Entry property doesn't show information about the Log which is being written to in any way.Helminthic
D
0

I agree with the idea of wrapping the EventLog class within another class as suggested by Christian. I recently worked on such a requirement.

This is the class that I created

 public class EventLogWatcher : EventLog
{
    Action<string, EntryWrittenEventArgs> _changeHandler;
    public EventLogWatcher(string logName, Action<string, EntryWrittenEventArgs> changeHandler)
        : base(logName)
    {
        _changeHandler = changeHandler;
    }

    public void EnableCapture()
    {
        base.EnableRaisingEvents = true;
        base.EntryWritten += EventLogChangeHandler;
    }

    public void DisableCapture()
    {
        base.EnableRaisingEvents = false;
        base.EntryWritten -= EventLogChangeHandler;
    }

    private void EventLogChangeHandler(object sender, EntryWrittenEventArgs e)
    {
        _changeHandler(base.Log, e);
    }
}

Here is a usage

 foreach (string eventlogType in LogTypes)
            logWatchers.Add(new EventLogWatcher(eventlogType, EventLogChangeHandler));

        foreach (EventLogWatcher localLog in logWatchers)
        {
            try
            {
                localLog.EnableCapture();
            }
            catch(Exception ex)
            {
                EventManager.PublishExceptionLogMessage(ex);
            }
        }
        EventManager.PublishInfoLogMessage($"Started EventLog listeners for {string.Join(",", LogTypes)} logs");

 private void EventLogChangeHandler(string eventLogType, EntryWrittenEventArgs e)
    {
        try
        {
            if (UploadAllowed(eventLogType, e))
            {

                Dm.EventLog model = _eventLogEntryMapper.MapEntryToModel(e);
                Task.Factory.StartNew(
                       () => _eventLogUploadService.UploadEventLog(model),
                       _cancellationTokenProvider.Token,
                       TaskCreationOptions.None,
                       TaskScheduler.Default);
            }
        }
        catch(Exception ex)
        {
            EventManager.PublishExceptionLogMessage(ex);
        }

    }
Danger answered 31/1, 2017 at 15:28 Comment(0)
M
0

Another option would be to change the event-registration like this:

eventLog.EntryWritten += (sender, e) => eventLog_EntryWritten(eventLog, e);
Mauritius answered 30/1, 2020 at 8:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.