【问题标题】:NHibernate logging using NLog.Web.AspNetCore使用 NLog.Web.AspNetCore 进行 NHibernate 日志记录
【发布时间】:2020-09-16 13:48:56
【问题描述】:

我几乎浪费了一整天的时间,试图通过 NLog.Web.AspNetCore 为一个 ASP.Net Core 项目制作 NHibernate 日志消息——但无济于事。我能找到的唯一示例是隐藏的deep inside the NHibernate Git repository,但它不适用于现代版本的 Microsoft 日志库。更不用说这是一个非常粗略的解决方案,因为我必须复制/粘贴该文件夹中的两个辅助类来手动桥接 Microsoft 世界和 NHibernate 世界之间的记录器和记录器工厂。

是否有任何我无法识别的理智、现代、优雅的解决方案(或 NuGet 包)?我觉得我在这里遗漏了一些简单的东西,但就我的一生而言,我似乎无法让它发挥作用。

为了清楚起见,我正在寻找一种通过 NLog 管道 NHibernate 自己的日志消息的方法,不是使用 NHibernate 将 NLog 的消息持久保存到数据库。

【问题讨论】:

  • 您能解释一下NHibernate logging 的意思吗?这是否意味着您要记录所有已执行的 SQL 语句?找到这些文章:gunnarpeipman.com/nhibernate-log-sql-debug-windowgunnarpeipman.com/aspnet-core-nhibernate-log-sql(建议继承自 EmptyInterceptor 并挂钩到 sessionFactory)
  • @RomanArtiukhin,NHibernateToMicrosoftLoggerFactory 是我在 OP 中提到的两个复制/粘贴、不兼容、粗略的类之一(注意它在 URL 的文件夹中声明——它是一个 hack,不是框架的一部分)。
  • @RolfKristensen 这是一种有趣的方法——我还没有找到那些文章。这当然是一个可行的解决方案,但它仍然很粗略——您最终只捕获 SQL,而不是其他内部 NHibernate 消息和警告;此外,它假设您的代码将在应用程序的所有会话中注入拦截器(我在代码的各个部分中至少有一个无状态会话和一个有状态会话)。我仍然希望我能找到一种方法来使用 NHibernate 的原生 NHibernateLogger.SetLoggersFactory(),然后让 NHibernate 做它的事情......
  • incompatible, sketchy classes 你能详细说明不兼容吗?究竟是什么不兼容? NHibernateToMicrosoftLogger 是普通的适配器类。如果ILogger 界面发生了变化,只需调整它——它不应该太复杂。
  • @RomanArtiukhin,我对这种方法有多个问题,这是一个不足以表达所有问题的媒介。库和包管理器的重点是确保在从生态系统中的任何库的一个版本过渡到另一个版本时顺利进行协调——我不应该负责创建和维护主要组件之间的桥梁(例如 ORM 和记录基础设施)。例如,Github 库使用 Microsoft.Extensions.Logging.Abstractions 2.0.0.0,但当前的 NuGet 版本是 3.1.8;有多个重大更改。

标签: asp.net-core logging nhibernate nlog


【解决方案1】:

也许你可以试试这个(仅适用于 NHibernate > 5.1.0):

NHibernateLogger.SetLoggersFactory(new NHibernate.Logging.NLog.NLogLoggerFactory());

并像这样实现 NLogLoggerFactory:

using NHibernate;
using NLog;
using System;
using System.Collections.Generic;

namespace NHibernate.Logging.NLog
{

    public class NLogLoggerFactory : INHibernateLoggerFactory
    {
        private readonly LogFactory _factory;

        public NLogLoggerFactory(LogFactory logFactory = null)
        {
            _factory = logFactory ?? LogManager.LogFactory;
        }

        public INHibernateLogger LoggerFor(string keyName)
        {
            return new NLogLogger(_factory.GetLogger(keyName));
        }

        public INHibernateLogger LoggerFor(Type type)
        {
            return new NLogLogger(_factory.GetLogger(type.ToString()));
        }
    }

    class NLogLogger : INHibernateLogger
    {
        private readonly ILogger _logger;

        private readonly Dictionary<NHibernateLogLevel, LogLevel> LevelMapping = new Dictionary<NHibernateLogLevel, LogLevel>() {
            { NHibernateLogLevel.Trace, LogLevel.Trace },
            { NHibernateLogLevel.Debug, LogLevel.Debug },
            { NHibernateLogLevel.Info, LogLevel.Info },
            { NHibernateLogLevel.Warn, LogLevel.Warn },
            { NHibernateLogLevel.Error, LogLevel.Error },
            { NHibernateLogLevel.Fatal, LogLevel.Fatal },
            { NHibernateLogLevel.None, LogLevel.Off },
        };

        public NLogLogger(NLog.ILogger logger)
        {
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        }

        public bool IsEnabled(NHibernateLogLevel logLevel)
        {
            return _logger.IsEnabled(LevelMapping[logLevel]);
        }

        public void Log(NHibernateLogLevel logLevel, NHibernateLogValues state, Exception exception)
        {
            _logger.Log(LevelMapping[logLevel], exception, state.Format, state.Args);
        }
    }
}

【讨论】:

  • 我必须对其进行一些小的语法更改才能编译,但我仍然对 NHibernate 团队不提供开箱即用的兼容中间件感到不满——但它确实有效!由于这是第一次真正的东西终于起作用了,谢谢你!
  • 很高兴它可以工作。非常欢迎您更新我的答案,并更正任何语法错误。我没有自己编译代码,只是从接口写的。
  • 完成。我选择排除您的故障安全开关块,并改用字典。我这样做有两个原因:(1)速度,和(2)我实际上想知道将来是否有任何问题(即 NHibernate 是否添加了与现有日志级别不匹配的新日志级别),而不是默默地隐藏不匹配的消息。如果我有时间,我实际上会在主 NHibernate 存储库上创建一个拉取请求——除非你想这样做。再次感谢您!
【解决方案2】:

几个月后(!),我终于厌倦了为每个项目都使用自己的微库,并决定改为编写一个公共库:RBC.NHibernate.NLog

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-11
    • 2011-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多