Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Top 9 Windows Event Log Tips Using C#

0.00/5 (No votes)
8 Feb 2016 1  
Learn how to use the Windows Event Log via C#. Find different logging solutions and various test strategies.The post Top 9 Windows Event Log Tips Using C# appeared first on Automate The Planet.

In this article, I am going to share with you my tips and tricks on how to use Windows Event Log with C#. You will find some basic examples to get you started. After that in the publication, you will read about how to create Event Loggers through prominent logging libraries like log4net and NLog. At the end of the article, I am going to show you how to create unit and integration tests for your event log loggers.

Getting Started Event Log C#

Definition

Event Viewer is a tool that displays detailed information about significant events (for example, programs that don't start as expected or updates that are downloaded automatically) on your computer. Event Viewer can be helpful when troubleshooting problems and errors with Windows and other programs.

To start writing messages to the Event Log, you first need to create a new event source.

Create Event Source

if (!EventLog.SourceExists("Automate The Planet"))
{
    EventLog.CreateEventSource("Rock'N'Roll", "Automate The Planet");
} 

The code first checks if the event source exists if it doesn't, it is created.

Write New Event Log Entry

EventLog eventLog = new EventLog();
eventLog.Source = "Automate The Planet";

// Write a new entry to the source.
eventLog.WriteEntry("You need community. It’s here and it’s waiting just for you. ",
EventLogEntryType.Information);

Create a new log instance and assign its source instance. Then call the WriteEntry method.

Read Event Log Entries

EventLog automateThePlanetLog = new EventLog();
automateThePlanetLog.Log = "Automate The Planet";
foreach (EventLogEntry entry in automateThePlanetLog.Entries)
{
    Console.WriteLine(entry.Message);
} 

The above code reads all the entries from the log named "Automate The Planet". The entry object contains all the information about the log entry,

Delete Event Source
// Delete Event Source if exists.
if (EventLog.SourceExists("Rock'N'Roll"))
{
    EventLog.DeleteEventSource("Rock'N'Roll");
}

// Delete the Log
if (EventLog.Exists("Automate The Planet"))
{
    // Delete Source
    EventLog.Delete("Automate The Planet");
}  

If the event log source exists then, we delete it. The same is valid for the event log.

Write to Event Log log4net

Definition

The Apache log4net library is a tool to help the programmer output log statements to a variety of output targets. log4net is a port of the excellent Apache log4j™ framework to the Microsoft® .NET runtime.

 
It is a piece of cake to configure log4net to start logging messages to specified event log. You need the following information in your app.config or log4net.config
 
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net" />
  </configSections>
  <log4net debug="true">
    <appender name="EventLogAppender" type="log4net.Appender.EventLogAppender">
      <param name="LogName" value="Kaspersky Event Log" />
      <param name="ApplicationName" value="kis" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%-5level %logger - %message%newline" />
      </layout>
    </appender>
    <root>
      <priority value="DEBUG" />
      <appender-ref ref="EventLogAppender" />
    </root>
  </log4net> 

Set the LogName parameter to be equal to the name of the event log where your code needs to write. The ApplicationName should be set to the name of the event log source.

private static readonly log4net.ILog log = 
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
static void Main(string[] args)
{
    log.Info("log4net log message to Kaspersky event log.");
}

The above code is going to write the specified message in the 'Kaspersky Event Log' event log with source kis.

Write to Event Log NLog

Definition

NLog is a free logging platform for .NET, Silverlight and Windows Phone with rich log routing and management capabilities. NLog makes it easy to produce and manage high-quality logs for your application regardless of its size or complexity.
 
To start using NLog, first you need to install two NuGet packages- NLog and NLog.Config. The later is going to add the NLog.config file to your project. The below configuration will set up the logger to write the new messages to the specified event log.
 
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"
      autoReload="true"
      throwExceptions="false"
      internalLogLevel="Off" internalLogFile="c:\temp\nlog-internal.log" >
  <targets>
    <target
      name="eventlog"
      xsi:type="EventLog"
      layout="${longdate}|${level}|${message}"
      log="Kaspersky Event Log"
      source="kis"
      machineName="." />
  </targets>
  <rules>
    <logger name="*" minlevel="Trace" writeTo="eventlog" />
  </rules>
</nlog>

The below code is going to write the specified message to the Kaspersky Event Log.

private static Logger logger = LogManager.GetCurrentClassLogger();
public static void Main(string[] args)
{
    logger.Info("NLog log message to Kaspersky event log.");
}​

Unit Test Event Log Logger

To be able to exchange the logger solutions if needed, we can create a logger interface that is going to be used in the production code.

public interface ILogger
{
    void LogInfo(string message);

    void LogError(Exception exception);
}

After that we can create a concrete logger implementation that depends on NLog.

public class EventLogger : ILogger
{
    private readonly Logger logger = LogManager.GetCurrentClassLogger();

    public void LogInfo(string message)
    {
        if (string.IsNullOrEmpty(message))
        {
            throw new ArgumentException("The logged message cannot be null or empty.");
        }
        logger.Log(LogLevel.Info, message);
    }

    public void LogError(Exception exception)
    {
        logger.Log(LogLevel.Error, exception.Message);
    }
}

Let's assume that we need to create a calculation application. Before the calculation, a new message should be written to the event log.

public class Calculator
{
    private readonly ILogger logger;

    public Calculator(ILogger logger)
    {
        this.logger = logger;
    }

    public int Sum(int a, int b)
    {
        logger.LogInfo(string.Format("Sum {0} and {1}", a, b));
        return a + b;
    }
}

As you can see the Calculator is not using the EventLogger directly but is working with the ILogger interface. We can use unity IOC container to initialize the calculator app and the logger. 

public static void Main(string[] args)
{
    // Register a type to have a singleton lifetime without mapping the type
    IUnityContainer unityContainer = new UnityContainer();
    unityContainer.RegisterType<Loggers.ILogger, EventLogger>(
        new ContainerControlledLifetimeManager());
    Loggers.ILogger eventLogger = unityContainer.Resolve<Loggers.ILogger>(); 
    eventLogger.LogInfo("EventLogger log message to Kaspersky event log.");
}​

If you need to write unit tests for the Calculator, it is really easy to mock the EventLogger. For a mocking framework, I use Telerik Just Mock. You can install it as a NuGet package. The Lite version is free.

[TestClass]
public class CalculatorShould
{
    [TestMethod]
    public void LogMessageWhenSumNumbers()
    {
        //Arrange
        var logger = Mock.Create<ILogger>();
        string loggedMessage = string.Empty;
        Mock.Arrange(() => logger.LogInfo(Arg.AnyString)).
        DoInstead(() => loggedMessage = "Automate The Planet rocks!");
        Calculator calculator = new Calculator(logger);

        //Act
        calculator.Sum(1, 1);

        //Assert
        Assert.AreEqual<string>("Automate The Planet rocks!", loggedMessage);
    }
}
 

As the calculator app uses an interface instead of the EventLogger directly, it is easy to mock its behaviour. Instead of sending the specified message to the event log, we set the loggedMessage variable. If the LogInfo method is called the variable is initialized. At the end of the test assert that the correct string is assigned.

Integration Test Event Log Logger

Sometimes you need to test the real integration between the event log and your application. If you develop a web application, it may be deployed on multiple machines so you should be able to test against all of them.

public abstract class EventLogAsserter
{
    private readonly string logName;
    private readonly List<string> machineNames;
    private readonly List<EventLog> eventLogs;
    private readonly List<EventLogEntry> revertedEventLogEntries;

    public EventLogAsserter(string logName, List<string> machineNames)
    {
        this.logName = logName;
        this.machineNames = machineNames;
        this.eventLogs = new List<EventLog>();
        this.revertedEventLogEntries = new List<EventLogEntry>();
    }

    public void AssertMessageExistsInTop(string message, string sourceName, int topCount)
    {
        bool isMessagePresent = false;
        this.InitializeEventLogs(sourceName);
        for (int i = 0; i < topCount; i++)
        {
            if (this.revertedEventLogEntries.Count > i)
            {
                var currentEntry = revertedEventLogEntries[i];
                if (currentEntry.Message.Contains(message))
                {
                    isMessagePresent = true;
                    break;
                }
            }
            else
            {
                break;
            }
        }

        Assert.IsTrue(isMessagePresent, 
        "The event log '{0}' doesn't contain the message '{1}'", 
        this.logName,
        message);
    }

    private void InitializeEventLogs(string sourceName)
    {
        this.eventLogs.Clear();
        this.revertedEventLogEntries.Clear();
        foreach (var currentMachine in this.machineNames)
        {
            try
            {
                var currentEventLog = new EventLog(this.logName, currentMachine, sourceName);
                this.eventLogs.Add(currentEventLog);
                var eventLogEntries = new EventLogEntry[currentEventLog.Entries.Count];
                currentEventLog.Entries.CopyTo(eventLogEntries, 0);
                this.revertedEventLogEntries.AddRange(eventLogEntries.Reverse().ToList());
            }
            catch (InvalidOperationException ex)
            {
                string eventLogNotFoundExceptionMessage = 
                string.Format("The specified event log- '{0}' doesn't exist on machine- '{1}'",
                this.logName,
                currentMachine);
                throw new NonExistingEventLogException(eventLogNotFoundExceptionMessage, ex);
            }
        }
    }
}

This is the base class for the specific event logs asserters. It is going to get the event log entries from the specified event log from all mentioned machines. The log entries are populated reverted so that you can check the newest first. Through the public method AssertMessageExistsInTop, you can check if a particular message exists in the last topCount messages in the event log.

public class AntonMachineEventLogAsserter : EventLogAsserter
{
    public AntonMachineEventLogAsserter()
        : base("Application", new List<string>() { "DESKTOP-FL88834" })
    {
    }
}

The specific loggers inherit the EventLogAssert and pass to its constructor the name of the event log and the list of machines' names.

The usage is pretty straightforward.

AntonMachineEventLogAsserter eventLogAsserter = new AntonMachineEventLogAsserter();
eventLogAsserter.AssertMessageExistsInTop(
  "The VSS service is shutting down due to idle timeout.", "VSS", 22);​

Test Manually Remote Machines' Event Logs

Open the Event Viewer. Click on the Action menu item and choose Connect to another Computer. You need to be added as an administrator of the remote machine.

 
If you enjoy my publications, feel free to SUBSCRIBE
Also, hit these share buttons. Thank you!
 

All images are purchased from DepositPhotos.com and cannot be downloaded and used for free.
License Agreement

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here