如何将CallingMemberName传递给自定义日志记录提供程序

时间:2017-01-22 01:45:09

标签: c# logging

使用ASP.NET Core并使用ILogging和ILoggingProvider实现我自己的控制台日志记录提供程序,因为我想将调用函数的名称作为日志记录的一部分传递给记录器以及日期/时间戳。

检索调用函数名称的最佳方法是在函数参数中使用[CallerMemberName]属性,但是当我试图保持标准日志记录模式并继承ILogger接口时我无法解决如何重载任何Log方法调用以使用附加函数参数来添加CallerMemberName属性。

以下是Main中的代码:

public class Program
{
    static ILogger Logger { get; } = ApplicationLogging.CreateLogger<Program>();

    public static void Main(string[] args)
    {
         ApplicationLogging.Logger.AddMyLogger();
         Program.Logger.LogInformation("Test log");
    ...
    }
 }

这是我的自定义日志记录提供程序

// Setup logging for all classes to use
public static class ApplicationLogging
{
    public static ILoggerFactory Logger { get; } = new LoggerFactory();
    public static ILogger CreateLogger<T>() =>
    Logger.CreateLogger<T>();
}

public static class MyLoggerProviderExtensions
{
    public static ILoggerFactory AddMyLogger(this ILoggerFactory loggerFactory)
    {
        loggerFactory.AddProvider(new MyLoggerProvider());
        return loggerFactory;
    }
}


public class MyLoggerProvider : ILoggerProvider
{
    public MyLoggerProvider()
    {
    }

public ILogger CreateLogger(string categoryName)
    {
        return new MyLogger();
    }

    public void Dispose()
    {
    }

    void IDisposable.Dispose()
    {
        throw new NotImplementedException();
    }
}

public class MyLogger : ILogger
{
    public MyLogger()
    {
    }

    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
    {
        Console.WriteLine("{0,-12} {1,-20} {2}", DateTime.Now.ToString("HH:mm:ss.fff"), " [NEED_CALLING_METHOD_NAME_HERE]", state);
    }

    public bool IsEnabled(LogLevel logLevel)
    {
        return true;
    }

    public IDisposable BeginScope<TState>(TState state)
    {
        return new NoopDisposable();
    }

    private class NoopDisposable : IDisposable
    {
        public void Dispose()
        {
        }
    }
}

如果我将CallerMemberName添加到Log方法调用中,那么我没有按照接口实现它并且它将不会编译(如预期的那样)。我尝试添加一个类范围的变量,并在实例化记录器时设置调用成员名称,但不会捕获正确的调用成员。

我是C#的新手,所以我可能错过了最好的方法 - 我看到它的方式我必须重载Log函数来添加[CallerMemberName]属性,但标准的日志记录调用语义(例如。 LogCritical)不会使用我的重载函数。

当然,我可以放弃我的自定义日志记录提供程序并编写自己的日志记录功能,这将更简单,但不会利用Microsoft提供的日志记录基础结构。我知道我可以使用Reflection但是我不想采用额外的CPU命中,因为这个软件可以在非常低端的硬件上运行。

1 个答案:

答案 0 :(得分:1)

在日志功能中:

public void Log()
{
  var stackTrace = new System.Diagnostics.StackTrace(1); // skip one frame as this is the Log function frame
  var name = stackTrace.GetFrame(0).GetMethod().Name;
}

编辑:

如果你想避免反思:

using (_logger.BeginScope("name of method"))
{
    // log the stuff
}

不确定.Net Core但是在正常的.Net中你可以通过将面向方面编程很容易地用于多种方法来添加它。