【问题标题】:How to redirect npgsql log output to a log4net logger?如何将 npgsql 日志输出重定向到 log4net 记录器?
【发布时间】:2012-04-22 23:10:19
【问题描述】:

是否可以将 npgsql 日志输出重定向到 log4net 记录器?从 npgsql 源代码来看,它看起来像是直接记录到 stdout/stderr 或指定文件(使用 NpgsqlEventLog 上的静态属性)。有没有办法将该登录路由到 log4net?

【问题讨论】:

    标签: logging log4net npgsql


    【解决方案1】:

    我就是这样做的,它似乎工作得相当好。请注意,我将注销命令拆分到单独的附加程序,因为它变得非常冗长......

    首先,在对 Npgsql 进行任何其他调用之前添加它:

    NpgsqlLogManager.Provider = new Log4NetNpgsqlLoggingProvider("NpgsqlDefaultLogger")
    {
        CommandLoggerName = "NpgsqlCommandLogger"
    };
    

    现在您需要添加日志记录提供程序类:

    using System;
    using Npgsql.Logging;
    
    namespace Util.Npgsql
    {
        public class Log4NetNpgsqlLoggingProvider : INpgsqlLoggingProvider
        {
            public string DefaultLoggerName { get; }
            public string CommandLoggerName { get; set; }
    
            public Log4NetNpgsqlLoggingProvider(string defaultLoggerName)
            {
                if (defaultLoggerName == null) throw new ArgumentNullException(nameof(defaultLoggerName));
                DefaultLoggerName = defaultLoggerName;
            }
    
            public NpgsqlLogger CreateLogger(string name)
            {
                switch (name)
                {
                    case "Npgsql.NpgsqlCommand":
                        return new Log4NetNpgsqlLogger(CommandLoggerName ?? DefaultLoggerName);
                    default:
                        return new Log4NetNpgsqlLogger(DefaultLoggerName);
                }
            }
        }
    }
    

    您还需要实际的记录器类:

    using System;
    using log4net;
    using log4net.Core;
    using Npgsql.Logging;
    
    namespace Util.Npgsql
    {
        public class Log4NetNpgsqlLogger : NpgsqlLogger
        {
            private readonly ILog _log;
    
            public Log4NetNpgsqlLogger(string name)
            {
                _log = LogManager.GetLogger(name);
            }
    
            public override bool IsEnabled(NpgsqlLogLevel level)
            {
                return _log.Logger.IsEnabledFor(GetLog4NetLevelFromNpgsqlLogLevel(level));
            }
    
            public override void Log(NpgsqlLogLevel level, int connectorId, string msg, Exception exception = null)
            {
                _log.Logger.Log(typeof(NpgsqlLogger), GetLog4NetLevelFromNpgsqlLogLevel(level), connectorId + ": " + msg, exception);
            }
    
            protected Level GetLog4NetLevelFromNpgsqlLogLevel(NpgsqlLogLevel level)
            {
                switch (level)
                {
                    case NpgsqlLogLevel.Trace:
                    case NpgsqlLogLevel.Debug:
                        return Level.Debug;
                    case NpgsqlLogLevel.Info:
                        return Level.Info;
                    case NpgsqlLogLevel.Warn:
                        return Level.Warn;
                    case NpgsqlLogLevel.Error:
                        return Level.Error;
                    case NpgsqlLogLevel.Fatal:
                        return Level.Fatal;
                    default:
                        throw new Exception("Unknown Npgsql Log Level: " + level);
                }
            }
        }
    }
    

    【讨论】:

    • 另请注意,在 Npgsql 3.2.0 中:“Npgsql 的自定义日志记录已替换为 [Microsoft.Extensions.Logging]”。然而,在 3.2.2 中它被恢复了:“由于许多投诉,Npgsql 3.2 对 Microsoft.Extensions.Logging 的使用已被删除,现在日志记录的工作方式与 Npgsql 3.1 中的一样”。参考:github.com/npgsql/Npgsql/releases
    【解决方案2】:

    首先将 log4net 添加到您的解决方案中,简单的方法是使用 nuget: 所以你这样做: 安装包 log4net 然后你必须安装 npgsql: 安装包 npgsql

    在您的 web.config 文件中添加以下元素:(您必须使用 app.config 而非 web 解决方案)

    在配置部分 printf("%d\n", 42); /*

    //the most important thing is to ensure that the type on your parameter         //section is correct. otherwise, no error will be returned, and no data will be         inserted.
    
    //now, at your code you can use this function:
    
            protected void LogInfo(string message, params object[] args)
            {
                log4net.ILog log =     log4net.LogManager.GetLogger("postgreSqlLogAppender");
                log4net.ThreadContext.Properties["UserId"] = args.[0];
                log4net.ThreadContext.Properties["EntityId"] = args.[1];
                log.Info(string.Format("{0}: {1}",     this.GetType().Name.Replace("Controller", ""), string.Format(message, args)));
                log4net.ThreadContext.Properties.Remove("UserId");
                log4net.ThreadContext.Properties.Remove("EntityId");
            }
    
    
    //to call your function
        void test()
    {
       LogInfo("My message",15,326)
    }
    
    
    //in my case 15 is my current user_id and 326 is the my class_object.
         */
    

    【讨论】:

      【解决方案3】:

      我对npgsql一无所知,但是如果你有源并且允许更改它,那么应该更改它以支持log4net会更容易。

      如果您没有来源,那将是不容易的,甚至可能是不可能的。由于 log4net 不拦截来自其他来源的输出,我能看到的唯一方法是拥有一个后台线程来监视 npgsql 输出到的文件,并且当文件更改时,您需要读取该文件并解析信息,然后使用该信息调用 log4net。

      你仍然有 log4net 会认为每个调用都来自你的例程而不是 npgsql 和堆栈跟踪的问题。也只有在每次创建日志条目时 npgsql 都在锁定、打开、写入和关闭文件时才有效。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-11-25
        • 2012-01-05
        • 1970-01-01
        • 2018-01-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-16
        相关资源
        最近更新 更多