This article shows how to log error using asp.net in either a log file or in System event log.
Introduction
This article has been written to provide the solution for error logging problem asked in the Forums (http://www.dotnetfunda.com/forums/thread2884-create-error-log-in-csharp.aspx). In this article, we shall see how to log error in a log file and in the system event log using ASP.NET with C#.
If your website or web application has massive users and you are expecting a lot of logs, it is not suggested to use this mechanism to log error as this is considerably slow in performance and there is less flexibility. In large enterprise applications, it is suggested to use Logging Application Block or other third party components available; one of them is Log4Net, however you should use them very judiciously otherwise this may slow down your application performance.
Ideally, you should log the exceptions or any activity of the user when you are really required to do so as logging error by any mechanism is an additional overhead on the application so be careful while doing that.
In order to show the error logging, I have created a sample application in which I have a default.aspx page, error.aspx page, global.asax page App_Code/ErrorLogging.cs and web.config file.
Functions to Log error in ASP.NET
Lets start and write functions in the App_Code/ErrorLogging.cs file to log error in .log file and event log. In order to use the classes/objects used in these functions, we need to use following namespaces.
using System.Configuration;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using context = System.Web.HttpContext;
Logging error in log file
In order to log error in log file, I have created LogErrorToLogFile function that accepts Exception and user friendly message. Below is the source code for this function.
Get solutions of your .NET problems with video explanations and source code in .NET How to's.
/// <summary>
/// Log the error and return
/// </summary>
/// <param name="ee">The ee.</param>
/// <param name="userFriendlyError">The user friendly error.</param>
/// <returns></returns>
public static string LogErrorToLogFile(Exception ee, string userFriendlyError)
{
try
{
string path = context.Current.Server.MapPath("~/ErrorLogging/");
// check if directory exists
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
path = path + DateTime.Today.ToString("dd-MMM-yy") + ".log";
// check if file exist
if (!File.Exists(path))
{
File.Create(path).Dispose();
}
// log the error now
using (StreamWriter writer = File.AppendText(path))
{
string error = "\r\nLog written at : " + DateTime.Now.ToString() +
"\r\nError occured on page : " + context.Current.Request.Url.ToString() +
"\r\n\r\nHere is the actual error :\n" + ee.ToString();
writer.WriteLine(error);
writer.WriteLine("==========================================");
writer.Flush();
writer.Close();
}
return userFriendlyError;
}
catch
{
throw;
}
}
In the above function, first I have checked whether the Directory where I want to create my log file exists, if not create it. Then I have checked the log file in which I want to write the error exists, if not then create it. Here, I have used a single file for a specific day. Once my file is ready, I am writing the DateTime of the log, Page where the error occured, and the actual error that has occurred. Notice that I have used ee.ToString() (Exception object) instead of writing ee.Message as it gives only the message of the error but doesn't give why, where and what caused that exception.
At the end, I am returning the friendly message that was passed into this function. Below is the picture of my sample error log file.
Picture - 1
Logging error in Event Log
In order to log error in System Event Log, I have created LogErrorInSystemEvent function that again accepts the same parameters that is accepted by the above function.
/// <summary>
/// Logs the error in system event.
/// </summary>
/// <param name="ee">The ee.</param>
/// <param name="userFriendlyError">The user friendly error.</param>
/// <returns></returns>
public static string LogErrorInSystemEvent(Exception ee, string userFriendlyError)
{
string eventLog = "SampleError";
string eventSource = "ErrorLoggingSampleApp";
// check if source exists
if (!EventLog.SourceExists(eventSource))
{
System.Diagnostics.EventLog.CreateEventSource(eventSource, eventLog);
}
// create the instance of the EventLog and log the error
using (EventLog myLog = new EventLog(eventLog))
{
myLog.Source = eventSource;
string error = "\r\nLog written at : " + DateTime.Now.ToString() +
"\r\nError occured on page : " + context.Current.Request.Url.ToString() +
"\r\n\nHere is the actual error :\n" + ee.ToString();
myLog.WriteEntry(error, EventLogEntryType.Error);
}
return userFriendlyError;
}
In above function, first I have checked if the Event Source under which I want to log the error exists, if not then create by passing the event source and event log name parameters in CreateEventSource method of EventLog class.
Note that you may ran into following error while manipulating the event log name and event source name in the CreateEventSource method.
Exception Details: System.ArgumentException: The source 'ErrorLoggingSampleApp1' is not registered in log 'Sample1Error1'. (It is registered in log 'Sample1Error'.) " 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.
and
Exception Details: System.ArgumentException: The source 'ErrorLoggingSampleApp1' is not registered in log 'Sample1Error1'. (It is registered in log 'Sample1Error'.) " 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.
The cause of above errors are already written in the error itself however just to summarize; in order to log error in the Event Log you must have created the Event source using a new event log name. Now you will be able to log error only if you have specified both parameters correctly to the EventLog object. Any mismatch will cause any of the above two errors. For example, if I have created a event source with "SampleError" and "ErrorLoggingUsingSampleApp" as Event Log and Event Source name respectively, I will not be able to log error with "SampleError1" Event Log in the "ErrorLoggingUsingSampleApp" event source or vice-versa.
Little tweaking now
In order to accomodate both types of error logging in my sample application, I have created an appSettings in my web.config file.
<appSettings>
<add key="ErrorLogType" value="2"/>
</appSettings>
Here, I shall assume that if the value of ErrorLogType is 1 then I have to log the error into log file otherwise in the System Event Log.
So for that I have created another function in the App_Data/ErrorLogging.cs file called LogError and here is the code.
/// <summary>
/// Logs the error.
/// </summary>
/// <param name="ee">The ee.</param>
/// <param name="userFriendlyError">The user friendly error.</param>
/// <returns></returns>
public static string LogError(Exception ee, string userFriendlyError)
{
string logType = ConfigurationManager.AppSettings["ErrorLogType"].ToString();
if (logType.Equals("1"))
{
return LogErrorToLogFile(ee, userFriendlyError);
}
else
{
return LogErrorInSystemEvent(ee, userFriendlyError);
}
}
It is preety straight forward, I have retrieved the value of ErrorLogType from the web.config appSettings and if it is "1" then have called the LogErrorToLogFile function else LogErrorInSystemEvent function.
Testing the application
Now in order to test the functions, write following code snippet in your Page_Load event of the default.aspx page.
protected void Page_Load(object sender, EventArgs e)
{
//string s = "ram";
//int j = int.Parse(s);
try
{
throw new Exception("Error occured");
}
catch (Exception ee)
{
lblMessage.Text = ErrorLogging.LogError(ee, "An error occured.");
}
}
As soon as the page runs, an error will occur and it will log error in the event log as I have specified appSettings value of ErrorLogType in my web.config as "2".
Handling error globally in your application
In order to handle any error globally in the asp.net application, we can mention the error logging code into Application_Error event of the global.asax page, here is the code snippet
void Application_Error(object sender, EventArgs e)
{
// find out the last error
Exception ee = Server.GetLastError().GetBaseException();
// log the error now
ErrorLogging.LogError(ee, "");
}
In the above code, first I have retrieved the last error occured in the application using Server.GetLastError() method and then called my LogError function, I have written into my App_Code/ErrorLogging.cs file.
In order to improve the user experience and avoid any security flaw by exposing our application errors, we can redirect the end user to a specified generic error page. To do that we need to specify customError settings in our web.config file and below is the setting.
<customErrors mode="On" redirectMode="ResponseRewrite" defaultRedirect="~/ErrorLogging/error.aspx" />
Notice the setting redirectMode that I have specified in bold, this is to avoid the security vulnerablity exposed recently in ASP.NET, read more about it here and here.
Sending email when error occured
Along with logging error, we can also send email to the administrator of the application notifying about the error. In order to do that we can call below function by passing necessary parameters. The way of sending email from asp.net slightly differrs on different hosting providers, so you little tweak below function accordingly, you can also use this article if this works for you.
public static bool SendEmail(string toAddress, string ccAddress, string bccAddress, string subject, string body, MailPriority priority, bool isHtml)
{
try
{
using (SmtpClient smtpClient = new SmtpClient())
{
using (MailMessage message = new MailMessage())
{
MailAddress fromAddress = new MailAddress("yourmail@domain.com", "Your name");
// You can specify the host name or ipaddress of your server
smtpClient.Host = "mail.yourdomain.com"; //you can also specify mail server IP address here
//Default port will be 25
smtpClient.Port = 25;
NetworkCredential info = new NetworkCredential("yourmail@domain.com", "your password");
smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;
smtpClient.UseDefaultCredentials = false;
smtpClient.Credentials = info;
//From address will be given as a MailAddress Object
message.From = fromAddress;
message.Priority = priority;
// To address collection of MailAddress
message.To.Add(toAddress);
message.Subject = subject;
// CC and BCC optional
if (ccAddress.Length > 0)
{
message.CC.Add(ccAddress);
}
if (bccAddress.Length > 0)
{
message.Bcc.Add(bccAddress);
}
//Body can be Html or text format
//Specify true if it is html message
message.IsBodyHtml = isHtml;
// Message body content
message.Body = body;
// Send SMTP mail
smtpClient.Send(message);
}
}
return true;
}
catch (Exception ee)
{
Logger.LogError(ee, "Error while sending email to " + toAddress);
throw;
}
}
Source code
The entire source code of my sample application is attached with this email. You will need to keep ErrorLoggin.cs file in the App_Code folder and web.config file in the root folder. You must have write permission in the folder where you want to write your error log file, in my case it is ErrorLoggin folder.
Conclusion
Hope this article would be useful for all the readers. Please feel free to comment about this article and vote if you think it is useful. Keep reading and sharing your knowledge, the more you share the more you learn !
Thank you.