我使用 AdoNetAppender 进行了数据库日志记录。我想做的是在每个日志语句上记录用户身份。但是,我不想使用标准的 log4net %identity 参数,原因有两个:
- log4net 警告说它非常慢,因为它必须查找上下文标识。
- 在某些服务组件中,标准身份是服务帐户,但我们已经在变量中捕获了用户身份,我想使用它。
我见过一些人使用 log4net.ThreadContext 添加其他属性的代码,但我知道这是由于线程交错而“不安全”的(这也是性能消耗)。
我的方法是扩展 AdoNetAppenderParameter 类:
public class UserAdoNetAppenderParameter : AdoNetAppenderParameter
{
public UserAdoNetAppenderParameter()
{
DbType = DbType.String;
PatternLayout layout = new PatternLayout();
Layout2RawLayoutAdapter converter = new Layout2RawLayoutAdapter(layout);
Layout = converter;
ParameterName = "@username";
Size = 255;
}
public override void Prepare(IDbCommand command)
{
command.Parameters.Add(this);
}
public override void FormatValue(IDbCommand command, LoggingEvent loggingEvent)
{
string[] data = loggingEvent.RenderedMessage.Split('~');
string username = data[0];
command.Parameters["@username"] = username;
}
}
然后以编程方式将其添加到当前的附加程序中,如下所示:
ILog myLog = LogManager.GetLogger("ConnectionService");
IAppender[] appenders = myLog.Logger.Repository.GetAppenders();
AdoNetAppender appender = (AdoNetAppender)appenders[0];
appender.AddParameter(new UserAdoNetAppenderParameter());
myLog.InfoFormat("{0}~{1}~{2}~{3}", userName, "ClassName", "Class Method", "Message");
这里的目的是使用标准格式的消息并解析字符串的第一部分,该部分应该始终是用户名。然后,自定义 appender 参数的 FormatValue() 方法应仅使用字符串的该部分,以便可以将其写入日志数据库中的单独字段。
我的问题是没有日志语句写入数据库。奇怪的是,调试时,FormatValue() 方法中的断点只有在我停止服务时才会被命中。
我已经浏览了很多与此相关的东西,但还没有找到任何答案。有没有人设法做到这一点,还是我走错了路。PS 我也尝试过扩展 AdoNetAppender,但它不允许您设置参数值。