在ASP.NET Core WebAPI中实现Log4net [英] Implement log4net in asp.net core webapi

查看:165
本文介绍了在ASP.NET Core WebAPI中实现Log4net的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个asp.net核心网络api.到目前为止,我正在使用ILogger记录消息.但是ILogger中没有致命的日志级别.有关键级别,但是我们的团队需要致命单词而不是关键单词.我有什么办法可以调整打印到日志的工作?

I have a asp.net core web api. As of now I'm using ILogger to log the messages. But ILogger doesn't have Fatal loglevel in it. There is Critical level, but our team requires Fatal word instead of Critical word.Is there any way I can tweak the work which gets printed to logs?

如果没有,我想用具有致命级别的log4Net替换ILogger. 我具有多层体系结构: WebApplication1 WebApplication1.Helper .所有这些都是解决方案中包含的不同项目.

If not, I want to replace ILogger with log4Net which has Fatal level in it.So this is what I have done , but somehow it is not working. I have multi layer architecture : WebApplication1, WebApplication1.Helper . All these are different projects with in a solution.

WebApplication1 中: 我添加了Microsoft.Extensions.Logging.Log4Net.AspNetCore参考.
startup.cs

In WebApplication1: I have added Microsoft.Extensions.Logging.Log4Net.AspNetCore reference.
In startup.cs

public void ConfigureServices(IServiceCollection apiServices)
    {
        var provider = apiServices.BuildServiceProvider();

        var factory = new LoggerFactory()
               .AddConsole().AddLog4Net().AddApplicationInsights(provider, LogLevel.Information);

        apiServices.AddSingleton(factory);
        apiServices.AddLogging();
        apiServices.AddMvc();
        apiServices.AddOptions();
    }

HomeController.cs

[Route("api/[controller]")]
    [ApiController]
    public class HomeController : Controller
    {
        private readonly ILog4NetHelper _logHelper = new Log4NetHelper();
        [HttpGet]
        public virtual IActionResult GetData()
        {
            try
            {
                _logHelper.Log4NetMessage("Info", "Start GetData");
                return new OkObjectResult("Your in Home Controller");
            }
            catch (Exception ex)
            {
                _logHelper.Log4NetMessage("Error", "Exception in GetData" + ex.Message);
                throw;
            }
        }
    }

WebApplication1.Helper项目
WebApplication1.Helper项目中,我添加了接口ILog4NetHelper和实现该接口Log4NetHelper的类.另外我还添加了log4Net配置文件.

WebApplication1.Helper project
And in WebApplication1.Helper project , I have added a interface ILog4NetHelper and class which implements this interface Log4NetHelper. Also I have added log4Net config file.

  public class Log4NetHelper : ILog4NetHelper
    {
        readonly ILog _log =log4net.LogManager.GetLogger(typeof(Log4NetHelper));
        public void Log4NetMessage(string type,string message)
        {
            string logMessage = message;    
            switch (type)
            {
                case "Info":
                    _log.Info(logMessage);
                    break;
                case "Error":
                    _log.Error(logMessage);
                    break;
                case "Fatal":
                    _log.Fatal(logMessage);
                    break;
                default:
                    _log.Info(logMessage);
                    break;
            }
        }
    }

当我托管该应用程序并运行它时,它给了我500内部服务器错误.错误消息是这样的:

When I host this application and run this, it is giving me a 500 internal server error. The error message is this :

InvalidOperationException:无法解析类型的服务 尝试激活时"WebApplication1.Helper.Log4NetHelper" 'WebApplication1.Helper.Log4NetHelper'. Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType,类型implementationType,CallSiteChain,callSiteChain, ParameterInfo []参数,布尔型throwIfCallSiteNotFound)

InvalidOperationException: Unable to resolve service for type 'WebApplication1.Helper.Log4NetHelper' while attempting to activate 'WebApplication1.Helper.Log4NetHelper'. Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, bool throwIfCallSiteNotFound)

我该如何解决?

推荐答案

ASP.Net Core内置日志记录是Microsoft进行以依赖项注入方式记录Microsoft的障碍.它遵循Log4Net方法的基本原理和原则(已在.Net,Java和Javascript等标准中进行了标准化).因此,这两种方法并不完全相互矛盾.

ASP.Net Core built-in logging was Microsoft's stab at doing logging the Microsoft, dependency-injected way. It follows the basic principles and tenets of the Log4Net approach (which has been standardized across .Net, Java, and Javascript, among others). So, the two approaches are not entirely at odds with one another.

但是,在这种特殊情况下,该实现似乎与两种记录方法的意图实际上冲突.

However, in this particular case, the implementation appears to actually conflict with the intent of both approaches to logging.

Log4Net分离了记录写入日志输出这两个动作.第一个是通过 ILog 界面完成的.第二个是通过 Appenders .

Log4Net separates out the two acts of recording and writing log output. The first is done via the ILog interface. The second is done via one of the Appenders.

类似地,ASP.net Core API使用 ILogger 和一个或多个

Similarly, the ASP.net Core API uses an ILogger and one or more Providers to emit log messages.

由于我对log4net较为满意,并且在每个类中都没有通过依赖注入添加记录器的意义,我使用了log4net的LogManager.GetLogger(typeof(MyClass))方法,而不是通过Microsoft DI来实现.我的附加程序也通过log4net运行.因此,我的实现重点是将Microsoft日志记录输出转换为log4net格式,这似乎是您的团队想要的,但与您在此处所做的相反.我的方法基于本文.我使用的代码如下.

As I am more comfortable with log4net, and also don't see much of a point in having loggers added via dependency injection in EVERY CLASS, I used log4net's approach of LogManager.GetLogger(typeof(MyClass)) rather than doing it via Microsoft DI. My appenders also run through log4net. Thus, my implementation focused on translating the Microsoft logging outputs into the log4net format, which appears to be the what your team would like but the opposite of what you are doing here. My approach was based on this article. The code I used is below.

实施说明:

我通过log4net设置了一个自定义追加程序,该程序将我的日志写出到日志数据库(此数据库的常用数据库是loki和/或elasticsearch).

I set up a custom appender via log4net which writes my logs out to a logging database (commonly-used databases for this are loki and/or elasticsearch).

startup.csConfigure()方法中,您需要具有以下行(请注意,我在ConfigureServices中实例化了customAppender,然后将其添加到DI中,但是您不必这样):

In the Configure() method on startup.cs, you'll need to have the following line (note that I instantiate the customAppender in the ConfigureServices and then add it to the DI, but you wouldn't have to do it this way):

loggerFactory.AddLog4Net(_serverConfig.LoggingSettings, customAppender);

还必须在ConfigureServices()中添加以下内容(不知道为什么,但似乎可以确保常规的.net核心日志记录可以启动).

It is also necessary to have the following in ConfigureServices() (not sure why, but it seems to ensure that the regular .net core logging kicks in).

services.AddLogging(config => {
    config.AddDebug();
    config.AddConsole();
});

Log4NetLogger.cs

/// <summary>
/// Writes ASP.net core logs out to the log4net system.
/// </summary>
public class Log4NetLogger : ILogger
{
    private readonly ILog _logger;
    public Log4NetLogger(string name)
    {
        _logger = LogManager.GetLogger(typeof(Log4NetProvider).Assembly, name);
    }

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

    public bool IsEnabled(LogLevel logLevel)
    {
        switch (logLevel) {
            case LogLevel.Critical:
                return _logger.IsFatalEnabled;
            case LogLevel.Debug:
            case LogLevel.Trace:
                return _logger.IsDebugEnabled;
            case LogLevel.Error:
                return _logger.IsErrorEnabled;
            case LogLevel.Information:
                return _logger.IsInfoEnabled;
            case LogLevel.Warning:
                return _logger.IsWarnEnabled;
            default:
                throw new ArgumentOutOfRangeException(nameof(logLevel));
        }
    }

    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state,
        Exception exception, Func<TState, Exception, string> formatter)
    {
        if (!this.IsEnabled(logLevel)) {
            return;
        }

        if (formatter == null) {
            throw new ArgumentNullException(nameof(formatter));
        }
        string message = null;
        if (null != formatter) {
            message = formatter(state, exception);
        }
        if (!string.IsNullOrEmpty(message) || exception != null) {
            switch (logLevel) {
                case LogLevel.Critical:
                    _logger.Fatal(message);
                    break;
                case LogLevel.Debug:
                case LogLevel.Trace:
                    _logger.Debug(message);
                    break;
                case LogLevel.Error:
                    _logger.Error(message);
                    break;
                case LogLevel.Information:
                    _logger.Info(message);
                    break;
                case LogLevel.Warning:
                    _logger.Warn(message);
                    break;
                default:
                    _logger.Warn($"Encountered unknown log level {logLevel}, writing out as Info.");
                    _logger.Info(message, exception);
                    break;
            }
        }
    }

Log4NetProvider.cs

/// <summary>
/// Returns new log4net loggers when called by the ASP.net core logging framework
/// </summary>
public class Log4NetProvider : ILoggerProvider
{
    private readonly LoggingConfig _config;
    private readonly ConcurrentDictionary<string, Log4NetLogger> _loggers =
        new ConcurrentDictionary<string, Log4NetLogger>();
    private readonly ILoggerRepository _repository =
        log4net.LogManager.CreateRepository(typeof(Log4NetProvider).Assembly, typeof(log4net.Repository.Hierarchy.Hierarchy));

    public Log4NetProvider(LoggingConfig config, MyCustomAppender otherAppender)
    {
        _config = config;
        BasicConfigurator.Configure(_repository, new ConsoleAppender(), otherAppender);

        LogManager.GetLogger(this.GetType()).Info("Logging initialized.");
    }

    public ILogger CreateLogger(string categoryName)
    {
        return _loggers.GetOrAdd(categoryName, this.CreateLoggerImplementation(categoryName));
    }

    public void Dispose()
    {
        _loggers.Clear();
    }

    private Log4NetLogger CreateLoggerImplementation(string name)
    {
        return new Log4NetLogger(name);
    }
}

Log4NetExtensions.cs

/// <summary>
/// A helper class for initializing Log4Net in the .NET core project.
/// </summary>
public static class Log4netExtensions
{
    public static ILoggerFactory AddLog4Net(this ILoggerFactory factory, LoggingConfig config, MyCustomAppender appender)
    {
        factory.AddProvider(new Log4NetProvider(config, appender));
        return factory;
    }
}

这篇关于在ASP.NET Core WebAPI中实现Log4net的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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