Log files and memory logs in detail

Logging is essential for trouble-shooting, activity tracking, and audit. MailBee.NET provides extensive (and extensible!) file and memory logging facilities available to your applications.

You can adjust a lot of parameters, control how the log expands and truncate the oldest part, control which messages are added to the log and which are not, add your own messages or redirect the log output to another place like database or Windows Event Log.


Logger settings and options

All e-mail components of MailBee.NET family, including Smtp component, support Log property (e.g. Smtp.Log). This property provides access to an instance of Logger class which controls logging. That's how you can enable logging into a file and clear this file:

Smtp mailer = new Smtp();

mailer.Log.Enabled = true;
mailer.Log.Filename = @"C:\Temp\log.txt";
mailer.Log.Clear();
Dim mailer As Smtp = New Smtp()

mailer.Log.Enabled = True
mailer.Log.Filename = "C:\Temp\log.txt"
mailer.Log.Clear()

We assume mailer is an Smtp object instance. In addition to that, for all the samples in this guide we assume MailBee, MailBee.Mime, and MailBee.SmtpMail namespaces are imported and the license key is set. See Import namespaces and set license key topic for details.

Note that your application must have permission to write into the specified location (this especially concerns ASP.NET web applications which are typically run under the context of a user which does not have much permissions to access the filesystem).

If you want to have file logging in place but don't want to have your application crash in case of a logging error (such as a lack of permission), you can tell MailBee.NET to disable logging in case if logging error occurs:

mailer.Log.DisableOnException = true;
mailer.Log.DisableOnException = True

More elegant solution in case if file logging is not allowed would be using other types of logging, such as memory log:

mailer.Log.MemoryLog = true;
mailer.Log.MemoryLog = True

To see memory logging in place, check OAuth 2.0 ASP.NET projects installed by MailBee.NET Objects setup in My Documents\MailBee.NET Objects\Samples\ASP.NET folder. C# project is cs_2013_oauth_samples and VB version is vb_2013_oauth_samples.

To read the current contents of the memory log, use Logger.GetMemoryLog method:

Console.WriteLine(mailer.Log.GetMemoryLog());
Console.WriteLine(mailer.Log.GetMemoryLog())

It's up to you when to display the memory log to the user (or save it somewhere like database). For instance, you can do this at the moment when an exception occurs.

Logger.Clear method can be used to clear the memory log as well as the file log. However, if in case of a file log you usually use this method to tidy up the file so that the log contents of previous sessions of your application would not mess with the new data, in case of a memory log you'll call this method multiple times during a single session of your application to avoid unnecessary growth of the data.

For instance, you may consider clearing the memory log each time your application passes certain key point and the previous log data becomes no longer important or relevant.

MailBee.NET also provides an automatic way to keep the log small (this concerns both file and memory logs). Set Logger.MaxSize property for that. The oldest half of the log history will be automatically removed from the log each time its size is going to exceed the maximum size limit you set. And you'll always have the most recent information there (because the 2nd half of the log with newer items remains).

Another way to keep the log file relatively small is to use Logger.OldFilename property. This lets you still use Logger.MaxSize but instead of deleting the old half of the data the existing log is just renamed. Thus, all the history remains but it becomes split into smaller files.

Logger.KeepLogFileOpen property allows for better performance of file logging. By default, MailBee.NET opens and closes the log file each time a log record is created. This allows for concurrent access to the file, the file is available to other applications, and so on. But in case of frequent write operations, it's slower. Set Logger.KeepLogFileOpen property to true to tell MailBee.NET not to close the log file on each writing.

In the end, when the application is about to be closed (or you just no longer need the log), you should set Logger.KeepLogFileOpen back to false to close the file. You'll also need to disable logging with Logger.Enabled set to false in case if you know that from the current point your application may still perform some actions which could write into the log.

Logger.Format property allows you to tune the format of each log record.

For instance, if you're using Smtp component in multi-threaded mode, adding the current thread and context information makes it easier to read this log then. This code enables the context information in the log by settingLogFormatOptions.AddContextInfo flag:

mailer.Log.Format = LogFormatOptions.AddContextInfo;
mailer.Log.Format = LogFormatOptions.AddContextInfo

Note that MailBee.NET properly implements the concurrent access of multiple threads to the same log file (in case if all these threads were spawned by the same Smtp class instance). In case if you have multiple instances of Smtp class working simultaneously, you should use Logger.SyncRoot property to synchronize the access. The next topic explains this.

You can also add your own log messages into the log using Logger.WriteLine method. If you need more control (such as avoid having a particular message to be added into the log), use Smtp.LogNewEntry event. To learn more, refer to LogNewEntry event topic.

If the log may contain international characters in a codepage different from the computer's default codepage, you can use Logger.FileEncoding property to set the codepage of the log file.

Logger.HidePasswords property lets you control whether password should be displayed as-is (not secure!) or replaced with asterisks. By default, passwords are not displayed for security reasons.

Log messages (along with error messages) can be customized. For instance, if you want to translate them into your local language or otherwise adjust any or all of them, you can use Resources class for that.


Synchronize access to log file of multiple instances of Smtp class

In case if you're using multiple instances of Smtp class and they all need to write into the same log file, create an object and set Smtp.Log.SyncRoot property of every Smtp instance to this object:

// Create a synchronization object. It can be of any type.
object syncObject = new object();

Smtp mailer1 = new Smtp();

// mailer1 writes into C:\Temp\log.txt.
mailer1.Log.Enabled = true;
mailer1.Log.Filename = "C:\\Temp\\log.txt";

mailer1.Log.SyncRoot = syncObject;

// mailer2 writes into C:\Temp\log.txt either.
Smtp mailer2 = new Smtp();

mailer2.Log.Enabled = true;
mailer2.Log.Filename = "C:\\Temp\\log.txt";

mailer2.Log.SyncRoot = syncObject;
' Create a synchronization object. It can be of any type.
Dim syncObject As New Object()

Dim mailer1 As New Smtp()

' mailer1 writes into C:\Temp\log.txt.
mailer1.Log.Enabled = True
mailer1.Log.Filename = "C:\Temp\log.txt"

mailer1.Log.SyncRoot = syncObject

' mailer2 writes into C:\Temp\log.txt either.
Dim mailer2 As New Smtp()

mailer2.Log.Enabled = True
mailer2.Log.Filename = "C:\Temp\log.txt"

mailer2.Log.SyncRoot = syncObject

The instances can be of different classes (not only two Smtp instances, like in the sample above, but Smtp and Imap and Pop3 as well). And you can have any number of instances being synchronized.

However, in case if you are willing to use multiple instances of Smtp class to send e-mails concurrently, consider using Smtp.AddJob(string, string, EmailAddressCollection) method and its overloads to feed Smtp component with multiple e-mails to be sent, and set Smtp.MaxThreadCount property to enable multi-threading. See Send bulk e-mail through two SMTP relay servers for increased throughput topic for details.


LogNewEntry event

Smtp component raises Smtp.LogNewEntry event each time a new log record is about to be created and saved into the file or memory log.

This event gives you full control over the logging process. You can:

And you can log your own messages with Logger.WriteLine method. Please note that messages added with that method do not cause Smtp.LogNewEntry event to get raised. Thus, it's safe to call Logger.WriteLine even in Smtp.LogNewEntry event handler, you won't get endless recursion.

This console sample redirects all the logging output into Windows Event Log (which you can then examine with Event Viewer tool):

using System;
using System.Diagnostics;
using MailBee;
using MailBee.Mime;
using MailBee.SmtpMail;

class Sample
{
    static void OnLogNewEntry(object sender, LogNewEntryEventArgs e)
    {
        // Suppress adding this log entry into the log file.
        e.NewEntry.AddThisEntry = false;

        // The default log entry type.
        EventLogEntryType entryType = EventLogEntryType.Information;

        // Check if the entry is an error or warning.
        if (e.NewEntry.MessageType == LogMessageType.Info)
        {
            if (e.NewEntry.MessageText.StartsWith("Error"))
            {
                entryType = EventLogEntryType.Error;
            }
            else if (e.NewEntry.MessageText.StartsWith("Warning"))
            {
                entryType = EventLogEntryType.Warning;
            }
        }

        // Save the entry in Windows Event Log.
        EventLog.WriteEntry("Application", e.NewEntry.MessageText, entryType);
    }

    static void Main(string[] args)
    {
        Smtp mailer = new Smtp();

        // Attach event handler and enable logging.
        mailer.LogNewEntry += new LogNewEntryEventHandler(OnLogNewEntry);
        mailer.Log.Enabled = true;

        // To demonstrate Error entry in Event Log, use wrong password.
        mailer.SmtpServers.Add("mail.provider.com", "joe", "bad password");

        // Send a simple e-mail.
        mailer.Message.From = new EmailAddress("joe@here.com");
        mailer.Message.To.Add("bill@there.com");
        mailer.Message.Subject = "Test message";
        mailer.Send();
    }
}
Imports System
Imports System.Diagnostics
Imports MailBee
Imports MailBee.Mime
Imports MailBee.SmtpMail

Module Module1
    Sub OnLogNewEntry(ByVal sender As Object, ByVal e As LogNewEntryEventArgs)
        ' Suppress adding this log entry into the log file.
        e.NewEntry.AddThisEntry = False

        ' The default log entry type.
        Dim entryType As EventLogEntryType = EventLogEntryType.Information

        ' Check if the entry is an error or warning.
        If e.NewEntry.MessageType = LogMessageType.Info Then
            If e.NewEntry.MessageText.StartsWith("Error") Then
                entryType = EventLogEntryType.Error
            Else
                If e.NewEntry.MessageText.StartsWith("Warning") Then
                    entryType = EventLogEntryType.Warning
                End If
            End If
        End If

        ' Save the entry in Windows Event Log.
        EventLog.WriteEntry("Application", e.NewEntry.MessageText, entryType)
    End Sub

    Sub Main()
        Dim mailer As New Smtp()

        ' Attach event handler and enable logging.
        AddHandler mailer.LogNewEntry, AddressOf OnLogNewEntry
        mailer.Log.Enabled = True

        ' To demonstrate Error entry in Event Log, use wrong password.
        mailer.SmtpServers.Add("mail.provider.com", "joe", "bad password")

        ' Send a simple e-mail.
        mailer.Message.From = New EmailAddress("joe@here.com")
        mailer.Message.To.Add("bill@there.com")
        mailer.Message.Subject = "Test message"
        mailer.Send()
    End Sub
End Module

Of course, real-world applications should not write so many records into Windows Event Log (you should log only error messages or very important events).

Note that each record you added in Windows Event Log might have a warning like "The description for Event ID ( 0 ) in Source ( Application ) cannot be found. The local computer may not have the necessary registry information or message DLL files to display messages from a remote computer."

To avoid this, you'll need to prepare an event source before writing into Windows Event Log (such as with EventLog.CreateEventSource method).


Send feedback to AfterLogic

Copyright © 2006-2023 AfterLogic Corporation. All rights reserved.