c# MVC日志方法的执行和性能
本文关键字:执行 性能 方法 MVC 日志 | 更新日期: 2023-09-27 18:09:45
关于方法执行时间的记录(例如,通过postsharp,通过动作过滤器,或通过自定义方法属性)还有许多其他的帖子。
因此,记录一个方法完成的时间在这一点上是相对简单的。
然而,我希望做的是在每个请求的基础上使用更细粒度的性能指标,例如,会话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
}
}
理想情况下,我希望将所有这些操作(父方法,服务调用和db调用)链接在一起-最有可能的候选将通过会话id -但这意味着每个调用都需要访问会话id。
据我所知,完成这一任务的最好方法是利用方法属性来记录父性能时间,然后使用某种自定义库函数来存储调用的各种时间(可能使用nlog来记录)。
我想问的是关于什么是最好的方法(如果可能的话)来实现上述目标的意见?
我是否错过了任何第三方库的存在-即Unity或Postsharp是否提供此功能(或其他库)?
是否可以通过会话id链接所有这些记录?例如,我不知道如何通过postsharp(1)在MVC动作内部存储单个方法调用,以及(2)在调用之间传递变量。
根据您的问题,您需要记录与请求相关的所有操作。我将提出我的观点,希望对大家有用。
是否使用现有框架取决于许多原因,现在我将重点关注自定义实现。
首先,要完成这个问题,您需要一个日志结构:
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; }
}
接下来,您需要创建一个记录器对象,并调用您想要记录的每个点,例如:
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(自动生成)中获取键的值,用于对所有条目进行分组。
日志记录器。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);
另外,最好实现异步操作,以避免服务器阻塞请求。
如果这个答案是有意义的,我们可以改进概念,这是一个基本的想法,你可以如何解决你的问题