I've been using the following basic code which I took from a website to write messages to the Windows Event Log using the EventLog class from System.Diagnostics
class Program
{
static void Main(string[] args)
{
WriteEventLogEntry("This is an entry in the event log");
}
private static void WriteEventLogEntry(string message)
{
// Create an instance of EventLog
System.Diagnostics.EventLog eventLog = new System.Diagnostics.EventLog();
// Check if the event source exists. If not create it.
if (!System.Diagnostics.EventLog.SourceExists("TestApplication"))
{
System.Diagnostics.EventLog.CreateEventSource("TestApplication", "Application");
}
// Set the source name for writing log entries.
eventLog.Source = "TestApplicationNotExisting";
// Create an event ID to add to the event log
int eventID = 8;
// Write an entry to the event log.
eventLog.WriteEntry(message,
System.Diagnostics.EventLogEntryType.Error,
eventID);
// Close the Event Log
eventLog.Close();
}
}
I've tweaked the code above so that the Source that is being selected is one that I have not previously created using the CreateEventSource method. I expected this to throw an exception but instead it works perfectly well and I have a message in the Event Log from source "TestApplicationNotExisting".
Why is this not throwing an exception? if I can select sources on the fly then what's the point of the CreateEventSource method?
Related
In a WinForms application, an exception is occurring within a method that is run when a BackgroundWorker.DoWork event is fired.
System.ComponentModel.BackgroundWorker worker = new System.ComponentModel.BackgroundWorker();
worker.DoWork += import_begin;
System.Objects arguments = new System.Object[] {filename, why};
worker.RunWorkerAsync(arguments);
private void import_begin(System.Object sender, System.ComponentModel.DoWorkEventArgs args)
{
// unpack the arguments
System.String filename = (System.String)arguments[0];
// exception is occurring here
Controller.Excel excel = new Controller.Excel(filename);
}
I have set breakpoints to pin down where the exception was thrown, and it was in the line of code as commented above. Even after handling the exception, there is a dialog box that shows up:
"Exception has been thrown by the target of an invocation".
Is it possible to prevent this dialog box?
By the way, the exception is of type InvalidDataException, due to an invalid file type attempted to be imported.
Edit: partial Controller.Excel code:
class Excel
{
protected OfficeOpenXml.ExcelPackage excel;
protected const int HEADER_ROW_OFFSET = 7;
System.Globalization.CultureInfo provider;
// ctor
public Excel(System.String filename)
{
excel = new OfficeOpenXml.ExcelPackage(new System.IO.FileInfo(filename));
excel.Compatibility.IsWorksheets1Based = false;
provider = System.Globalization.CultureInfo.InvariantCulture;
}
}
OP:
it is using the standard file dialog form. It is intended for the user to open an .xlsx file, and this exception occurs whenever they try to open any other file type
I sounds as though you just want to handle the condition gracefully when the user somehow picks a file which isn't an Excel file and/or corrupt.
Change your code to something like:
private void import_begin(System.Object sender, System.ComponentModel.DoWorkEventArgs args)
{
// unpack the arguments
System.String filename = (System.String)arguments[0];
// you probably should inspect the file extension in `filename` to see if it
// is at least .xls or .xlsx prior to using Controller
try
{
Controller.Excel excel = new Controller.Excel(filename);
...
}
catch (InvalidDataException ex)
{
// gracefully handle the error
...
}
catch (Exception ex)
{
// eat, don't want thread to unwind
}
}
Now if they pick any other file type or the file is a corrupted Excel file, the catch handler above will be invoked where you can handle the situation gracefully.
Normally you shouldn't update the UI from a worker but MessageBox has it's own message pump.
Tip
To keep it neat, you might want to inspect the file's extension prior to running the BackgroundWorker. It's a quick check for a quick win and keeps all UI-related activities in the main thread and not a child thread where things become more complex.
I want to add logging of exceptions to my Windows Store App. Based on an idea from here, I've started off with this code in App.xaml.cs:
sealed partial class App : Application
{
private LoggingChannel channel;
private LoggingSession session;
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
channel = new LoggingChannel("PlatypiChannel");
session = new LoggingSession("PlatypiSession");
session.AddLoggingChannel(channel, LoggingLevel.Error);
UnhandledException += Application_UnhandledException;
}
async private void Application_UnhandledException(object sender, UnhandledExceptionEventArgs ex)
{
ex.Handled = true;
String exceptionCornucopia = String.Format("Message0 == {0}; Message1 == {1}; HResult == {2}; Inner Ex == {3}; StackTrace == {4}", ex.Message, ex.Exception.Message, ex.Exception.HResult, ex.Exception.InnerException, ex.Exception.StackTrace);
channel.LogMessage(exceptionCornucopia, LoggingLevel.Error);
// not seeing how this saves the channel's logged messages...???
StorageFile logFile = await session.SaveToFileAsync(ApplicationData.Current.LocalFolder, "CrashLog");
}
As the comment indicates, it seems to me the last line simply saves a file named "CrashLog" to the LocalFolder. But how do the LogMessages get into that file? There is obviously a key piece missing here.
I know that this question has been open for a long time, but I just want to provide an answer for anyone else finding this.
The secret here is that the LogMessages are all written into the LoggingChannel, which itself has previously been registered with the LoggingSession:
session.AddLoggingChannel(channel, LoggingLevel.Error);
When the session is then saved to a file, it obviously knows about the associated channels and where to search for pending log messages.
I would like to know if how can we catch the event in C# when a system event log is created. Also I would like to know if how can I get only ERROR LOGS from Windows event logs using C#.
I have the following code but it just returns me all logs. I just need ERROR logs:
System.Diagnostics.EventLog eventLog1 = new System.Diagnostics.EventLog("Application", Environment.MachineName);
int i = 0;
foreach (System.Diagnostics.EventLogEntry entry in eventLog1.Entries)
{
Label1.Text += "Log is : " + entry.Message + Environment.NewLine;
}
You can use CreateEventSource static method of EventLog class to create event log like
EventLog.CreateEventSource("MyApp","Application");
EventLog class present in System.Diagnostics namespace.
You can use WriteEntry() method to write to the event log. EventLogEntryType enum can be used to specify the type of event you want to log. An example below
EventLog.WriteEntry(sSource, sEvent, EventLogEntryType.Warning, 234);
See How to write to an event log by using Visual C#
if you are looking for reading only ERROR level log then you can use the below code block. You just need to check EntryType of the eventlog entry and then print/display accordingly.
static void Main(string[] args)
{
EventLog el = new EventLog("Application", "MY-PC");
foreach (EventLogEntry entry in el.Entries)
{
if (entry.EntryType == EventLogEntryType.Error)
{
Console.WriteLine(entry.Message);
}
}
}
It is simple, I want to write something to event log.
protected override void OnStop()
{
// TODO: Add code here to perform any tear-down necessary to stop your service.
if (!System.Diagnostics.EventLog.SourceExists("IvrService"))
{
System.Diagnostics.EventLog.CreateEventSource(
"IvrService", "IvrServiceLog");
}
EventLog eventLog1 = new System.Diagnostics.EventLog();
eventLog1.Source = "IvrService";
eventLog1.Log = "IvrServiceLog";
try
{
eventLog1.WriteEntry("Successfully "+State.Stopped.ToString());
IvrApplication.StopImmediate();
}
catch (Exception ex)
{
// eventLog1.WriteEntry(ex.Message);
}
}
The exception is:
Failed to stop service. System.ArgumentException: The source 'IvrService' is not registered in log 'IvrServiceLog'. (It is registered in log 'Application'.) " The Source and Log properties must be matched, or you may set Log to the empty string, and it will automatically be matched to the Source property.
at System.Diagnostics.EventLogInternal.VerifyAndCreateSource(String sourceName, String currentMachineName)
at System.Diagnostics.EventLogInternal.WriteEntry(String message, EventLogEntryType type, Int32 eventID, Int16 category, Byte[] rawData)
at System.Diagnostics.EventLog.WriteEntry(String message)
The error message is telling you exactly what is wrong. You have the Event Source IvrService registered with the Application Log, not the IvrServiceLog. The System.Diagnostics.EventLog.SourceExists verifies that the source exists, but not for a particular log.
My guess is that you originally registered this with the Application log and then later changed it to write to the IvrServiceLog.
To clean up your development machine, you could simply run the following and then you code should work going forward.
System.Diagnostics.EventLog.DeleteEventSource("IvrService");
I am developing an app to capture event logs (security) from multiple Windows systems. I have a handler to EntryWritten. I am able to map most fields from the Event Viewer to the EntryWrittenEventArgs entry in .net. However, I cannot seem to find the mappings for the Level, OpCode and Task Category fields which show up in Event Viewer. Any ideas on how I get this in vb.net or c#? Thanks
The EventLog class in the System.Diagnostics namespace does not contain fields for Level, OpCode or Task. There is, however, the EventRecord class in the System.Diagnostics.Eventing.Reader namespace which is capable of returning those fields. Note that this namespace is mainly used for retrieving event logs from a remote machine. Even though you could use it to get logs on the local machine as well, it opens a local pipe to the system, which makes it slower than the EventLog class. If you really need to access those fields though, this is how this class is generally used:
private void LoadEventLogs()
{
List<EventRecord> eventLogs = new List<EventRecord>();
EventLogSession session = new EventLogSession();
foreach (string logName in session.GetLogNames())
{
EventLogQuery query = new EventLogQuery(logName, PathType.LogName);
query.TolerateQueryErrors = true;
query.Session = session;
EventLogWatcher logWatcher = new EventLogWatcher(query);
logWatcher.EventRecordWritten +=
new EventHandler<EventRecordWrittenEventArgs>(LogWatcher_EventRecordWritten);
try
{
logWatcher.Enabled = true;
}
catch (EventLogException) { }
// This is how you'd read the logs
//using (EventLogReader reader = new EventLogReader(query))
//{
// for (EventRecord eventInstance = reader.ReadEvent(); eventInstance != null; eventInstance = reader.ReadEvent())
// {
// eventLogs.Add(eventInstance);
// }
//}
}
}
And the LogWatcher_EventRecordWritten event handler:
private void LogWatcher_EventRecordWritten(object sender, EventRecordWrittenEventArgs e)
{
var level = e.EventRecord.Level;
var task = e.EventRecord.TaskDisplayName;
var opCode = e.EventRecord.OpcodeDisplayName;
// Other properties
}
Note that I wrapped the logWatcher.Enabled = true; statement in a try-catch block, because not all sources allow entry-written listeners (security should work fine). The commented-out section shows you an example of reading all the logs, if you need it.