问题1: 在公司进行log4net写入服务器配置的时候,一切正常,但是在家里的机器上,就频繁出现这个问题:
SQL Server 2008 报错:已成功与服务器建立连接,但是在登录前的握手期间发生错误
并且这种错误是随机性的,在log4net往数据库插入几条的时候,没问题,但是插入次数一多起来,就频繁报这个错误。后来没办法,网上搜罗了一圈,最终发现了解决方案:
将相关的TCP参数都设置为启动之后,就再没遇到过问题。
问题2,log4net配置都正确,但是一直无法写入数据库。
这个问题困扰了好久,最终得以解决,大家就看看我的解决代码吧,我也懒得帖步骤了。
配置文件如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | < log4net > < root > < level value="WARN"/> < level value="INFO"/> < level value="DEBUG"/> < level value="FINE"/> <!--<appender-ref ref="LogFileAppender" />--> < appender-ref ref="ADONetAppender" /> </ root > < appender name="LogFileAppender" type="log4net.Appender.RollingFileAppender"> <!--文件名称--> < file value="log.txt" /> <!--所有新的日志都进行追加--> < appendToFile value="true" /> <!--文件名称格式--> < datePattern value="-yyyy.MM.dd" /> <!--文件名按日期滚动--> < rollingStyle value="Date" /> < maxSizeRollBackups value="10" /> <!--文件名称不固定,可变--> < staticLogFileName value="false" /> < layout type="log4net.Layout.PatternLayout"> < param name="ConversionPattern" value="%-5p%d{yyyy-MM-dd hh:mm:ss} – %m%n" /> </ layout > </ appender > < appender name="ADONetAppender" type="log4net.Appender.ADONetAppender"> <!--BufferSize为缓冲区大小,只有日志记录超1条才会一块写入到数据库--> < bufferSize value="1"/> < connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/> < connectionString value="Data Source=****;Initial Catalog=***;Persist Security Info=True;User ID=sa;Password=***;MultipleActiveResultSets=True"/> < commandText value="INSERT INTO edu_log (Date,Thread,Level,Logger,Message,SchoolID,SysTypeID) values(@log_date,@thread,@log_level,@logger,@content,@s_id,@t_id)"/> < parameter > < parameterName value="@log_date" /> < dbType value="DateTime" /> < layout type="log4net.Layout.RawTimeStampLayout" /> </ parameter > < parameter > < parameterName value="@thread" /> < dbType value="String" /> < size value="255" /> < layout type="log4net.Layout.PatternLayout"> < conversionPattern value="%thread" /> </ layout > </ parameter > < parameter > < parameterName value="@log_level" /> < dbType value="String" /> < size value="50" /> < layout type="log4net.Layout.PatternLayout"> < conversionPattern value="%level" /> </ layout > </ parameter > < parameter > < parameterName value="@logger" /> < dbType value="String" /> < size value="255" /> < layout type="log4net.Layout.PatternLayout"> < conversionPattern value="%logger" /> </ layout > </ parameter > < parameter > < parameterName value="@content" /> < dbType value="String" /> < size value="4000" /> < layout type="FuNong.Framework.Logger.CustomLayout"> < conversionPattern value="%property{content}" /> </ layout > </ parameter > < parameter > < parameterName value="@s_id" /> < dbType value="String" /> < size value="50" /> < layout type="FuNong.Framework.Logger.CustomLayout"> < conversionPattern value="%property{s_id}" /> </ layout > </ parameter > < parameter > < parameterName value="@t_id" /> < dbType value="String" /> < size value="50" /> < layout type="FuNong.Framework.Logger.CustomLayout"> < conversionPattern value="%property{t_id}" /> </ layout > </ parameter > </ appender > </ log4net > |
注意上面配置代码中:log4net.Layout.PatternLayout 是log4net本身提供的配置模板,如果你有的字段需要用到其本身的模板字段的话,就可以使用。
还需要注意这段话: <conversionPattern value="%property{s_id}" />,它表明,我们将会利用log4net提供的已有的property转义模板来识别我们的字段。
但是如果你有自定义字段的话,你就需要自己写layout和converter了。在上面的配置文件中,content,s_id,t_id是我自定义的三个字段,如何让这三个字段也写入到数据库呢,我们一步一步来配置。
首先,需要将三个自定义字段放到一个entity类中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | namespace FuNong.Framework.Logger { public class LogContent { public LogContent( string content, string s_id, string t_id) { this .content = content; this .s_id = s_id; this .t_id = t_id; } public string content { get ; set ; } public string s_id { get ; set ; } public string t_id { get ; set ; } } } |
然后,定义我们自己的layout,由于我们使用了property字段模板,所以我们这里需要按照如下方式添加:
1 2 3 4 5 6 7 8 9 10 | namespace FuNong.Framework.Logger { public class CustomLayout:PatternLayout { public CustomLayout() { this .AddConverter( "property" , typeof (XPatternConverter)); } } } |
最后,就是我们的Converter实现了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | namespace FuNong.Framework.Logger { public class XPatternConverter : PatternLayoutConverter { protected override void Convert(System.IO.TextWriter writer, log4net.Core.LoggingEvent loggingEvent) { if ( this .Option != null ) { // Write the value for the specified key WriteObject(writer, loggingEvent.Repository, LookupProperty(Option, loggingEvent)); } else { // Write all the key value pairs WriteDictionary(writer, loggingEvent.Repository, loggingEvent.GetProperties()); } } /// <summary> /// 通过反射获取传入的日志对象的某个属性的值 /// </summary> /// <param name="property"></param> /// <returns></returns> private Object LookupProperty(String property, log4net.Core.LoggingEvent loggingEvent) { Object propertyValue = String.Empty; PropertyInfo propertyInfo; propertyInfo = loggingEvent.MessageObject.GetType().GetProperty(property); if (propertyInfo != null ) { propertyValue = propertyInfo.GetValue(loggingEvent.MessageObject, null ); } return propertyValue; } } } |
从上面代码,我们可以看到,log4net会通过反射来识别我们logContent这个entity中的字段,然后逐个赋值,再写到数据库的。
下面我们稍微包装一下:
1 2 3 4 5 6 7 8 9 10 11 | namespace FuNong.Framework.Logger { public interface ILoggerService { void Debug( object message); void Error( object message); void Fatal( object message); void Info( object message); void Warn( object message); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | namespace FuNong.Framework.Logger { public class LoggerService:ILoggerService { public LoggerService() { log4net.Config.XmlConfigurator.Configure(); logger = LogManager.GetLogger( typeof (LoggerService)); } private readonly ILog logger; public void Info( object message) { logger.Info(message); } public void Warn( object message) { logger.Warn(message); } public void Debug( object message) { logger.Debug(message); } public void Error( object message) { logger.Error(message); } public void Fatal( object message) { logger.Fatal(message); } } } |
由于我用了autofac做ioc,所以我们就直接看使用方法吧:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | protected override void OnAuthorization(AuthorizationContext filterContext) { if (auth) { var collection = cookie.GetCookieCollection( "FuNong.UserInfo.Login" ); if (collection == null ) { logger.Warn( new LogContent( "用户登陆信息提取失败,将会跳转到登陆界面..." , "1" , "2" )); filterContext.Result = new RedirectResult( "Home/Login" ); } else { logger.Info( new LogContent( "用户验证成功,请继续之前操作..." , "1" , "2" )); } } } |
这样,当我们运行起来后,我们就发现,程序已经将数据写入数据库了。
整个配置不难,但是细节挺多,稍微不小心,就可能导致写入不到数据库。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步