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

6

7

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.

Oceania answered 8/10, 2011 at 1:44 Comment(0)
G
6

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>
Grayce answered 16/7, 2015 at 21:13 Comment(0)
R
4

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>
Rousing answered 18/10, 2016 at 10:57 Comment(7)
Trying your suggestion verbatim, instead of message 1,2,3 on separate lines, I get simple "System.Char[]". Where that comes from I don't know. Is there something missing?Fuzz
I copy blocked yours.Fuzz
System.Char[] is a Type, it´s like you are adding an object to sEvent.Add(object) instead of a string.Rousing
using the code above I've been able to get multiple lines on my development environment (PC) but haven't been able to write out multiple lines on my production environment (Server). Is there any setting that might be missing?Rosin
@WouterVanherck but have you managed to write any log on server? If so it should work normally. Sometimes it happens that on server the application don't have permission to create a new Event SourceRousing
@Rousing Thanks for replying. The logger is able to write the string at the first index in sEvent.ToArray() but isn't able to write other lines. Sadly, this is not a permission issue but a rather strange occurrence...Rosin
Now how do you get it to display an attribute like <Data Name="param1">Message 1</Data>.Yasukoyataghan
E
3

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);
Erubescent answered 17/4, 2020 at 8:25 Comment(0)
C
2

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();

        }
    }
Cloistral answered 13/7, 2016 at 12:24 Comment(0)
G
1

I tried using \n \t using EventLog.WriteEntry(). However I was not successful. I found a solution for this problem. We can use logger.WriteEvent()

//Object of eventinstance.

EventInstance eventInstance= new EventInstance(0, 0) {EntryType =       EventLogEntryType.Warning};
//Array of string.Event data node is generated based on the array size.

string [] eventLog = EventLogger.BuildEventLog("EventLogSamples.WriteEventSample2","test");

//Need to specify the source

EventLog log = new EventLog {Source = "source"};
log.WriteEvent(eventInstance, eventLog);

I was able to successfully write multiple eventData as shown below

- <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
- <System>
  <Provider Name="test" /> 

  </System>
- <EventData>
  <Data>EventLogSamples.WriteEventSample2</Data> 
  <Data>test</Data> 
  </EventData>
  </Event>

Please let me know if you find any issues. PK (Prathap Kudupu)

Gunfire answered 13/6, 2013 at 6:18 Comment(3)
Does anyone know how to add attributes to the Data elements?Lipo
I can't find the EventLogger object. What reference do i have to add to get it? I also can't find any reference to it when searching MSDN.Deuced
@Lipo yes I doErubescent
W
-2

Simply put line break characters in your message string to log multiple lines of text.

Witticism answered 8/10, 2011 at 2:53 Comment(5)
I tried to add line break characters in my message string (sEvent) but the event log shows this in the same line. Even the XML view of the event log prints it out this way. <EventData> <Data>EventLogger Test Log 1 \n Line 2 \n Line 3</Data> </EventData>Oceania
Reading the documentation (msdn.microsoft.com/en-us/library/e29k5ebc.aspx): the event viewer treats [the message string] as an insertion string. That means the string can contain escape sequences that go directly to the log's formatter (which is why it comments that IPv6 addresses cannot be logged correctly). Try using %n for line breaks, eg: sEvent = "EventLogger Test Log 1 %n Line 2 %n Line 3";.Witticism
Using "%n" for line breaks gives the same result as for "\n". <EventData> <Data>CpEventLogger Test Log 1 %n Line 2 %n Line 3</Data> </EventData>Oceania
However, using linebreaks this way: sEvent = "CpEventLogger Test Log 1" + Environment.NewLine + "Line 2" + Environment.NewLine + "Line 3 "; causes the message string to show up on different lines in the General view but the XML view still shows up like this: <EventData> <Data>CpEventLogger Test Log 1 Line 2 Line 3</Data> </EventData> Oceania
If the viewer displays the text on multiple lines, then the line breaks really exist in the underlying data, and the issue is just with the way the XML gets formatted, which is outside of your control.Witticism

© 2022 - 2024 — McMap. All rights reserved.