使 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);
}
}
我有一个常用的日志记录项目,它使用 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}
之类的东西)。我的问题是用我自己的自定义 属性.
%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);
}
}