Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add multiple lines of EventData to an EventLog in Windows?

Tags:

c#

event-log

I am able to currently create a Windows Event Log using the following code:

    string sSource;
    string sLog;
    string sEvent;
    sSource = "Sample App";
    sLog = "Application";
    sEvent = "Sample Event";

    if (!EventLog.SourceExists(sSource))
        EventLog.CreateEventSource(sSource,sLog);

EventLog.WriteEntry(sSource, sEvent, EventLogEntryType.Warning, 11111);

This creates a log in the Application Log. I want to add more than one line of data to the event in the event log so that while debugging I can parse the log directly for the problems. Also, I looked at some of the other logs in the Application logs and they seem to have a binary data field in them. I was not able to figure out as to how to write such a field because the above piece of code only adds an EventData field.

like image 476
Anoop Avatar asked Oct 08 '11 01:10

Anoop


4 Answers

One liner should be like this:

EventLog.WriteEvent("Application", new EventInstance(123, 0, EventLogEntryType.Information), new object[] { "Entry1" , "Entry2" });

Here Application is event source, 123 is the event Id and 0 = NONE is event category. You may need to check the existence of the event source first.

This is how the event looks like:

 <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
  <System>
  <Provider Name="Application" /> 
  <EventID Qualifiers="0">1001</EventID> 
  <Level>4</Level> 
  <Task>0</Task> 
  <Keywords>0x80000000000000</Keywords> 
  <TimeCreated SystemTime="2015-07-12T21:26:07.000000000Z" /> 
  <EventRecordID>86554</EventRecordID> 
  <Channel>Application</Channel> 
  <Computer>YOUR_COMPUTER</Computer> 
  <Security /> 
  </System>
  <EventData>
     <Data>Entry1</Data> 
     <Data>Entry2</Data> 
  </EventData>
 </Event>
like image 123
batbaatar Avatar answered Dec 04 '22 06:12

batbaatar


I got a little confused about Prathap Kudpu's answer, so I rewrote it

{
    string sSource = "Application Name";
    string sLog = "Application";

    EventInstance eventInstance = new EventInstance(0, 0, EventLogEntryType.Error);

    List<string> sEvent = new List<string>();
    sEvent.Add("Message 1");
    sEvent.Add("Message 2");
    sEvent.Add("Message 3");

    // Check if Event Source was created (Possibly throw error if you are not running with high privilege)
    if (!EventLog.SourceExists(sSource))
        EventLog.CreateEventSource(sSource, sLog);            

    EventLog.WriteEvent(sSource, eventInstance, sEvent.ToArray());
}

Basically, You create a list of string with the "Lines" or data you Want, create an EventInstance object, and Write an Event instead of WriteEntry

Result:

<EventData>
  <Data>Message 1</Data> 
  <Data>Message 2</Data> 
  <Data>Message 3</Data> 
</EventData>
like image 31
Daniel Avatar answered Dec 04 '22 06:12

Daniel


The above answers are fine if you just want a simple <Data Name="param1">data</Data> structure but it falls down if you want a more complex payload, e.g. like you get in a bluescreen event:

<Data Name="BugcheckCode">4522044</Data> 
<Data Name="BugcheckParameter1">0x74006e00650076</Data> 
<Data Name="BugcheckParameter2">0x61007400610044</Data> 
<Data Name="BugcheckParameter3">0x610044003c003e</Data> 
<Data Name="BugcheckParameter4">0x4e002000610074</Data> 
<Data Name="SleepInProgress">7143521</Data> 
<Data Name="PowerButtonTimestamp">18577494495789157</Data> 
<Data Name="BootAppStatus">6750325</Data> 
<Data Name="Checkpoint">99</Data> 
<Data Name="ConnectedStandbyInProgress">true</Data> 
<Data Name="SystemSleepTransitionsToOn">1795187456</Data> 
<Data Name="CsEntryScenarioInstanceId">0</Data> 
<Data Name="BugcheckInfoFromEFI">true</Data> 

I don't believe this is possible using the EventLog.WriteEntry helper. I noticed you can do this using PowerShell though:

New-WinEvent -ProviderName Microsoft-Windows-Kernel-Power -Id $evtID -Version 5 -Payload "<EventData><Data Name=""BugcheckCode"">210</Data><Data Name=""BugcheckParameter1"">0xffffc080b5744760</Data><Data Name=""BugcheckParameter2"">0x2</Data><Data Name=""BugcheckParameter3"">0x0</Data><Data Name=""BugcheckParameter4"">0xfffff80261641530</Data><Data Name=""SleepInProgress"">0</Data><Data Name=""PowerButtonTimestamp"">0</Data><Data Name=""BootAppStatus"">0</Data><Data Name=""Checkpoint"">0</Data><Data Name=""ConnectedStandbyInProgress"">false</Data><Data Name=""SystemSleepTransitionsToOn"">0</Data><Data Name=""CsEntryScenarioInstanceId"">0</Data><Data Name=""BugcheckInfoFromEFI"">false</Data><Data Name=""CheckpointStatus"">0</Data></EventData>"

So I dug out the dll that this uses and reflected the code out. I ended up with a little helper class that allows you to pass whatever payload you require:

public class EventLogHelper
{
        /// <summary>
        /// Taken from the source code of Microsoft.PowerShell.Commands.NewWinEventCommand
        /// </summary>
        /// <param name="providerName">"Microsoft-Windows-Kernel-Power"</param>
        /// <param name="eventId">41</param>
        /// <param name="version">5</param>
        /// <param name="payLoad"></param>
        public static void AddEventToEventLog(string providerName, long eventId, int version, string payLoad = "")
        {
            using (ProviderMetadata providerMetaData = LoadProvider(providerName))
            {
                EventDescriptor eventDescriptor = LoadEventDescriptor(providerMetaData, eventId, Convert.ToByte(version));


                ProcessRecord(providerMetaData, eventDescriptor, payLoad);
            }
        }

        private static ProviderMetadata LoadProvider(string providerName)
        {
            using (EventLogSession eventLogSession = new EventLogSession())
            {
                IEnumerable<string> providers = eventLogSession.GetProviderNames().OrderBy(s => s);
                foreach (string providerName2 in providers)
                {
                    if (string.Equals(providerName2, providerName, StringComparison.OrdinalIgnoreCase))
                    {

                        return new ProviderMetadata(providerName2);

                    }
                }
            }

            throw new Exception("Failed to find Microsoft-Windows-Kernel-Power provider");
        }

        private static EventDescriptor LoadEventDescriptor(ProviderMetadata providerMetadata, long id, byte version)
        {

            EventMetadata eventMetadata = providerMetadata.Events.First(f => f.Id == id && f.Version == version);

            return CreateEventDescriptor(providerMetadata, eventMetadata);

        }

        private static EventDescriptor CreateEventDescriptor(ProviderMetadata providerMetaData, EventMetadata emd)
        {
            long num = 0L;
            foreach (EventKeyword keyword in emd.Keywords)
            {
                num |= keyword.Value;
            }
            byte b = 0;
            using (IEnumerator<EventLogLink> enumerator2 = providerMetaData.LogLinks.GetEnumerator())
            {
                while (enumerator2.MoveNext() && !string.Equals(enumerator2.Current.LogName, emd.LogLink.LogName, StringComparison.OrdinalIgnoreCase))
                {
                    b = (byte)(b + 1);
                }
            }

            int parsedId = (int)emd.Id;

            if (emd.Id > ushort.MaxValue)
                parsedId = (ushort)emd.Id;

            return new EventDescriptor(parsedId, emd.Version, b, (byte)emd.Level.Value, (byte)emd.Opcode.Value, emd.Task.Value, num);
        }

        private static void ProcessRecord(ProviderMetadata providerMetadata, EventDescriptor eventDescriptor, string payload)
        {
            using (EventProvider eventProvider = new EventProvider(providerMetadata.Id))
            {

                eventProvider.WriteEvent(ref eventDescriptor, payload);

            }
        }
}

this can then be called:

string payload = @"<EventData><Data Name=""BugcheckCode"">210</Data><Data Name=""BugcheckParameter1"">0xffffc080b5744760</Data><Data Name=""BugcheckParameter2"">0x2</Data><Data Name=""BugcheckParameter3"">0x0</Data><Data Name=""BugcheckParameter4"">0xfffff80261641530</Data><Data Name=""SleepInProgress"">0</Data><Data Name=""PowerButtonTimestamp"">0</Data><Data Name=""BootAppStatus"">0</Data><Data Name=""Checkpoint"">0</Data><Data Name=""ConnectedStandbyInProgress"">false</Data><Data Name=""SystemSleepTransitionsToOn"">0</Data><Data Name=""CsEntryScenarioInstanceId"">0</Data><Data Name=""BugcheckInfoFromEFI"">false</Data><Data Name=""CheckpointStatus"">0</Data></EventData>";
EventLogHelper.AddEventToEventLog("Microsoft-Windows-Kernel-Power", 41, 5, payload);
like image 36
Liam Avatar answered Dec 04 '22 04:12

Liam


If you want to add more lines you can simply add an 'Enviroment.NewLine'

  [Extension()]
    [MethodImpl(MethodImplOptions.NoInlining)]
    public void WriteInfo(string info)
    {
        try
        {
            MethodBase callingMethod = new StackFrame(1, true).GetMethod();
            string typeCalling = callingMethod.DeclaringType.FullName;

            string baseStr = "TYPE: {0}{3} METHOD: {1}{3} DETAIL: {2}";
            baseStr = string.Format(baseStr, new object[] {
                                                        callingMethod,
                                                        typeCalling,
                                                        info,
                                                        Environment.NewLine
    });

            EventLog.WriteEntry("entryName", baseStr, EventLogEntryType.Information);
        }
        catch
        {
            Debugger.Break();

        }
    }
like image 25
MirlvsMaximvs Avatar answered Dec 04 '22 04:12

MirlvsMaximvs