In this article, you will see the Parameter Log utility class, which we can use to trace parameter values during an exception. We will see how to use the log utility, a Log string sample followed by a list of limitations that the logger has.
Introduction
Exceptions are common in any project. To track exceptions, we use error loggers which may only log the exception detail and some additional pieces of information. But hardly do we get an idea for which input set (parameters and values) a particular method is throwing the error.
Parameter Log Utility
Here is the utility class, which we can use to trace parameter
values during the exception.
internal class ParamLogUtility
{
private readonly String _methodName;
private String _paramaterLog;
private readonly JavaScriptSerializer _serializer;
private readonly Dictionary<String, Type> _methodParamaters;
private readonly List<Tuple<String, Type, object>>_providedParametars;
public ParamLogUtility(params Expression<Func<object>>[] providedParameters)
{
try
{
_serializer = new JavaScriptSerializer();
var currentMethod = new StackTrace().GetFrame(1).GetMethod();
_methodName = String.Format("Class = {0}, Method = {1}",
currentMethod.DeclaringType.FullName, currentMethod.Name);
_methodParamaters = new Dictionary<string, Type>();
(from aParamater in currentMethod.GetParameters()
select new { Name = aParamater.Name, DataType = aParamater.ParameterType })
.ToList()
.ForEach(obj => _methodParamaters.Add(obj.Name, obj.DataType));
_providedParametars = new List<Tuple<string, Type, object>>();
foreach (var aExpression in providedParameters)
{
Expression bodyType = aExpression.Body;
if (bodyType is MemberExpression)
{
AddProvidedParamaterDetail((MemberExpression)aExpression.Body);
}
else if (bodyType is UnaryExpression)
{
UnaryExpression unaryExpression = (UnaryExpression)aExpression.Body;
AddProvidedParamaterDetail((MemberExpression)unaryExpression.Operand);
}
else
{
throw new Exception("Expression type unknown.");
}
}
ProcessLog();
}
catch (Exception exception)
{
throw new Exception("Error in paramater log processing.", exception);
}
}
private void ProcessLog()
{
try
{
foreach (var aMethodParamater in _methodParamaters)
{
var aParameter =
_providedParametars.Where(
obj => obj.Item1.Equals(aMethodParamater.Key) &&
obj.Item2 == aMethodParamater.Value).Single();
_paramaterLog += String.Format(@" ""{0}"":{1},",
aParameter.Item1, _serializer.Serialize(aParameter.Item3));
}
_paramaterLog = (_paramaterLog != null) ?
_paramaterLog.Trim(' ', ',') : string.Empty;
}
catch (Exception exception)
{
throw new Exception("MathodParamater is not found in providedParameters.");
}
}
private void AddProvidedParamaterDetail(MemberExpression memberExpression)
{
ConstantExpression constantExpression =
(ConstantExpression) memberExpression.Expression;
var name = memberExpression.Member.Name;
var value = ((FieldInfo)
memberExpression.Member).GetValue(constantExpression.Value);
var type = value.GetType();
_providedParametars.Add(new Tuple<string, Type, object>(name, type, value));
}
public String GetLog()
{
return String.Format("{0}({1})", _methodName, _paramaterLog);
}
}
- Inside contractor,
ParamLogUtility(params Expression<Func<object>>[] providedParameters)
we will pass all the expected method parameters. GetLog()
will return us the error log string
Using Log Utility
To use the code, we may have to add System.Web.Extensions.dll reference at our project, which is located somewhere around this location
C:\Program Files
(x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Web.Extensions.dll
If the method contains any parameter. we will use the utility class like:
private void Add(string id, int age, string name, PersonEntity aPersonEntity)
{
try
{
throw new NotImplementedException();
}
catch (Exception exception)
{
var paramLog = new ParamLogUtility(() => aPersonEntity,
() => age, () => id, () => name).GetLog();
}
}
It is not important that all methods should have parameters. If there is no parameter, we can use it like:
var paramLog = new ParamLogUtility().GetLog();
Log String Sample
Class = MethodParamatersLog.Program, Method = Add("id":"1",
"age":24, "name":"Dipon",
"aPersonEntity":{"CreatedDateTime":"\/Date(1405115574273)\/",
"Id":"1","Name":"Dipon","Age":24})
Limitations
This logger does have some limitations like:
- Only parameters pacified at method signature could participate in log process. If we add some extra variables to the process, it would throw an error as here
aPersonEntity
is not part of the method signature.
private static void Add(string id, int age, string name)
{
PersonEntity aPersonEntity = new PersonEntity();
try
{
throw new NotImplementedException();
}
catch (Exception exception)
{
var paramLog = new ParamLogUtility(() => aPersonEntity, () => age,
() => id, () => name).GetLog();
var error = exception;
}
}
- All the parameters of the method should take part in the log process. If not, it would throw an error. This is important because sometimes we may forget to add method parameters to the log string. This error will remind us to use thus unused parameters.
private static void Add(string id, int age, string name)
{
PersonEntity aPersonEntity = new PersonEntity();
try
{
throw new NotImplementedException();
}
catch (Exception exception)
{
var paramLog = new ParamLogUtility(() => name).GetLog();
var error = exception;
}
}
- There can be some other errors too, which I haven’t faced yet. So if you find any, please let me know.
- Should we use this utility to every method? Obviously not!
You can find the sample project of VS 2013 solution in the attachment.
History
- 13th July, 2014: Initial version