我正在尝试在我的应用程序中“注入”自定义跟踪方法。
我希望尽可能优雅,不需要修改现有的大部分代码,并且可以轻松启用/禁用它。
我能想到的一个解决方案是创建一个自定义public class MethodSnifferAttribute : Attribute
{
private Stopwatch sw = null;
public void BeforeExecution()
{
sw = new Stopwatch();
sw.Start();
}
public void ExecutionEnd()
{
sw.Stop();
LoggerManager.Logger.Log("Execution time: " + sw.ElapsedMilliseconds);
}
}
public class MyClass
{
[MethodSniffer]
public void Function()
{
// do a long task
}
}
,我将它附加到我想要跟踪的方法上。
基本理念:
.NET
是否有任何现有的nav-tab
属性为调用/结束方法提供回调?
答案 0 :(得分:7)
属性的方法。有一些安全属性可以由CLR调用,但这超出了这个问题的主题,无论如何都不会有用。
有一些技术可以在不同的级别重写代码。源代码编织,IL编织等。
您需要查看某种方法来修改IL并重写它以便执行计时。别担心,你不必写所有这些。人们已经做到了。例如,您可以使用PostSharp。
这里有article,提供了一个示例
[Serializable]
[DebuggerStepThrough]
[AttributeUsage(AttributeTargets.Method)]
public sealed class LogExecutionTimeAttribute : OnMethodInvocationAspect
{
private static readonly ILog Log = LogManager.GetLogger(typeof(LogExecutionTimeAttribute));
// If no threshold is provided, then just log the execution time as debug
public LogExecutionTimeAttribute() : this (int.MaxValue, true)
{
}
// If a threshold is provided, then just flag warnning when threshold's exceeded
public LogExecutionTimeAttribute(int threshold) : this (threshold, false)
{
}
// Greediest constructor
public LogExecutionTimeAttribute(int threshold, bool logDebug)
{
Threshold = threshold;
LogDebug = logDebug;
}
public int Threshold { get; set; }
public bool LogDebug { get; set; }
// Record time spent executing the method
public override void OnInvocation(MethodInvocationEventArgs eventArgs)
{
var sw = Stopwatch.StartNew();
eventArgs.Proceed();
sw.Stop();
var timeSpent = sw.ElapsedMilliseconds;
if (LogDebug)
{
Log.DebugFormat(
"Method [{0}{1}] took [{2}] milliseconds to execute",
eventArgs.Method.DeclaringType.Name,
eventArgs.Method.Name,
timeSpent);
}
if (timeSpent > Threshold)
{
Log.WarnFormat(
"Method [{0}{1}] was expected to finish within [{2}] milliseconds, but took [{3}] instead!",
eventArgs.Method.DeclaringType.Name,
eventArgs.Method.Name,
Threshold,
timeSpent);
}
}
注意:我已修改文章中的示例以使用StopWatch
而不是DateTime
,因为DateTime
并不准确。
答案 1 :(得分:1)
您可以使用PostSharp(可用作NuGet包)轻松跟踪方法执行时间。执行该操作的自定义方法级属性的代码(取自here):
[Serializable]
[DebuggerStepThrough]
[AttributeUsage(AttributeTargets.Method)]
public sealed class LogExecutionTimeAttribute : OnMethodInvocationAspect
{
private static readonly ILog Log = LogManager.GetLogger(typeof(LogExecutionTimeAttribute));
// If no threshold is provided, then just log the execution time as debug
public LogExecutionTimeAttribute() : this (int.MaxValue, true)
{
}
// If a threshold is provided, then just flag warnning when threshold's exceeded
public LogExecutionTimeAttribute(int threshold) : this (threshold, false)
{
}
// Greediest constructor
public LogExecutionTimeAttribute(int threshold, bool logDebug)
{
Threshold = threshold;
LogDebug = logDebug;
}
public int Threshold { get; set; }
public bool LogDebug { get; set; }
// Record time spent executing the method
public override void OnInvocation(MethodInvocationEventArgs eventArgs)
{
var start = DateTime.Now;
eventArgs.Proceed();
var timeSpent = (DateTime.Now - start).TotalMilliseconds;
if (LogDebug)
{
Log.DebugFormat(
"Method [{0}{1}] took [{2}] milliseconds to execute",
eventArgs.Method.DeclaringType.Name,
eventArgs.Method.Name,
timeSpent);
}
if (timeSpent > Threshold)
{
Log.WarnFormat(
"Method [{0}{1}] was expected to finish within [{2}] milliseconds, but took [{3}] instead!",
eventArgs.Method.DeclaringType.Name,
eventArgs.Method.Name,
Threshold,
timeSpent);
}
}