Reputation: 3412
There is a webforms application with classes that contain lot of methods. I want to keep logs of the methods that are being called in a flexible and easy way. I want to know which method has finally been called and some other additional info like:
Currently, I am using log4net for filesystem logging like:
using log4net;
private static readonly ILog Log1 = LogManager.GetLogger("Log1");
public int DoSomething(int itemId = 0)
{
Log1.DebugFormat("[DoSomething] - Doing Something on item {0} Started", itemId );
try
{
//something..
}
catch (Exception ex)
{
Log1.Debug("[DoSomething] - Something Failed", ex);
}
Log1.DebugFormat("[DoSomething] - Doing Something on item {0} Finished", itemId );
return 0;
}
How is it possible to achieve this without writing every time these pieces of code in every method? Is there a better and automatic way? What about the performance cost in every case?
An alternative approach would be great!
Upvotes: 0
Views: 107
Reputation: 101633
Below code should give you a starting point. It's a sample which uses console instead of log4net, but I think it's trivial to extend it to use whatever you need.
First install PostSharp nuget package. Then define new aspect:
[Serializable]
public sealed class TraceAttribute : OnMethodBoundaryAspect
{
private readonly string _argumentsFormat;
[NonSerialized]
private string _methodName;
public TraceAttribute() {
}
public TraceAttribute(string argumentsFormat) {
_argumentsFormat = argumentsFormat;
}
public override void RuntimeInitialize(MethodBase method) {
_methodName = method.Name;
}
public override void OnEntry(MethodExecutionArgs args) {
string msg = $"[{_methodName}]: entered";
if (!String.IsNullOrWhiteSpace(_argumentsFormat)) {
msg += String.Format(". Arguments:" + _argumentsFormat, args.Arguments.ToArray());
}
Console.WriteLine(msg);
}
// Invoked at runtime after the target method is invoked (in a finally block).
public override void OnExit(MethodExecutionArgs args) {
string msg = $"[{_methodName}]: exited";
if (!String.IsNullOrWhiteSpace(_argumentsFormat)) {
msg += String.Format(". Arguments: " + _argumentsFormat, args.Arguments.ToArray());
}
Console.WriteLine(msg);
}
public override void OnException(MethodExecutionArgs args) {
string msg = $"[{_methodName}]: exception";
if (!String.IsNullOrWhiteSpace(_argumentsFormat))
{
msg += String.Format(". Arguments: " + _argumentsFormat, args.Arguments.ToArray());
}
msg += ". Details: " + args.Exception.ToString();
Console.WriteLine(msg);
}
}
What we basically do here is inheriting MethodBoundaryAspect and define what code should be executed when target method is entered, exited, and when exception is thrown. Use it like this:
public class Program {
static void Main(string[] args) {
TestStuff(1);
TestStuff(2);
TestStuff(3);
Console.ReadKey();
}
[Trace("itemId: {0}")]
static void TestStuff(int itemId) {
Console.WriteLine("Inside TestStuff: " + itemId);
if (itemId == 3)
throw new Exception("Test exception");
}
}
You can also apply that attribute to whole classes. In this case - all methods inside that class will be traced.
Upvotes: 1