最近在写一个项目,需要将日志写入数据库,Log4Net的功能仅仅只能满足写入消息部分,若需要写入自定义信息就不行了,所以这里扩展了Log4Net的部分功能。
扩展字段
建立扩展字段的Entity类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Kelun.Log4Net
{
/// <summary>
/// 扩展Log4Net字段
/// </summary>
class LogMessage
{
/// <summary>
/// 订单号
/// </summary>
public string OrderNum { get; set; }
/// <summary>
/// 用户
/// </summary>
public string UserName { get; set; }
public LogMessage(string orderNum, string userName)
{
OrderNum = orderNum;
UserName = userName;
}
}
}
转换类
using log4net.Core;
using log4net.Layout.Pattern;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Kelun.Log4Net
{
/// <summary>
/// Log4Net 扩展字段
/// 转换自定义字段
/// </summary>
class ParemterContent
{
internal sealed class OrderNumParam : PatternLayoutConverter
{
protected override void Convert(TextWriter writer, LoggingEvent loggingEvent)
{
if (loggingEvent.MessageObject is LogMessage content)
{
writer.Write(content.OrderNum);
}
}
}
internal sealed class UserNameParam : PatternLayoutConverter
{
protected override void Convert(TextWriter writer, LoggingEvent loggingEvent)
{
if (loggingEvent.MessageObject is LogMessage content)
{
writer.Write(content.UserName);
}
}
}
}
}
Layout 扩展
using log4net.Layout;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Kelun.Log4Net
{
class MyLoggerLayout : PatternLayout
{
public MyLoggerLayout()
{
this.AddConverter("OrderNum", typeof(ParemterContent.OrderNumParam));
this.AddConverter("UserName", typeof(ParemterContent.UserNameParam));
}
}
}
扩展方法
接口
using log4net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Kelun.Log4Net
{
interface IMyLog : ILog
{
void Debug(object message, string OrderNum, string UserName);
void Debug(object message, string OrderNum, string UserName,Exception t);
void Info(object message, string OrderNum, string UserName);
void Info(object message, string OrderNum, string UserName, Exception t);
void Warn(object message, string OrderNum, string UserName);
void Warn(object message, string OrderNum, string UserName, Exception t);
void Error(object message, string OrderNum, string UserName);
void Error(object message, string OrderNum, string UserName, Exception t);
}
}
接口实现
using Kelun.Log4Net;
using log4net.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Kelun.Log4Net
{
class MyLogImpl : LogImpl, IMyLog
{
public static readonly Type ThisDeclaringType = typeof(MyLogImpl);
public MyLogImpl(ILogger logger) : base(logger)
{
}
#region 实现重写
public void Debug(object message, string OrderNum, string UserName)
{
Debug(message, OrderNum, UserName, null);
}
public void Debug(object message, string OrderNum, string UserName, Exception t)
{
if (this.IsDebugEnabled)
{
LoggingEvent loggingEvent = new LoggingEvent(ThisDeclaringType, Logger.Repository, Logger.Name, Level.Debug, message, t);
loggingEvent.Properties["UserName"] = UserName;
loggingEvent.Properties["OrderNum"] = OrderNum;
Logger.Log(loggingEvent);
}
}
public void Error(object message, string OrderNum, string UserName)
{
Error(message, OrderNum, UserName, null);
}
public void Error(object message, string OrderNum, string UserName, Exception t)
{
if (this.IsErrorEnabled)
{
LoggingEvent loggingEvent = new LoggingEvent(ThisDeclaringType, Logger.Repository, Logger.Name, Level.Error, message, t);
loggingEvent.Properties["UserName"] = UserName;
loggingEvent.Properties["OrderNum"] = OrderNum;
Logger.Log(loggingEvent);
}
}
public void Info(object message, string OrderNum, string UserName)
{
Info(message, OrderNum, UserName, null);
}
public void Info(object message, string OrderNum, string UserName, Exception t)
{
if (this.IsInfoEnabled)
{
LoggingEvent loggingEvent = new LoggingEvent(ThisDeclaringType, Logger.Repository, Logger.Name, Level.Info, message, t);
loggingEvent.Properties["UserName"] = UserName;
loggingEvent.Properties["OrderNum"] = OrderNum;
Logger.Log(loggingEvent);
}
}
public void Warn(object message, string OrderNum, string UserName)
{
Warn(message, OrderNum, UserName, null);
}
public void Warn(object message, string OrderNum, string UserName, Exception t)
{
LoggingEvent loggingEvent = new LoggingEvent(ThisDeclaringType, Logger.Repository, Logger.Name, Level.Warn, message, t);
loggingEvent.Properties["UserName"] = UserName;
loggingEvent.Properties["OrderNum"] = OrderNum;
Logger.Log(loggingEvent);
}
#endregion
}
}
扩展Manager
using log4net.Core;
using System.Reflection;
using System;
namespace Kelun.Log4Net
{
class MyLogManager
{
#region Static Member Variables
/// <summary>
/// The wrapper map to use to hold the <see cref="MyLogImpl"/> objects
/// </summary>
private static readonly WrapperMap s_wrapperMap = new WrapperMap(new WrapperCreationHandler(WrapperCreationHandler));
#endregion
#region Constructor
private MyLogManager() { }
#endregion
#region Type Specific Manager Methods
/// <summary>
/// Returns the named logger if it exists
/// </summary>
/// <remarks>
/// <para>If the named logger exists (in the default hierarchy) then it
/// returns a reference to the logger, otherwise it returns
/// <c>null</c>.</para>
/// </remarks>
/// <param name="name">The fully qualified logger name to look for</param>
/// <returns>The logger found, or null</returns>
public static IMyLog Exists(string name)
{
return Exists(Assembly.GetCallingAssembly(), name);
}
/// <summary>
/// Returns the named logger if it exists
/// </summary>
/// <remarks>
/// <para>If the named logger exists (in the specified domain) then it
/// returns a reference to the logger, otherwise it returns
/// <c>null</c>.</para>
/// </remarks>
/// <param name="domain">the domain to lookup in</param>
/// <param name="name">The fully qualified logger name to look for</param>
/// <returns>The logger found, or null</returns>
public static IMyLog Exists(string domain, string name)
{
return WrapLogger(LoggerManager.Exists(domain, name));
}
/// <summary>
/// Returns the named logger if it exists
/// </summary>
/// <remarks>
/// <para>If the named logger exists (in the specified assembly's domain) then it
/// returns a reference to the logger, otherwise it returns
/// <c>null</c>.</para>
/// </remarks>
/// <param name="assembly">the assembly to use to lookup the domain</param>
/// <param name="name">The fully qualified logger name to look for</param>
/// <returns>The logger found, or null</returns>
public static IMyLog Exists(Assembly assembly, string name)
{
return WrapLogger(LoggerManager.Exists(assembly, name));
}
/// <summary>
/// Returns all the currently defined loggers in the default domain.
/// </summary>
/// <remarks>
/// <para>The root logger is <b>not</b> included in the returned array.</para>
/// </remarks>
/// <returns>All the defined loggers</returns>
public static IMyLog[] GetCurrentLoggers()
{
return GetCurrentLoggers(Assembly.GetCallingAssembly());
}
/// <summary>
/// Returns all the currently defined loggers in the specified domain.
/// </summary>
/// <param name="domain">the domain to lookup in</param>
/// <remarks>
/// The root logger is <b>not</b> included in the returned array.
/// </remarks>
/// <returns>All the defined loggers</returns>
public static IMyLog[] GetCurrentLoggers(string domain)
{
return WrapLoggers(LoggerManager.GetCurrentLoggers(domain));
}
/// <summary>
/// Returns all the currently defined loggers in the specified assembly's domain.
/// </summary>
/// <param name="assembly">the assembly to use to lookup the domain</param>
/// <remarks>
/// The root logger is <b>not</b> included in the returned array.
/// </remarks>
/// <returns>All the defined loggers</returns>
public static IMyLog[] GetCurrentLoggers(Assembly assembly)
{
return WrapLoggers(LoggerManager.GetCurrentLoggers(assembly));
}
/// <summary>
/// Retrieve or create a named logger.
/// </summary>
/// <remarks>
/// <para>Retrieve a logger named as the <paramref name="name"/>
/// parameter. If the named logger already exists, then the
/// existing instance will be returned. Otherwise, a new instance is
/// created.</para>
///
/// <para>By default, loggers do not have a set level but inherit
/// it from the hierarchy. This is one of the central features of
/// log4net.</para>
/// </remarks>
/// <param name="name">The name of the logger to retrieve.</param>
/// <returns>the logger with the name specified</returns>
public static IMyLog GetLogger(string name)
{
return GetLogger(Assembly.GetCallingAssembly(), name);
}
/// <summary>
/// Retrieve or create a named logger.
/// </summary>
/// <remarks>
/// <para>Retrieve a logger named as the <paramref name="name"/>
/// parameter. If the named logger already exists, then the
/// existing instance will be returned. Otherwise, a new instance is
/// created.</para>
///
/// <para>By default, loggers do not have a set level but inherit
/// it from the hierarchy. This is one of the central features of
/// log4net.</para>
/// </remarks>
/// <param name="domain">the domain to lookup in</param>
/// <param name="name">The name of the logger to retrieve.</param>
/// <returns>the logger with the name specified</returns>
public static IMyLog GetLogger(string domain, string name)
{
return WrapLogger(LoggerManager.GetLogger(domain, name));
}
/// <summary>
/// Retrieve or create a named logger.
/// </summary>
/// <remarks>
/// <para>Retrieve a logger named as the <paramref name="name"/>
/// parameter. If the named logger already exists, then the
/// existing instance will be returned. Otherwise, a new instance is
/// created.</para>
///
/// <para>By default, loggers do not have a set level but inherit
/// it from the hierarchy. This is one of the central features of
/// log4net.</para>
/// </remarks>
/// <param name="assembly">the assembly to use to lookup the domain</param>
/// <param name="name">The name of the logger to retrieve.</param>
/// <returns>the logger with the name specified</returns>
public static IMyLog GetLogger(Assembly assembly, string name)
{
return WrapLogger(LoggerManager.GetLogger(assembly, name));
}
/// <summary>
/// Shorthand for <see cref="LogManager.GetLogger(string)"/>.
/// </summary>
/// <remarks>
/// Get the logger for the fully qualified name of the type specified.
/// </remarks>
/// <param name="type">The full name of <paramref name="type"/> will
/// be used as the name of the logger to retrieve.</param>
/// <returns>the logger with the name specified</returns>
public static IMyLog GetLogger(Type type)
{
return GetLogger(Assembly.GetCallingAssembly(), type.FullName);
}
/// <summary>
/// Shorthand for <see cref="LogManager.GetLogger(string)"/>.
/// </summary>
/// <remarks>
/// Get the logger for the fully qualified name of the type specified.
/// </remarks>
/// <param name="domain">the domain to lookup in</param>
/// <param name="type">The full name of <paramref name="type"/> will
/// be used as the name of the logger to retrieve.</param>
/// <returns>the logger with the name specified</returns>
public static IMyLog GetLogger(string domain, Type type)
{
return WrapLogger(LoggerManager.GetLogger(domain, type));
}
/// <summary>
/// Shorthand for <see cref="LogManager.GetLogger(string)"/>.
/// </summary>
/// <remarks>
/// Get the logger for the fully qualified name of the type specified.
/// </remarks>
/// <param name="assembly">the assembly to use to lookup the domain</param>
/// <param name="type">The full name of <paramref name="type"/> will
/// be used as the name of the logger to retrieve.</param>
/// <returns>the logger with the name specified</returns>
public static IMyLog GetLogger(Assembly assembly, Type type)
{
return WrapLogger(LoggerManager.GetLogger(assembly, type));
}
#endregion
#region Extension Handlers
/// <summary>
/// Lookup the wrapper object for the logger specified
/// </summary>
/// <param name="logger">the logger to get the wrapper for</param>
/// <returns>the wrapper for the logger specified</returns>
private static IMyLog WrapLogger(ILogger logger)
{
return (IMyLog)s_wrapperMap.GetWrapper(logger);
}
/// <summary>
/// Lookup the wrapper objects for the loggers specified
/// </summary>
/// <param name="loggers">the loggers to get the wrappers for</param>
/// <returns>Lookup the wrapper objects for the loggers specified</returns>
private static IMyLog[] WrapLoggers(ILogger[] loggers)
{
IMyLog[] results = new IMyLog[loggers.Length];
for (int i = 0; i < loggers.Length; i++)
{
results[i] = WrapLogger(loggers[i]);
}
return results;
}
/// <summary>
/// Method to create the <see cref="ILoggerWrapper"/> objects used by
/// this manager.
/// </summary>
/// <param name="logger">The logger to wrap</param>
/// <returns>The wrapper for the logger specified</returns>
private static ILoggerWrapper WrapperCreationHandler(ILogger logger)
{
return new MyLogImpl(logger);
}
#endregion
}
}
配置文件及数据库建表语句
配置文件
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net debug="true">
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender" >
<file value="testlog.txt" />
<appendToFile value="true" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="100" />
<rollingStyle value="Date" />
<datePattern value="yyyy-MM-dd"/>
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5level %date %logger - [%message] - %property{OrderNum} - %property{UserName %newline" />
</layout>
</appender>
<!-- 写入SqlServer数据库 -->
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
<!--缓存多少数据后写入数据库-->
<bufferSize value="1" />
<!--数据源连接类型-->
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<!-- SQL连接字符串-->
<!--<connectionString value="Data Source=JALENAPC;Initial Catalog=erp;integrated security=false;Persist Security Info=True;User ID=sa;Password=privacy" />-->
<ConnectionStringName value="Kelun.Properties.Settings.ConnectionString"/>
<!--SQL写入语句-->
<commandText value="INSERT INTO [Loging] (logDate, logLevel, logLogger, logOrder, logMessage, logUser, logException) VALUES (@logDate, @logLevel, @logLogger, @logOrder, @logMessage ,@logUser, @logException)" />
<!-- 写入参数 -->
<parameter>
<parameterName value="@logDate" />
<dbType value="DateTime" />
<layout type="log4net.Layout.RawTimeStampLayout" />
</parameter>
<parameter>
<parameterName value="@logLevel" />
<dbType value="String" />
<size value="50" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%level" />
</layout>
</parameter>
<parameter>
<parameterName value="@logLogger" />
<dbType value="String" />
<size value="500" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%logger" />
</layout>
</parameter>
<parameter>
<parameterName value="@logOrder" />
<dbType value="String" />
<size value="20" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{OrderNum}" />
</layout>
</parameter>
<parameter>
<parameterName value="@logMessage" />
<dbType value="String" />
<size value="4000" />
<!--<layout type="log4net.Layout.PatternLayout">-->
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message" />
</layout>
</parameter>
<parameter>
<parameterName value="@logUser" />
<dbType value="String" />
<size value="50" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{UserName}" />
</layout>
</parameter>
<parameter>
<parameterName value="@logException" />
<dbType value="String" />
<size value="2000" />
<layout type="log4net.Layout.ExceptionLayout" />
</parameter>
</appender>
<root>
<level value="ALL"/>
<appender-ref ref="AdoNetAppender" />
<appender-ref ref="RollingFileAppender" />
</root>
<!--<logger name="MyLogger">
<level value="ALL"/>
<appender-ref ref="AdoNetAppender" />
</logger>-->
</log4net>
</configuration>
建表语句
create table Loging (
id int identity,
logDate datetime null,
logLevel varchar(50) null,
logLogger varchar(500) null,
logOrder varchar(20) null,
logMessage text null,
logUser varchar(50) null,
logException text null,
constraint PK_LOGING primary key (id)
)
使用
AssemblyInfo.cs 增加如下内容
// 自动配置Log4Net
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config",Watch =true)]
private static readonly IMyLog logger = MyLogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
logger.Debug("只有消息的输出");
logger.Debug("日志内容", "OrderNum", "Jalena");
logger.Warn("Warn.......","OrderNum","Jalena");
logger.Error("Error...", "order..", "王麻子", new Exception("异常信息"));
最后来个数据库最终数据
文章评论