tags:

views:

3907

answers:

6

I recently had a problem during the deployment of a windows service. Four computers did not cause any problems, but on the fifth any attempt to start the service failed due to an exception. The exception stack trace is written to the event log, so I though it should be easy to identify the cause:

protected override void OnStart(string[] args)
{
    EventLog.WriteEntry("Starting service", EventLogEntryType.Information);

    try
    {
        //...
        base.OnStart(args);
    }
    catch (Exception ex)
    {
        EventLog.WriteEntry("Service can not start. Stack trace:" + ex.StackTrace, EventLogEntryType.Error);
        Stop();
        return;
    }

    EventLog.WriteEntry("Service started", EventLogEntryType.Information);           
}

But alas, no information was ever written to the log. I finally traced it to the first log entry being written. It threw an exception because the application event log was full with recent entries, and configured to only overwrite entries older than 7 days.

What are the best practices on writing to the event log, considering that I can not change the configuration of the application event log?

Should I always put EventLog.WriteEntry in a try block, if yes, how should I handle the exception (writing it to the event log is probably a bad idea), should I check on the event log status in my OnStart method, or do you have any better suggestion?

+9  A: 

Use log4net

The advantage of using log4net is that you can check the logging and control it with far more flexibility than you will account for within your code.

If you were logging to the event log, and seeing problems and no event log entries, you could always have switched to a file-appender log and have seen it working... which would have then told you that it was something to do with the event log.

log4net is also defensive, it won't crash your program if it fails to write the log entry. So you wouldn't have seen this happen (so you wouldn't have your logs files, but your program would be running and again you could've specified a second logging method to get log files).

The key bit in the log4net documentation is this:

[log4net] is a best-effort and fail-stop logging system.

By fail-stop, we mean that log4net will not throw unexpected exceptions at run-time potentially causing your application to crash. If for any reason, log4net throws an uncaught exception (except for ArgumentException and ArgumentNullException which may be thrown), please send an email to the [email protected] mailing list. Uncaught exceptions are handled as serious bugs requiring immediate attention.

Moreover, log4net will not revert to System.Console.Out or System.Console.Error when its designated output stream is not opened, is not writable or becomes full. This avoids corrupting an otherwise working program by flooding the user's terminal because logging fails. However, log4net will output a single message to System.Console.Error and System.Diagnostics.Trace indicating that logging can not be performed.

(my emphasis)

For most things, there is a library that does it better than you will. The best thing is to never re-invent, log4net solves logging in .Net and will make your life easier.

Actually, log4net does have the ability to cause apps to crash (compact framework/windows mobile apps at least) - sort of. Use of log4net's UDP appender will crash ActiveSync (which connects devices to the PC). I learned this during a demo where we lost a huge contact.
MusiGenesis
+3  A: 

I think logging exceptions is one of the rare cases where you are better off swallowing the exception. In most cases you don't want your app to fail on this.

But why are you writing your logging code yourself anyway? Use a framework like NLog or Log4Net! These also swallow exceptions like I just said but you can redirect the logging output to a different location (file, messagebox etc.) with just a configuration change. This makes solving problems like this much easier.

Mendelt
Writing to the EventLog is not "writing your logging code yourself".
MusiGenesis
@MusiGenesis: Please explain. To me writing logging specific exception handling is writing code that's already been done better by Log4Net or NLog for example. I see no reason to write another logging framework.
Mendelt
System.Diagnostics.EventLog is a built-in .NET class for writing to the Windows event log, not something they've written themselves.
MusiGenesis
Moreover, the question was "what is the best wasy to write event log entries?", not "what is the best logging framework?"
MusiGenesis
FWIW, the event log does blow.
MusiGenesis
<sarcasm>Why are you writing your own serice anyway, windows comes pre-loaded with heaps of windows services! all you have to do is start one of them up!.. otherwise, just google 'service' and you will see millions, surely one of these does what u want.. dont reinvent the wheel man </sarcasm>
Michael Dausmann
+2  A: 

Look into utilizing the Logging App Block.

The Enterprise Library Logging Application Block simplifies the implementation of common logging functions. Developers can use the Logging Block to write information to a variety of locations:

  • The event log
  • An e-mail message
  • A database
  • A message queue
  • A text file
  • A WMI event
  • Custom locations using application block extension points
gimel
+3  A: 
System.Diagnostics.EventLog log = 
    new System.Diagnostics.EventLog("YourLogNameHere");
log.ModifyOverflowPolicy(
    System.Diagnostics.OverflowAction.OverwriteAsNeeded, 0);

This should fix your overflow problem. The event log is generally extremely reliable, once it's configured correctly. When using the event log, I used to add a quick emergency backup logger that simply wrote to a text file (this takes about 5 minutes to write). It never got called.

MusiGenesis
Unfortunately I am not allowed to change the event log's configuration.
Treb
Can you create an application-specific log and write to that instead of the general "Application" log?
MusiGenesis
While this may work fine for a Windows service, which will usually be running with elevated privileges, desktop applications run by normal users (i.e. non-Administrators), can fail on the call to `ModifyOverflowPolicy` since it requires registry permissions that regular users don't have by default.
Mike Spross
+1  A: 

Can't you just use the default event-log mechanism that the ServiceBase class already provides? If your service doesn't start that will automatically write an entry to the event log stating so (with stacktrace).

Apart from that, and concerning the comments about log4net (or any other best-effort like logging-system), I think it really depends what you are trying to achieve.

In your example using log4net (or the builtin support for eventlogging of ServiceBase) is most likely OK.

However, there are situations where even the fact that an error occurred and that that fact could not be logged somewhere is a problem. For example, assume an authentication or authorization system. If you cannot successfully and reliably log that a, say, password authentication failed because of wrong credentials, you're maybe not allowed to continue (same so BTW if you the password authentication would have been successful).

So, sometimes you need to know when a logging attempt failed and handle that by itself. There are limits to this of course (chicken-egg-problem), and what you do is highly specific to the particular application or scenario.

Christian.K
A: 

Let's take a step back here:

The system event log is there to alert the system administrator that there was a problem with something on the system. You should allow the service start to fail. This will show up in the system error log with a reported source of "Service Control Manager". This means that the sys admin will know about the failure.

Next, if you need to troubleshoot then you should log exceptions to a file on disk at the top level of your program. You should also rethrow them so that the service start fails.

You can then identify any problems in the system event logs and cross reference the time of the failure into your application logs.

Ed Sykes
Given the specific example, why should I let the service start fail?It is common practice to log service start and stop events, but the event log being full is no good reason for the service not to start. The service running is more important, the event logging is just 'nice to have'.
Treb
I don't think i fully understand your problem. Are you logging all exceptions to the event log? Or just uncaught exceptions at the top level before the application crashes?
Ed Sykes
My question was not about exception logging, but about exceptions occurring when writing to the log. In the specific case of an exception during service startup, I am writing a log message 'service could not start', that also contains details about the exception, but the issue at hand is the writing of any log entry.
Treb