2015-05-28 15 views
8

Tôi đang cố gắng "tiêm" các phương pháp theo dõi tùy chỉnh trong ứng dụng của mình.Phương pháp theo dõi thời gian thực hiện

Tôi muốn làm cho nó thanh lịch nhất có thể, mà không cần sửa đổi nhiều mã hiện có và có khả năng bật/tắt dễ dàng.

Một giải pháp mà tôi có thể nghĩ là tạo một tùy chỉnh Attribute mà tôi sẽ đính kèm nó vào các phương pháp tôi muốn theo dõi.

ý tưởng cơ bản:

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 
    } 
} 

Có bất kỳ .NET thuộc tính hiện tại cung cấp callbacks khi một phương pháp được gọi/kết thúc?

+0

Tôi không nghĩ rằng tôi biết về bất kỳ. –

+1

Điều bạn đang tìm kiếm là trong lĩnh vực lập trình theo hướng khía cạnh. Có một thư viện gọi là [PostSharp] (https://www.postsharp.net/) mà thực hiện chính xác những gì bạn muốn. Nếu bạn đang tìm kiếm các giải pháp nguồn mở, hãy xem bài đăng [this] (http://stackoverflow.com/questions/633710/what-is-the-best-implementation-for-aop-in-net). –

+0

Postsharp sẽ làm điều này rất dễ dàng cho bạn. Bạn thậm chí có thể áp dụng các khía cạnh của bạn trên toàn bộ không gian tên thông qua AssemblyInfo.cs. Kiểm tra nó tại: https://www.postsharp.net/ –

Trả lời

4

Phương thức của thuộc tính không được gọi trừ khi bạn gọi nó theo cách thủ công. Có các thuộc tính bảo mật được gọi bởi CLR nhưng đó là vượt ra ngoài chủ đề của câu hỏi này và nó sẽ không hữu ích anyway.

Có các kỹ thuật để viết lại mã của bạn ở các cấp độ khác nhau. Mã nguồn dệt, IL dệt vv.

Bạn cần phải xem xét một số cách để sửa đổi IL và viết lại nó cho thời gian thực hiện. Đừng lo lắng, bạn không phải viết tất cả điều đó. Mọi người đã làm điều đó. Ví dụ: bạn có thể sử dụng PostSharp.

Dưới đây là một article cung cấp một ví dụ

[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); 
     } 
} 

Lưu ý: Tôi đã sửa đổi ví dụ từ bài viết để sử dụng StopWatch thay vì DateTimeDateTime là không chính xác.

+1

Làm tốt để sử dụng 'Đồng hồ bấm giờ' thay vì' Ngày giờ ' –

1

Bạn có thể theo dõi thời gian thực hiện phương thức dễ dàng với PostSharp (có sẵn dưới dạng gói NuGet). Quy tắc tùy chỉnh phương pháp cấp thuộc tính mà thực hiện điều đó (lấy từ 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); 
    } 
    } 
Các vấn đề liên quan