C#MVC日志记录方法的执行和性能 [英] C# MVC Logging method execution and performance

查看:183
本文介绍了C#MVC日志记录方法的执行和性能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

还有许多其他关于方法执行时间记录的文章(例如,通过动作过滤器,或通过自定义方法属性).

There are many other posts regarding the recording of method execution time (for example through postsharp, through action filters, or through a custom method attribute).

因此,在这一点上记录一个方法完成的时间相对简单.

So to record the time for a method to complete is relatively straightforward at this point.

不过,我要做的是根据每个请求获取更细粒度的性能指标,例如,使用会话ID跟踪针对给定请求发生的所有操作-以及所有请求经过的时间其中,而不仅仅是父方法(即动作控制器).

What I am looking to do however, is to get more fine-grained performance metrics on a per-request basis utilizing, for example, session id to track all operations that occured for a given request - and the time elapses for all of them, not just the parent (i.e. action controller) method.

例如,我希望能够执行以下操作:

For example, I would like to be able to do something like:

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.

Ideally I want to link all of these operations (the parent method, the service call and the db call) together - the most likely candidate would be through the session id - but that means that each call would need access to the session id.

据我所知,完成此操作的最佳方法是利用method属性记录父级执行时间,然后使用某种自定义库函数来存储调用的各种时间(可能使用nlog记录).

From what I've read, the best way of accomplishing this would be to utilize a method attribute to record the parent performance time, and then some sort of custom library function to store the various timing of the calls (probably using nlog to record).

我要问的是对实现上述目标的最佳方法(如果可能)的看法?

What I am asking for are opinions on what the best way (if at all possible) to accomplish the above?

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

Am I missing something with any third party libraries that exist - i.e. does Unity or Postsharp provide this functionality (or some other library)?

是否可以通过会话ID链接所有这些记录?例如,我看不到如何通过postharp(1)在MVC动作中存储单个方法调用,以及(2)在调用之间传递变量.

Is it possible to link all of these records via the session id? For example, I don't see how to via postsharp (1) store individual method calls INSIDE the MVC action, and (2) to pass variables between calls.

推荐答案

根据您的问题,您需要记录与请求相关的所有操作.我将提供自己的观点,希望对您有用.

According to your question, you need to log all operations related for a request. I'll provide my point of view, I hope that would be useful.

如果您要使用现有框架还是出于多种原因,现在我将重点介绍自定义实现.

If you'll use an existing framework or not depends of many reasons, for now I'll focus on and custom implementation.

首先,要解决此问题,您需要一个日志结构:

First, to accomplish this issue you need a log structure:

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

接下来,您需要创建一个记录器对象并在要记录的每个点上调用,例如:

Next, you need to create a logger object and invoke on each point you want to log, for example:

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(自动生成)中获取密钥值,以对所有条目进行分组.

In the code above, we take the key's value from server's session id (automatic generated) for group all entries.

Logger.Write方法的签名应类似于以下内容:

The Logger.Write method's signatures should be something like these:

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

通常,在实际的业务应用程序中,我们需要具有执行指标和其他内容的工作流定义,但是目前我不知道您想要开发此功能有多复杂.

Usually in real business applications, we need to have workflow definitions for execution metrics and other stuffs, but at this moment I don't know how complex do you want to develop this feature.

如果将所有记录器的调用添加到所需的位置,并将所有调用保存到数据库(sql或nosql)中,接下来,您将提取有关一个会话ID事件的所有信息.

If you add all logger's calls in your required point and save all of them into a database (sql or nosql), next you would extract all information about one session id events.

如上所示,有一些日志条目类型定义:警告和错误,假设您添加了try-catch块以进行错误处理,如果有异常,则可以在catch块内进行记录:

As you can see above, there are some log entry type definitions: warning and errors, suppose that you add try-catch block for error handling, inside of catch block if there is an exception you can log it:

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

另外,最好实现异步操作以避免服务器阻塞请求.

As an additional point, it's better to implement async operations to avoid server blocking for requests.

如果这个答案有意义,我们可以改进概念,这是解决问题的基本思路.

If this answer makes sense we can improve the concepts, this is a basic idea how you can solve your issue.

这篇关于C#MVC日志记录方法的执行和性能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆