使 log4net appender 有条件地在特定字段的属性之间进行选择

Making a log4net appender conditionally choose between properties for a particular field

我有一个常用的日志记录项目,它使用 log4net 来记录日志记录事件。由于它是一个普通项目,因此以非标准方式配置:几乎所有内容都是通过 C# 代码设置的。

现在,我有一个以这种方式配置的 AdoNet appender,其中包括记录触发日志事件的方法。它是作为日志记录初始化的一部分创建的,定义如下:

appender.AddParameter(new AdoNetAppenderParameter()
{
    ParameterName = "@Method",
    DbType = DbType.String,
    Size = 255,
    Layout = new RawLayoutConverter().ConvertFrom(new PatternLayout("%method")) as IRawLayout
});

因为我绑定到 log4net %method 属性,这将自动提取触发日志记录事件的方法名称,并在名为 [=12= 的参数中将其发送到数据库] 最终将被插入到数据库 table 中,该数据库有一个名为 Method.

的列

但是,我添加了一些新功能来全局处理异常并记录它们。当异常从任何地方冒泡到调用堆栈的顶部时,它将被传递到这个新的全局方法,以便可以记录它。我有权访问异常,因此我可以看到导致此异常的控制器和方法。我可以轻松地将其添加为 log4net 自定义 属性(映射到 %property{ExceptionMethod} 之类的东西)。我的问题是用我自己的自定义 属性.

覆盖(或覆盖)log4net 的 %method 属性

那么,当通过 AdoNet appender 发送数据时,我如何让 log4net 有条件地在 %method%property{ExceptionMethod} 之间进行选择,以便在我的日志数据库的 Method 列下记录此信息 table?这是否可行?

根据您的需要,您可能会发现完全用代码实现 AdoNetAppender 更容易。

至少有一种方法可以做到这一点,在我之前的回答中找到 here

在不确切知道您是如何配置和使用 log4net 的情况下,很难编写适合您现有框架的代码:尽管这个示例创建了两个 appender,一个使用 %method,一个使用 %property{ExceptionMethod},并将它们分配给不同的记录器:

public abstract class BaseAppender : AdoNetAppender
{
    protected BaseAppender()
    {
        // Add common parameters, set connection strings etc

        // e.g.
        this.AddParameter(new AdoNetAppenderParameter
        {
            ParameterName = "@log_level",
            DbType = DbType.String,
            Size = 50,
            Layout = new RawLayoutConverter().ConvertFrom(new PatternLayout("%level")) as IRawLayout
        });

        // Then ask each subclass to add the extra parameters
        this.AddExtraParameters();
    }

    protected abstract void AddExtraParameters();
}

public class RuntimeAppender : BaseAppender
{
    protected override void AddExtraParameters()
    {
        this.AddParameter(new AdoNetAppenderParameter
        {
            ParameterName = "@Method",
            DbType = DbType.String,
            Size = 255,
            Layout = new RawLayoutConverter().ConvertFrom(new PatternLayout("%method")) as IRawLayout
        });
    }
}

public class UnhandledExceptionAppender : BaseAppender
{
    protected override void AddExtraParameters()
    {
        this.AddParameter(new AdoNetAppenderParameter
        {
            ParameterName = "@Method",
            DbType = DbType.String,
            Size = 255,
            Layout =
                new RawLayoutConverter().ConvertFrom(new PatternLayout("%property{ExceptionMethod}")) as IRawLayout
        });
    }
}

public sealed class RuntimeLogger : Logger
{
    public RuntimeLogger(string name)
        : base(name)
    {
        this.Appenders.Add(new RuntimeAppender());
        this.Level = Level.Error; // etc
    }
}

public sealed class UnhandledExceptionLogger : Logger
{
    public UnhandledExceptionLogger(string name)
        : base(name)
    {
        this.Appenders.Add(new UnhandledExceptionAppender());
        this.Level = Level.Error; // etc
    }
}

然后,在运行时,您选择使用哪个:

public class ExceptionHandler
{
    public void HandleException(Exception ex)
    {
        string exceptionMethod = "set exception method here" ; 
        GlobalContext.Properties["ExceptionMethod"] = exceptionMethod;

        var logger = new UnhandledExceptionLogger("Logger Name Goes Here");
        logger.Log(Level.Error, "Message", ex);
    }
}

public class RuntimeLogging
{
    public void LogSomething(Exception ex)
    {
        var logger = new RuntimeLogger("Logger Name Goes Here");
        logger.Log(Level.Error, "Message", ex);
    }
}