Click here to Skip to main content
15,867,568 members
Articles / Programming Languages / C#

Top 9 Windows Event Log Tips Using C#

Rate me:
Please Sign up or sign in to vote.
4.92/5 (6 votes)
8 Feb 2016Ms-PL5 min read 23.9K   18   6
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

C#
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

C#
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

C#
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
C#
// 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
 
XML
<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.

C#
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
<?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.

C#
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.

C#
public interface ILogger
{
    void LogInfo(string message);

    void LogError(Exception exception);
}

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

C#
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.

C#
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. 

C#
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.

C#
[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.

C#
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.

C#
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.

C#
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

This article was originally posted at http://automatetheplanet.com/windows-event-log-tips

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
CEO Automate The Planet
Bulgaria Bulgaria
CTO and Co-founder of Automate The Planet Ltd, inventor of BELLATRIX Test Automation Framework, author of "Design Patterns for High-Quality Automated Tests: High-Quality Test Attributes and Best Practices" in C# and Java. Nowadays, he leads a team of passionate engineers helping companies succeed with their test automation. Additionally, he consults companies and leads automated testing trainings, writes books, and gives conference talks. You can find him on LinkedIn every day.

Comments and Discussions

 
Suggestionreading the event log(s)... Pin
John Torjo9-Feb-16 9:24
professionalJohn Torjo9-Feb-16 9:24 
QuestionWhen to use? Pin
Rob Philpott8-Feb-16 1:07
Rob Philpott8-Feb-16 1:07 
AnswerRe: When to use? Pin
Slacker0078-Feb-16 5:42
professionalSlacker0078-Feb-16 5:42 
GeneralRe: When to use? Pin
Anton Angelov8-Feb-16 8:10
Anton Angelov8-Feb-16 8:10 
QuestionImages and scripts won't show Pin
User 95579247-Feb-16 23:24
User 95579247-Feb-16 23:24 
AnswerRe: Images and scripts won't show Pin
Anton Angelov8-Feb-16 3:57
Anton Angelov8-Feb-16 3:57 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.