Email Trace Listener Only Sends E-mail on Application End

Topics: Logging Application Block
Sep 14, 2007 at 3:36 PM
Hello all:

I am using the Logging Application Block to write errors and information to log files as well as send e-mail via a e-mail trace listener. When I call the Logger.Write() method, the entries are immediately logged to the text file via the RollingTraceListener however the also associated e-mail is not sent until the application (which is a service) goes through its On Stop Event. I need the e-mails to be sent out immediately when I call the Logger.Write method from the static class Program LogInformation message method.

Here is my code used to write an "Information" and Handle Exceptions it is contained in the Program.cs file's static class Program.


static class Program {

/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main (string[] arg) {
try {
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new EmsToVmsDebug(), new EmsToVmsService() };
ServiceBase.Run(ServicesToRun);
}
catch (Exception ex) {
HandleException(ex, "Send Email");
}
}

internal static void HandleException (Exception e) {
HandleException(e, "Exception Policy");
}

internal static void HandleException (Exception e, string exceptionPolicyName) {
ExceptionPolicy.HandleException(e, exceptionPolicyName);
}

internal static void LogInformationMessage (string messageText) {
LogInformationMessage(messageText, String.Empty);
}

internal static void LogInformationMessage (string messageText, string category) {
LogEntry logEntry = new LogEntry();

if (category != string.Empty)
logEntry.Categories.Add(category);

logEntry.Message = messageText;
logEntry.TimeStamp = DateTime.Now;

Logger.Write(logEntry);
}
}
Sep 18, 2007 at 1:51 PM
Any ideas anyone?
Sep 18, 2007 at 8:03 PM
Hi Justin,

I'm confused with your code. First, you're catching errors on your main program, but I presume you are spawning a new thread or registering a callback on some external event to actually do the work and exceptions that occur there (which are likely the ones you're interested in) will not be handled in your main program. Second, you're probably relying on a logging exception handler to do your logging, since the LogInformationMessage methods are not being invoked in the code you show here.
Can you confirm this understanding and provide additional details about the exceptions you're interested in logging?

I wrote a short repro service that would log events as emails from a worker thread using the logging block, and traced it up to the point where the .NET SmtpClient was being invoked. I didn't have a test SMTP server handy to verify that the messages were being sent but I did get a connection exception when the client attempted to send the message, so it doesn't seem likely that the messages are being buffered.

Fernando
Sep 20, 2007 at 2:22 PM
Fernando,

Thanks for your reply. I have the overloaded HandleException and LogInformationMessage methods in my static class Program so that I can use those methods through out the program, calling the HandleException method in my catch blocks from my worker threads. I also call the LogInformationMessage to log items to a different log file. Based on the category an e-mail trace listener is attached to the category of "Ems Data Status". That way from my EmsToVmsService class, I can send e-mails.

Here is an example of using the LogInformationMessage method in the OnStart method in the EmsToVmsService class:

protected override void OnStart (string[] args) {
mContinueProcessing = true;

TimerCallback callback = new TimerCallback(HandleTimer);
mTimer = new Timer(callback, null, System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
int interval = Config.CheckInterval * 1000;
mTimer.Change(0, interval);

Program.LogInformationMessage("EmsToVms Started");
}

Here is an example of using the HandleException method in the HandleTimer method called by the TimerCallback:

private void HandleTimer (Object state) {
try {

if (!mContinueProcessing || mCurrentlyProcessing)
return;

mCurrentlyProcessing = true;
Process();
}
catch (Exception ex) {
Program.HandleException(ex, "Send Email");
}
finally {
mCurrentlyProcessing = false;
}
}

Finnally, here is my Process method:

private void Process () {
MaxTimeStampUtc = FetchEmsReadingsMaxTimeStampUtc();

if (MaxTimeStampUtc > LastTimeStampUtc) {
DataSet EmsReadings = FetchEmsReadings(MaxTimeStampUtc);
if (PgnValidation.DataSetHasData(EmsReadings)) {
FileStream outputFS = null;
StreamWriter outputSW = null;
try {
outputFS = new FileStream(Config.OutputFilePath, FileMode.Create, FileAccess.ReadWrite, FileShare.None);
outputSW = new StreamWriter(outputFS);
Program.LogInformationMessage("Created output file.");

WriteEmsReadingsToOutputFile(ref EmsReadings, ref outputSW);

if (Config.ManualInputFileEnabled) {
try {
//zzzjds remove demo code
using (StreamWriter sw = new StreamWriter(Config.ManualInputFilePath)) {
// Add some text to the file.
sw.Write("This is the ");
sw.WriteLine("header for the file.");
sw.WriteLine("-------------------");
// Arbitrary objects can also be written to the file.
sw.Write("The date is: ");
sw.WriteLine(DateTime.Now);
}

if (File.Exists(Config.ManualInputFilePath)) {
outputSW.Write(File.ReadAllText(Config.ManualInputFilePath));
Program.LogInformationMessage(String.Format("Sucuessfully merged manual file at {0}.", Config.ManualInputFilePath));

if (Config.ManualInputFileArchive)
File.Move(Config.ManualInputFilePath, Path.ChangeExtension(Config.ManualInputFilePath, "." + DateTime.Now.ToString("MMddyyyy HHmmss") + ".txt"));
else
File.Delete(Config.ManualInputFilePath);
}
else
Program.LogInformationMessage(String.Format("Manual file was not found to merge at {0}.", Config.ManualInputFilePath));

}
catch (Exception ex) {
Program.HandleException(ex);
}
finally {
//clean up
}
}

LastTimeStampUtc = MaxTimeStampUtc;

PurgeEmsReadings();
}
finally {
if (EmsReadings != null)
EmsReadings.Dispose();
if (outputSW != null) {
outputSW.Flush();
outputSW.Close();
Program.LogInformationMessage("Closed output file.");
outputSW.Dispose();
}
if (outputFS != null) {
//outputFS.Flush(); //this is not needed but here for reference b/c stream writer.flush flushes filestream.
outputFS.Close();
outputFS.Dispose();
}
}

if (Config.CopyOutputFile) {
try {
//Make effort to copy file, if fails, keep going.
File.Copy(Config.OutputFilePath, Config.CopyOutputFilePath, true);
Program.LogInformationMessage(String.Format("File {0} was copied to {1}.", Config.OutputFilePath, Config.CopyOutputFilePath));
}
catch (Exception ex) {
Program.HandleException(ex);
}
}
}
}
}

Please let me know your thoughts, I know that the LogInformationMessage is writing to the log file, but when I call the LogInformationMessage(message, "Ems Data Status") the email is not sent until I stop the services.