如何将npgsql日志输出重定向到log4net记录器?

时间:2012-04-10 16:18:25

标签: logging log4net npgsql

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

3 个答案:

答案 0 :(得分:2)

我就是这样做的,而且似乎工作得相当好。请注意,我正在将命令注销到单独的appender,因为它变得非常冗长......

首先,在对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);
            }
        }
    }
}

答案 1 :(得分:1)

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

如果您没有来源,那么这并不容易,甚至可能无法实现。由于log4net不拦截来自其他源的输出,我能看到的唯一方法就是有一个后台线程来监视npgsql输出的文件,当文件发生变化时,你需要读取该文件并解析信息,然后使用该信息调用log4net。

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

答案 2 :(得分:1)

首先将log4net添加到您的解决方案中,简单的方法是使用nuget: 所以你这样做: install-package log4net 那么你必须安装npgsql: install-Package npgsql

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

在configSection      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.
     */