How to Build a Simple Event Log Montior/Watcher (Using TCP in .NET)

How to Build a Simple Event Log Monitor/Watcher (Using TCP in .NET)

Other articles about how to build a process (Windows application or Windows Service) to watch/monitor Windows Event Logs on a remote computer:

.NET allows a developer to attach a “handler” to monitor for event log changes:

        ...
   Dim objLog As EventLog = New EventLog("Application")
   AddHandler objLog.EntryWritten, _
      AddressOf ApplicationLog_OnEntryWritten
   objLog.EnableRaisingEvents = True
      ...
Public Sub ApplicationLog_OnEntryWritten(ByVal [source] As Object, _
   ByVal e As EntryWrittenEventArgs)
      Try
         'handle event log change here
      Catch err As Exception
      'oops
      End Try
   End Sub

The only problem with this approach is that it does not allow you to monitor event log changes on a remote machine. See Microsoft support article 815314.

The following code allows you to build a simple event log “watcher” application to monitor event log changes on a remote machine(s).

Log Monitor Application (“Log Watcher”) consists of two components:

  • Event Log Monitoring Service: Responsible for monitoring event log changes on a machine

  • Centralized “Watcher Host”—Listener: Responsible for gathering data from log monitor services installed on different machines.

First, build a service component that will be responsible for “keeping an eye on” a machine’s event log. To create the service application (in other words, an application that runs as a service):

An application that runs as a service has a few events (inherited from System.ServiceProcess.ServiceBase):


  • OnStart(): Occurs when the service receives a Start command.

  • OnStop(): Occurs when the service receives a Stop command.

  • OnPause() and OnContinue(): Occurs when the service receives a Pause/Resume command.

For this application, you’ll only need the OnStart() and OnStop() events.

...
   'points to machine service is running on
Private m_LocalIP As String = System.Net.Dns.GetHostName()

Private m_Watcher_IP As String      'Listening Log Watcher Host IP
Private m_Watcher_Port As String    'Listening Log Watcher Host Port

Private m_ErrorLogFile As String    'Log file where we can log useful
                                    'information while the service
                                    'is running
...

Protected Overrides Sub OnStart(ByVal args() As String)
   ' Add code here to start your service. This method should set
   ' things in motion so your service can do its work.

   'open config file:    LogMonitoringService.exe.config
   m_Watcher_IP = _
      System.Configuration.ConfigurationSettings.AppSettings. _
      Get("watcher_ip")
   m_Watcher_Port = _
      System.Configuration.ConfigurationSettings.AppSettings. _
      Get("watcher_port")
   m_ErrorLogFile = Path.Combine(GetApplicationDirectory(), _
      "log_monitoring_service_errors.txt")

   WorkerThread = New Thread(AddressOf WatchEventLog)
   WorkerThread.Start()
End Sub

where the config file looks like this:

So, when the service starts, you get configuration settings and start the event log monitor:

Public Sub WatchEventLog()
   Try
      m_LogWatcherLog = New EventLog()
   'just to make sure we have LogMonitoringService source registered
      Try
         m_LogWatcherLog.CreateEventSource("LogMonitoringService", _
                                           "Application")
      Catch
      End Try
      m_LogWatcherLog.Close()
      m_LogWatcherLog = New EventLog("Application", ".", _
                                     "LogMonitoringService")
      m_LogWatcherLog.Source = "LogMonitoringService"

   'make a record in Application log:
      m_LogWatcherLog.WriteEntry("LogWacther started." & vbCrLf & _
         "Send data to [" & m_Watcher_IP & ":" & m_Watcher_Port & "]" _
         & vbCrLf & _
         "Error file [" & m_ErrorLogFile & "]", _
         EventLogEntryType.Information)

   'make a record in log file:
      LogError("LogWacther started." & vbCrLf & _
         "Send data to [" & m_Watcher_IP & ":" _
         & m_Watcher_Port & "]" & vbCrLf & _
         "Error file [" & m_ErrorLogFile & "]")

   ' "attach" to Application Log
      m_ApplicationLog = New EventLog()
      m_ApplicationLog.Log = "Application"
      AddHandler m_ApplicationLog.EntryWritten, _
         AddressOf ApplicationLog_OnEntryWritten
      m_ApplicationLog.EnableRaisingEvents = True

   ' "attach" to System Log
      m_SystemLog = New EventLog()
      m_SystemLog.Log = "System"
      AddHandler m_SystemLog.EntryWritten, _
         AddressOf SystemLog_OnEntryWritten
      m_SystemLog.EnableRaisingEvents = True

      m_run = True
      Do While (m_run)
         Thread.Sleep(10000)
      Loop

   Catch e As Exception
      Dim Log As New EventLog("Application")
      Log.WriteEntry("Failed to WatchEventLog:" &
         e.ToString, EventLogEntryType.Error)
      Log.Close()
      Log.Dispose()
   End Try
End Sub

Now, as soon as a change in the Application or System event logs is detected…

Public Sub ApplicationLog_OnEntryWritten(ByVal [source] As Object, _
   ByVal e As EntryWrittenEventArgs)
   Try
      LogError("Application Log Entry:" & vbCrLf & "Message _
         [" & e.Entry.Message & "]")

      SendEventLogEntryToHost("Application", e.Entry)

   Catch err As Exception
      LogError("Failed to ApplicationLog_OnEntryWritten:" & _
               err.ToString())
   End Try
End Sub

Public Sub SystemLog_OnEntryWritten(ByVal [source] As Object, _
                                    ByVal e As EntryWrittenEventArgs)
   Try
      LogError("System Log Entry:" & vbCrLf & "Message _
               [" & e.Entry.Message & "]")

      'send data to watcher
      SendEventLogEntryToHost("System", e.Entry)

   Catch err As Exception
      LogError("Failed to SystemLog_OnEntryWritten:" & err.ToString())
   End Try
End Sub

… the application will “contact” watching the host and send log entry data:

Private Function SendEventLogEntryToHost(ByVal LogName As String, _
   ByVal e As EventLogEntry) As Boolean
   Try
      Dim objTCP As Socket
      Dim remoteEndPoint As New IPEndPoint( _
         IPAddress.Parse(m_Watcher_IP), m_Watcher_Port)

      objTCP = New Socket( _
         remoteEndPoint.Address.AddressFamily, SocketType.Stream, _
            ProtocolType.Tcp)
      objTCP.Connect(remoteEndPoint)

      If objTCP.Connected Then
         LogError("objTCP socket connected to _
            [" & remoteEndPoint.Address.ToString() & "]" & vbCrLf & _
         " From Port [" & CType(objTCP.LocalEndPoint, IPEndPoint). _
                      Port.ToString() & "]")

         'send data to watcher host:
         Dim Message As String = _
            e.TimeGenerated.ToString("MM/dd/yyyy HH:mm:ss") & "|" & _
                                     LogName & "|" & _
                                     e.EntryType.ToString() & "|" & _
                                     e.Message

         Dim sendBytes As Byte() = _
            System.Text.Encoding.ASCII.GetBytes(Message)
         objTCP.Send(sendBytes, sendBytes.Length, SocketFlags.None)

         LogError("objTCP socket sent [" & sendBytes.Length & "] bytes")
      Else
         LogError("objTCP socket did not connected to _
            [" & remoteEndPoint.Address.ToString() & "]")
      End If

      objTCP.Shutdown(SocketShutdown.Both)
      objTCP.Close()
      LogError("TCP client closed")

   Catch err As Exception
      LogError("Failed to SendEventLogEntryToHost:" & err.ToString())
   End Try
End Function

To make life easier, the service application sends the event log entry as one string:

...
   Dim Message As String = _
      e.TimeGenerated.ToString("MM/dd/yyyy HH:mm:ss") & "|" & _
                               LogName & "|" & _
                               e.EntryType.ToString() & "|" & _
                               e.Message

        Dim sendBytes As Byte() = _
           System.Text.Encoding.ASCII.GetBytes(Message)
        objTCP.Send(sendBytes, sendBytes.Length, SocketFlags.None)
...

And the host will “split” the string into corresponding fields.

More by Author

Must Read