c# – 使用自定义参数记录log4net数据库

我使用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;
    }

}

然后以编程方式将其添加到当前的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()方法中的断点.

我已经搜索了大量与此有关的东西,但还没有找到任何答案.
有没有人设法做到这一点,或者我是在错误的轨道上.
附:我也试过扩展adonetappender,但它不能让你访问设置参数值.

解决方法

我还需要记录结构化数据,并喜欢使用这样的日志记录界面:
log.Debug( new {
    SomeProperty: "some value",OtherProperty: 123
})

所以我也编写了自定义adonetappenderParameter类来完成这项工作:

public class CustomadonetappenderParameter : adonetappenderParameter
{
    public override void FormatValue(IDbCommand command,LoggingEvent loggingEvent)
    {
        // Try to get property value
        object propertyValue = null;
        var propertyName = ParameterName.Replace("@","");

        var messageObject = loggingEvent.MessageObject;
        if (messageObject != null)
        {
            var property = messageObject.GetType().GetProperty(propertyName);
            if (property != null)
            {
                propertyValue = property.GetValue(messageObject,null);
            }
        }

        // Insert property value (or db null) into parameter
        var dataParameter = (IDbDataParameter)command.Parameters[ParameterName];
        dataParameter.Value = propertyValue ?? dbnull.Value;
    }
}

现在log4net配置可用于记录给定对象的任何属性

<?xml version="1.0" encoding="utf-8"?>
<log4net>
    <appender name="Myadonetappender" type="log4net.Appender.adonetappender">
        <connectionType value="System.Data.sqlClient.sqlConnection,System.Data,Version=1.0.3300.0,Culture=neutral,PublicKeyToken=b77a5c561934e089" />
        <connectionString value="... your connection string ..." />
        <commandText value="INSERT INTO mylog ([level],[someProperty]) VALUES (@log_level,@SomeProperty)" />

        <parameter>
            <parameterName value="@log_level" />
            <dbType value="String" />
            <size value="50" />
            <layout type="log4net.Layout.PatternLayout">
                <conversionPattern value="%level" />
            </layout>
        </parameter>

        <parameter type="yourNamespace.CustomadonetappenderParameter,yourAssemblyName">
            <parameterName value="@SomeProperty" />
            <dbType value="String" />
            <size value="255" />
        </parameter>
    </appender>

    <root>
        <level value="DEBUG" />
        <appender-ref ref="Myadonetappender" />
    </root>
</log4net>

相关文章

在要实现单例模式的类当中添加如下代码:实例化的时候:frmC...
1、如果制作圆角窗体,窗体先继承DOTNETBAR的:public parti...
根据网上资料,自己很粗略的实现了一个winform搜索提示,但是...
近期在做DSOFramer这个控件,打算自己弄一个自定义控件来封装...
今天玩了一把WMI,查询了一下电脑的硬件信息,感觉很多代码都...
最近在研究WinWordControl这个控件,因为上级要求在系统里,...