Introduction
This article provides a brief introduction to the use of Caller Information as a means for creating an error logging utility class for your C# 5.0/.NET 4.5 applications. Caller Information is a new language feature introduced with the .NET 4.5 update and is made available through the System.Runtime.CompilerServices namespace.
Caller Information Attributes
There are three attributes available for use:
- CallerMemberName
- CallerFilePath
- CallerLineNumber
It is important to note that the caller line number attribute points to the line where the method is called and not to the line where the exception actually occurred. In that respect the stack trace from an exception provides better information than the caller line number attribute when used to log exceptions.
Error Logging with Caller Information
Attached with the download is a simple application that implements an error logging class built using the caller information attributes. The application is a Windows Forms application with a single form and an error logging class. The application does not do much of anything aside from throwing as many errors as you'd like to record to a log file.
Having a look at the Solution Explorer shows that of note we have the error logging class (ErrorLogger.cs), the one and only form (Form1.cs), and the app.config file.

Figure 1 - Solution Explorer
We will open the ErrorLogger class first and have a look. The first thing worthy of note is that we are referencing the System.Runtime.CompilerServices library that gives us access to the Caller Attributes.
The ErrorLogger class is defined as a static class so we can write directly to the error log without creating an instance of the class. It contains only one method, WriteToErrorLog that we are really only going to pass two arguments into; the other arguments are defined as optional with a default value given. We don't ever actually pass anything for these arguments; the values will be supplied when we call the method at runtime.
As for the arguments, in the demo application we pass in the message portion of the captured exception along with the stack trace for the exception. The rest of the values will include the caller member name that tells us the method called when the exception occurred, the caller file path that tells us the path to the file containing the method, and the caller line number. The caller line number points to the line where this method was called, not to where the actual error occurred; we can look into the stack trace to get the actual line number of the error but this at least shows us the catch block where the error was caught and handled.
The code is commented and fairly self-explanatory so have a look. The basics of it are that it fetches the path to the error log folder from the app.config, then creates the directory and file, loading it with the error information we pass to the method along with the information supplied from the caller attributes.
using System;
using System.Text;
using System.IO;
using System.Runtime.CompilerServices;
namespace Demo_CallerInformation
{
/// <summary>
/// Write error information to a text file - the path to the error log folder is set
/// in the app.config file
/// </summary>
public static class ErrorLogger
{
/// <summary>
/// Write to Error Log as Text File
/// </summary>
/// <param name="msg">Pass in a string or the message portion of the exception</param>
/// <param name="stackTrace">Pass in the exception stacktrace</param>
/// <param name="memberName">CallerMemberName</param>
/// <param name="sourceFilePath">CallerFilePath</param>
/// <param name="sourceLineNumber">CallerLineNumber</param>
public static void WriteToErrorLog(string msg, string stackTrace,
[CallerMemberName] string memberName = "",
[CallerFilePath] string sourceFilePath = "",
[CallerLineNumber] int sourceLineNumber = 0)
{
// Get the path to the error log folder
string folderPath = Properties.Settings.Default.ErrorLogPath;
// make sure the folder exists, create it if necessary
if (!System.IO.Directory.Exists(folderPath))
System.IO.Directory.CreateDirectory(folderPath);
// put together a date string to append to the error log file name
string DateAppendage = DateTime.Now.Month.ToString() + "_" +
DateTime.Now.Day.ToString() + "_" + DateTime.Now.Year.ToString();
string errLogFile = folderPath + "ErrorLog_" + DateAppendage + ".txt";
// make sure the error log file exists
if (!File.Exists(errLogFile))
{
FileStream fs = new FileStream(errLogFile,
FileMode.CreateNew, FileAccess.ReadWrite);
StreamWriter s = new StreamWriter(fs);
s.Close();
fs.Close();
fs.Dispose();
}
// Capture the passed in and caller information (optional, empty arguments there) and log it
FileStream fs1 = new FileStream(errLogFile, FileMode.Append, FileAccess.Write);
StreamWriter s1 = new StreamWriter(fs1);
s1.Write("Error Log Entry: " + DateTime.Now.ToLongDateString() + Environment.NewLine);
s1.Write("Message: " + msg + Environment.NewLine);
s1.Write("Caller Member Name: " + memberName + Environment.NewLine);
s1.Write("Caller Path: " + sourceFilePath + Environment.NewLine);
s1.Write("Caller Line Number: " + sourceLineNumber.ToString() + Environment.NewLine);
s1.Write("Stack Trace: " + stackTrace + Environment.NewLine);
s1.Write("==================================================" + Environment.NewLine);
s1.Close();
fs1.Close();


Former memberPosted Jul 17, 2013, 1:39 AM
this is really nice article have.
Anubhav ChaudharyPosted Jul 15, 2013, 2:25 AM
Nice Article