2016-10-01 29 views
0

關於方法執行時間的記錄(例如,通過postsharp,通過action filters或通過自定義方法屬性),還有很多其他帖子。C#MVC日誌記錄方法的執行和性能

因此記錄方法完成的時間在這一點上是相對簡單的。

然而,我期望做的是在每個請求的基礎上獲得更多細粒度的性能指標,例如使用會話ID跟蹤給定請求發生的所有操作 - 並且時間過去了所有這些,不只是父母(即行動控制器)的方法。

例如,我希望能夠做一些事情,如:

namespace MvcApplication1.Controllers 
{ 
    public class ProductController : Controller 
    { 
     //record start of method 
     public ActionResult Index() 
     { 
      //record start of service1.method call 
      var data = service1.method(); 
      //store total time of service1.method call 

      //record start of db call 
      var objects = db.select(obj).where(id=0) 
      //store total time of db call 

      return View(); 
     } 
     //record total time of method 
    } 
} 

理想我想鏈接所有這些操作(父類的方法,服務調用和數據庫調用)一起 - 的最有可能的候選人將通過會話ID - 但這意味着每個電話都需要訪問會話ID。

從我讀過的,完成此操作的最佳方法是利用方法屬性來記錄父表現時間,然後某種自定義庫函數來存儲調用的各種時間(可能使用nlog記錄)。

我在問什麼是最好的方法(如果可能的話)來完成上述的意見?

我是否缺少任何存在的第三方庫 - 即Unity或Postsharp提供此功能(或其他庫)?

是否有可能通過會話ID鏈接所有這些記錄?例如,我沒有看到如何通過postharp(1)存儲MVC操作中的單個方法調用,以及(2)在調用之間傳遞變量。

回答

0

根據您的問題,您需要記錄與請求相關的所有操作。我會提供我的觀點,我希望這會有用。

如果您將使用現有的框架或取決於很多原因,現在我將專注於自定義實現。

首先,要完成這個問題,你需要一個日誌結構:

using System; 

public enum LogEntryType 
{ 
    Event, 
    Message, 
    Warning, 
    Error 
} 

public class LogEntry 
{ 
    public int? LogEntryID { get; set; } 

    public int? LogEntryType { get; set; } 

    public DateTime? EntryDate { get; set; } 

    public TimeSpan? ElapsedTime { get; set; } 

    public string Key { get; set; } 

    public string Description { get; set; } 
} 

接下來,你需要創建一個Logger對象並調用要記錄的每個點,例如:

namespace MvcApp.Controllers 
{ 
    public class ProductController : Controller 
    { 
     protected ILogger Logger; 

     public ProductController(ILogger logger;) 
     { 
      Logger = logger; 
     } 

     public ActionResult Index() 
     { 
      Logger.Write(LogEntry.Event, Server.SessionID, "Start of '{0}' action call", "Index"); 


      var serviceStopwatch = Stopwatch.StartNew(); 

      Logger.Write(LogEntry.Task, Server.SessionID, "Start of '{0}' task's execution", "GetData"); 

      var data = service.GetData(); 

      serviceStopwatch.Stop(); 

      Logger.Write(LogEntry.Task, Server.SessionID, serviceStopwatch.Elapsed, "End of '{0}' task's execution", "GetData"); 


      var dbCallStopwatch = Stopwatch.StartNew(); 

      Logger.Write(LogEntry.Task, Server.SessionID, "Start of '{0}' db call", "GetObjects"); 

      var objects = repository.GetObjects(); 

      dbCallStopwatch.Stop(); 

      Logger.Write(LogEntry.Task, Server.SessionID, dbCallStopwatch.Elapsed, "End of '{0}' db call", "GetObjects"); 


      Logger.Write(LogEntry.Event, Server.SessionID, "End of '{0}' action call", "Index"); 

      return View(); 
     } 
    } 
} 

在上面的代碼中,我們從服務器的會話ID(自動生成)中獲取密鑰的值,用於組所有條目。

的Logger.Write方法的簽名應該是這樣的:

public void Write(LogEntryType logEntryType, string key, string message, params string[] args) 
{ 
    var item = new LogEntry 
    { 
     LogEntryType = (int?)logEntryType, 
     EntryDate = DateTime.Now, 
     Key = key, 
     Description = string.Format(message, args) 
    }; 

    // Code for save log entry to text file, database, send email if it's an error, etc. 
} 

public void Write(LogEntryType logEntryType, string key, TimeSpan elapsedTime, string message, params string[] args) 
{ 
    var item = new LogEntry 
    { 
     LogEntryType = (int?)logEntryType, 
     EntryDate = DateTime.Now, 
     ElapsedTime = elapsedTime, 
     Key = key, 
     Description = string.Format(message, args) 
    }; 

    // Code for save log entry to text file, database, send email if it's an error, etc. 
} 

通常在實際業務應用,我們需要有執行指標和其他東西的工作流定義,但在這一刻我不知道知道你想開發這個功能有多複雜。

如果你在你的需要添加點都記錄儀的電話,他們都保存到數據庫(SQL或NoSQL的),接下來你會抽取約一個會話ID的所有事件信息。如上所述,有一些日誌條目類型定義:警告和錯誤,假設你添加try-catch塊來處理錯誤,在catch塊內部,如果有異常,你可以記錄它:

Logger.Write(LogEntry.Error, Server.SessionID, "There was an error on '{0}' task. Details: '{1}'", "Index", ex.Message); 

作爲一個額外的點,這是更好地實現異步操作,以避免阻塞服務器的請求。

如果這個答案是有道理的,我們可以改善的概念,這是一個基本的想法,你如何能夠解決您的問題。