是否可以将 npgsql 日志输出重定向到 log4net 记录器?从 npgsql 源代码来看,它看起来像是直接记录到 stdout/stderr 或指定文件(使用 上的静态属性NpgsqlEventLog
)。有没有办法将该登录路由到 log4net?
3 回答
这就是我所做的,它似乎工作得相当好。请注意,我将注销命令拆分到单独的附加程序,因为它变得非常冗长......
首先,在对 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);
}
}
}
}
首先将 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.
*/
我对npgsql一无所知,但如果你有源并且允许更改它,那么更改它以支持log4net应该更容易。
如果您没有源,那么这将是不容易的,甚至可能是不可能的。由于 log4net 不会拦截来自其他来源的输出,因此我能看到的唯一方法是拥有一个后台线程来监视 npgsql 正在输出到的文件,并且当文件更改时,您需要读取该文件并解析信息,然后使用该信息调用 log4net。
您仍然有 log4net 会认为每个调用都来自您的例程而不是 npgsql 和堆栈跟踪的问题。也只有在每次创建日志条目时 npgsql 都在锁定、打开、写入和关闭文件时才有效。