本文介绍了使用自定义参数的log4net数据库日志记录的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有使用AdoNetAppender的数据库记录。我想做的是在每个日志语句上记录用户身份。但是,我不想使用标准的log4net%身份参数有两个原因:


  1. log4net警告,

  2. 在某些服务组件中,标准标识是一个服务帐户,但是我们已经捕获了一个变量中的用户标识,我想使用它。 / li>

我已经看到一些人使用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命令,LoggingEvent loggingEvent)
{
string [] data = loggingEvent.RenderedMessage.Split ');
string username = data [0];
command.Parameters [@ username] = username;
}

}

然后以编程方式将其添加到当前appender如下:

  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()方法中的断点只有在停止服务时才会被触发。



我已经拖曳了很多东西,还没有找到任何答案。
有人设法做到这一点,或者我在错误的路径。
P.S.我也试过扩展AdoNetAppender,但它不允许你设置参数值。

解决方案

终于得到这个工作。确保log4net的内部日志记录有助于识别错误并下载log4net源代码并查看AdoNetAppenderParameter类,它显示了如何使用FormatValue()方法。所以,这里是修改的自定义appender参数:

  public class UserAdoNetAppenderParameter:AdoNetAppenderParameter 
{
$ b b public override void FormatValue(IDbCommand命令,LoggingEvent loggingEvent)
{
string [] data = loggingEvent.RenderedMessage.Split('〜');
string username = string.Empty;
if(data!= null&& data.Length> = 1)
username = data [0];

//查找参数
IDbDataParameter param =(IDbDataParameter)command.Parameters [ParameterName];

//格式化值
对象formattedValue = username;

//如果值为null,那么转换为DBNull
if(formattedValue == null)
{
formattedValue = DBNull.Value;
}

param.Value = formattedValue;
}

}

它在log4net配置文件中像这样:

 < parameter type =MyAssembly.Logging.UserAdoNetAppenderParameter,MyAssembly> 
< parameterName value =@ username/>
< dbtype value =String/>
< size value =255/>
< layout type =log4net.Layout.PatternLayoutvalue =%message/>
< / parameter>

按照惯例,我的日志语句将是这样:



if(log.IsDebugEnabled)
log.DebugFormat({0}〜{1}〜{2},username,someOtherParameter,message) ;

如果你看类,它使用data [0]作为用户名,遵循公约。但是,它会将用户名写入自己的参数,并进入日志数据库表中的单独字段,而无需将其临时填充到不安全的ThreadContext中。


I have database logging in place using the AdoNetAppender. What I'd like to do is log the user identity on each log statement. However, I don't want to use the standard log4net %identity parameter for two reasons:

  1. log4net warn that its extremely slow as it has to look up the context identity.
  2. In some service components the standard identity is a service account but we have already captured the user identity in a variable and I'd like to use that.

I have seen code where some people use the log4net.ThreadContext to add additional properties but I understand that this is 'unsafe' due to thread interleaving (and it is also a performance drain).

My approach has been to extend the AdoNetAppenderParameter class thus:

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;
    }

}

and then programmatically add this to the current appender like so:

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");

The intention here is to use a standard format for messages and parse the first part of the string which should always be the username. The FormatValue() method of the custom appender parameter should then use only that part of the string so that it can be written to a separate field in the log database.

My problem is that no log statements are written to the database. Oddly, when debugging, a breakpoint in the FormatValue() method is only hit when I stop the service.

I've trawled through loads of stuff relating to this but haven't yet found any answers.Has anyone managed to do this, or am I on the wrong trail.P.S. I've also tried extending the AdoNetAppender but it doesnt give you access to set the parameter values.

解决方案

After some experimentation, I finally got this to work. Ensuring that log4net's internal logging helped identify the errors and downloading the log4net source code and reviewing the AdoNetAppenderParameter class showed how the FormatValue() method should be used. So, here's the amended custom appender parameter:

public class UserAdoNetAppenderParameter : AdoNetAppenderParameter
{

    public override void FormatValue(IDbCommand command, LoggingEvent loggingEvent)
    {
        string[] data = loggingEvent.RenderedMessage.Split('~');
        string username = string.Empty;
        if (data != null && data.Length >= 1)
            username = data[0];

        // Lookup the parameter
        IDbDataParameter param = (IDbDataParameter)command.Parameters[ParameterName];

        // Format the value
        object formattedValue = username;

        // If the value is null then convert to a DBNull
        if (formattedValue == null)
        {
            formattedValue = DBNull.Value;
        }

        param.Value = formattedValue;
    }

}

And to use this, I add it in the log4net config file like this:

<parameter type="MyAssembly.Logging.UserAdoNetAppenderParameter, MyAssembly">
 <parameterName value="@username" />
 <dbType value="String" />
 <size value="255" />
 <layout type="log4net.Layout.PatternLayout" value="%message" />
</parameter>

And by convention, my log statements will be something like this:

if (log.IsDebugEnabled)
    log.DebugFormat("{0}~{1}~{2}", username, someOtherParameter, message);

If you look at the class, it uses data[0] as the username, so it is dependant on following the convention. It does, however, get the username into its own parameter and into a separate field in the log database table, without resorting to stuffing it temporarily into the unsafe ThreadContext.

这篇关于使用自定义参数的log4net数据库日志记录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-14 14:37