简体   繁体   English

如何在Log4Net中记录已用时间

[英]How to log elapsed time in Log4Net

I want to log the elapsed time of my APIs. 我想记录我的API的运行时间。 I see here two different approaches: 我在这里看到两种不同的方法:

  1. Using a stopwatch . 使用stopwatch Create a new stopwatch just after entering the API and then calling stop() just before quitting it (print the elapsed time on the log itself). 在输入API后立即创建一个新秒表,然后在退出之前调用stop() (在日志本身上打印已用时间)。

  2. Make two log printouts, one just after entering the API, the other just before quitting it. 制作两个日志打印输出,一个在输入API之后,另一个在退出之前。 The elapsed time would be "stored" as the time difference between the two log timestamps. 经过的时间将被“存储”为两个日志时间戳之间的时间差。

Which approach do you think is the best? 您认为哪种方法最好?

First one seems good but I need to create a new stopwatch everywhere. 第一个似乎很好,但我需要到处创建一个新的秒表。 The second is cleaner but then some math has to be done when reading back the log 第二个是更清洁,但在回读日志时必须完成一些数学运算

I'd go with the first option. 我会选择第一个选项。 The creation of a Stopwatch is very cheap. Stopwatch的制作非常便宜。 And with a good wrapper the required code in each API method can be as simple as: 使用一个好的包装器,每个API方法中所需的代码可以像下面这样简单:

public int MyApiMethod()
{
    using (new ExecutionTimeLogger())
    {
        // All API functionality goes inside this using block.
        var theResultValue = 23;
        return theResultValue;
    }
}

The class ExecutionTimeLogger would look something like this: ExecutionTimeLogger类看起来像这样:

using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using log4net;

public class ExecutionTimeLogger : IDisposable
{
    private readonly ILog log = LogManager.GetLogger("ExecutionTimes");
    private readonly string methodName;
    private readonly Stopwatch stopwatch;

    public ExecutionTimeLogger([CallerMemberName] string methodName = "")
    {
        this.methodName = methodName;
        stopwatch = Stopwatch.StartNew();
    }

    public void Dispose()
    {
        log.Debug(methodName + "() took " + stopwatch.ElapsedMilliseconds + " ms.");
        GC.SuppressFinalize(this);
    }
}

Depending on your logger implementation the output could look something like this: 根据您的记录器实现,输出可能如下所示:

15:04:23.4477 | 15:04:23.4477 | DEBUG | 调试| ExecutionTimes | 执行时间| MyApiMethod() took 42 ms. MyApiMethod()耗时42毫秒。

Note that the log output will also be generated when the API method threw an exception inside the using , because the ExecutionTimeLogger instance will be disposed nethertheless. 请注意,当API方法在using引发异常时,也会生成日志输出,因为ExecutionTimeLogger实例将被处理掉。

The methodName parameter will be automatically filled by the compiler because it has the [CallerMemberName] attribute . methodName参数将由编译器自动填充,因为它具有[CallerMemberName]属性 You don't need to pass it every time you create an ExecutionTimeLogger . 每次创建ExecutionTimeLogger都不需要传递它。

The line GC.SuppressFinalize(this) tells the garbage collector that a call to the finalizer of the ExecutionTimeLogger instance doesn't have to be scheduled, because we know it never created unmanaged resources. GC.SuppressFinalize(this)告诉垃圾收集器不必调度对ExecutionTimeLogger实例的终结器的调用,因为我们知道它从未创建过非托管资源。


If you are using Unity as the DI framework you could also write a UnityContainerExtension that wraps every method having a certain custom attribute (say LogExecutionTimeAttribute for example) with the required measurement and logging code. 如果您使用Unity作为DI框架,您还可以编写一个UnityContainerExtension ,它包含具有特定自定义属性的每个方法(例如LogExecutionTimeAttribute )以及所需的度量和日志记录代码。 That's much more complicated though. 但这要复杂得多。

I prefer the first approach (using stopwatch ). 我更喜欢第一种方法(使用stopwatch )。
if your methods are called synchronize you don't have to create a new Stopwatch object for each API call. 如果您的方法被称为同步,则不必为每个API调用创建新的Stopwatch对象。 you can define a global instance of Stopwatch and after calling Stop() ,call Reset() , or Restart() to start counting from the beginning. 你可以定义一个全局的Stopwatch实例,在调用Stop() ,调用Reset()Restart()从头开始计数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM