.net 日志系統(tǒng)解析
一. 寫在前面
日志系統(tǒng)對(duì)于任何項(xiàng)目都是必不可少的,無(wú)論對(duì)于測(cè)試階段的debug,性能測(cè)試,執(zhí)行時(shí)間,操作記錄還是線上的問(wèn)題排查,訪問(wèn)記錄等,日志系統(tǒng)都扮演著重要的角色。本篇分享的目的是能幫助需要的人快速搭建自己的LogSystem.,僅供參考。 先上個(gè)圖唄,自認(rèn)為頁(yè)面還算清爽吧:
我的LogSystem使用Log4net入庫(kù)的方式,網(wǎng)上特別多的分享,但是能完整運(yùn)行下來(lái)的真是很少,所以現(xiàn)在需要和以后用得上的小伙伴抓緊收藏咯。
二. Log4Net自定義內(nèi)容入庫(kù)
Log4Net存日志的方式,給人的感覺(jué)實(shí)在是不實(shí)用,IT行業(yè)不都求一個(gè)自動(dòng)化嗎?廢話不說(shuō)了,先上Log4net入庫(kù)系統(tǒng)的代碼。
LogSystem數(shù)據(jù)庫(kù)結(jié)構(gòu),我的建議是一個(gè)項(xiàng)目一個(gè)表。
在Log組件中,你需要這樣幾個(gè)類。下面分別給出代碼:
LogContent.cs,這里定義了Log實(shí)體,在實(shí)體化實(shí)體的時(shí)候,通過(guò)給構(gòu)造函數(shù)傳參創(chuàng)建好這個(gè)對(duì)象。注釋很詳細(xì)了
using System; namespace LogComponent { public class LogContent { public LogContent(string logLevel, string logMsg, string logModule, string description, string userName) { LogLevel = logLevel; UserName = userName; Description = description; LogMsg = logMsg; LogModule = logModule; } /// <summary> /// 日志級(jí)別 /// </summary> public string LogLevel { get; set; } /// <summary> /// 日志消息 /// </summary> public string LogMsg { get; set; } /// <summary> /// 系統(tǒng)登陸用戶 /// </summary> public string UserName { get; set; } /// <summary> /// 日志描述信息 /// </summary> public string Description { get; set; } /// <summary> /// 記錄時(shí)間 /// </summary> public DateTime LogDate { get; set; } /// <summary> /// 模塊名稱 /// </summary> public string LogModule { get; set; } } }
LogHelper.cs,定義了日志級(jí)別,和寫入方法
[assembly: log4net.Config.XmlConfigurator(Watch = true,ConfigFile = "log4net.config")] namespace LogComponent { public class LogHelper { static log4net.ILog log = log4net.LogManager.GetLogger("myLogger"); /// <summary> /// 異常日志 /// </summary> /// <param name="logMsg">日志信息</param> /// <param name="logModule">代碼模塊</param> /// <param name="description">其他描述</param> /// <param name="userName">用戶名</param> public static void LogError(string logMsg, string logModule, string description = "", string userName = "") { log.Error(new LogContent("Error", SubLogString(logMsg), logModule, SubLogString(description), userName)); } public static void LogInfo(string logMsg, string logModule, string description = "", string userName = "") { log.Info(new LogContent("Info", SubLogString(logMsg), logModule, SubLogString(description), userName)); } public static void LogWarn(string logMsg, string logModule, string description = "", string userName = "") { log.Warn(new LogContent("Warn", SubLogString(logMsg), logModule, SubLogString(description), userName)); } public static void LogDebug(string logMsg, string logModule, string description = "", string userName = "") { log.Debug(new LogContent("Debug", SubLogString(logMsg), logModule, SubLogString(description), userName)); } private static string SubLogString(string str) { if (str.Length > 1500) { return str.Substring(0, 1500); } return str; } } }
MessagePartternConverter.cs
using log4net.Core; using log4net.Layout.Pattern; using System.IO; using System.Reflection; namespace LogComponent { class MessagePatternConverter : PatternLayoutConverter { protected override void Convert(TextWriter writer, LoggingEvent loggingEvent) { if (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> /// 通過(guò)反射獲取傳入的日志對(duì)象的某個(gè)屬性的值 /// </summary> /// <param name="property"></param> /// <returns></returns> private object LookupProperty(string property, log4net.Core.LoggingEvent loggingEvent) { object propertyValue = string.Empty; PropertyInfo propertyInfo = loggingEvent.MessageObject.GetType().GetProperty(property); if (propertyInfo != null) propertyValue = propertyInfo.GetValue(loggingEvent.MessageObject, null); return propertyValue; } } }
MyLayout.cs
using log4net.Layout; namespace LogComponent { class MyLayout : PatternLayout { public MyLayout() { this.AddConverter("property", typeof(MessagePatternConverter)); } } }
其實(shí)看到這里,最重要的并不是代碼了,核心部分Log4net都幫我們寫好了,關(guān)鍵在于你的配置,下面是log4net.config的內(nèi)容。拿到你的web項(xiàng)目里是一樣用的。但是不要忘了在你的項(xiàng)目中引用nuget:log4net喲。
log4net.config如下:在其中主要配置了log入庫(kù)的參數(shù)和sql語(yǔ)句,當(dāng)然還有sql連接。注釋已經(jīng)很詳細(xì)了
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/> </configSections> <log4net> <root > <level value="Debug"/> <appender-ref ref="ADONetAppender"/> </root> <logger name="myLogger"> <level value="Debug"/> <appender-ref ref="ADONetAppender"/> </logger> <appender name="ADONetAppender" type="log4net.Appender.ADONetAppender,log4net"> <!--BufferSize為緩沖區(qū)大小,只有日志記錄超value條才會(huì)一塊寫入到數(shù)據(jù)庫(kù)--> <bufferSize value="1"/> <!--或?qū)憺?lt;param name="BufferSize" value="1" />--> <!--引用--> <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/> <!--連接數(shù)據(jù)庫(kù)字符串--> <connectionString value="Data Source=115.29.54.31;Initial Catalog=LogSystem;uid=sa;pwd=sa.;MultipleActiveResultSets=True"/> <!--插入到表Log--> <commandText value="INSERT INTO HdPubLog ([LogDate],[LogMsg],[UserName],[Description],[LogLevel],[LogModule]) VALUES (@log_date,@LogMsg,@UserName,@Description,@LogLevel,@LogModule)"/> <parameter> <parameterName value="@log_date"/> <dbType value="DateTime"/> <layout type="log4net.Layout.RawTimeStampLayout"/> <!--獲取log4net中提供的日志時(shí)間RawTimeStampLayout為默認(rèn)的時(shí)間輸出格式--> </parameter> <parameter> <parameterName value="@LogMsg"/> <dbType value="String"/> <size value="1510"/> <layout type="LogComponent.MyLayout, LogComponent"> <param name="ConversionPattern" value="%property{LogMsg}"/> </layout> </parameter> <parameter> <parameterName value="@UserName"/> <dbType value="String"/> <size value="50"/> <layout type="LogComponent.MyLayout, LogComponent"> <param name="ConversionPattern" value="%property{UserName}"/> </layout> </parameter> <parameter> <parameterName value="@Description"/> <dbType value="String"/> <size value="1510"/> <layout type="LogComponent.MyLayout, LogComponent"> <param name="ConversionPattern" value="%property{Description}"/> </layout> </parameter> <parameter> <parameterName value="@LogLevel"/> <dbType value="String"/> <size value="50"/> <layout type="LogComponent.MyLayout, LogComponent"> <param name="ConversionPattern" value="%property{LogLevel}"/> </layout> </parameter> <parameter> <parameterName value="@LogModule"/> <dbType value="String"/> <size value="50"/> <layout type="LogComponent.MyLayout, LogComponent"> <param name="ConversionPattern" value="%property{LogModule}"/> </layout> </parameter> </appender> </log4net> </configuration>
這樣一來(lái),你的配置就完成了,你可以直接測(cè)試插入的情況:
三. 把Log信息可視化
我的UI使用的是Datatables.js,彈出框是layer,日期組件好像是layDate,下拉框是修改樣式后的select2。UI代碼是我自己的一個(gè)框架里的,內(nèi)容太多就不貼出來(lái)了,你只需要和以前一樣,把數(shù)據(jù)從庫(kù)里查出來(lái),綁定給任意你喜歡的數(shù)據(jù)表格上。由于單頁(yè)面的日志系統(tǒng)沒(méi)有什么復(fù)雜操作,就用個(gè)sqlHelper查一下就算了,代碼和條件拼接如下
public class xxxDal { private SqlHelper _sqlHelper = new SqlHelper(); /// <summary> /// 獲取xxx的日志 /// </summary> /// <param name="model"></param> /// <returns></returns> public List<LogModel> GetxxxLog(SM_LogModel model) { StringBuilder sql = new StringBuilder(); List<SqlParameter> sqlParameters = new List<SqlParameter>(); StringBuilder sqlWhere = new StringBuilder(); if (!string.IsNullOrWhiteSpace(model.LogStartTime)) { sqlParameters.Add(new SqlParameter("@LogStartTime", model.LogStartTime)); sqlWhere.Append(@" AND h.LogDate > @LogStartTime"); } if (!string.IsNullOrWhiteSpace(model.LogEndTime)) { sqlParameters.Add(new SqlParameter("@LogEndTime", model.LogEndTime)); sqlWhere.Append(@" AND h.LogDate < @LogEndTime"); } if (!string.IsNullOrWhiteSpace(model.LogLevel)) { sqlParameters.Add(new SqlParameter("@LogLevel", model.LogLevel)); sqlWhere.Append(@" AND h.LogLevel = @LogLevel"); } if (!string.IsNullOrWhiteSpace(model.LogModule)) { sqlParameters.Add(new SqlParameter("@LogModule", model.LogModule)); sqlWhere.Append(@" AND h.LogModule = @LogModule"); } sql.AppendFormat(@" WITH t AS ( SELECT ROW_NUMBER() OVER ( ORDER BY id DESC ) AS IndexNum , [Id] , CONVERT(VARCHAR, [LogDate], 21) AS [LogDate] , [UserName] , SUBSTRING([Description], 0, 150) AS [Description] , SUBSTRING([LogMsg], 0, 200) AS [LogMsg] , [LogLevel] , [LogModule] FROM [LogSystem].[dbo].[xxxLog] h WHERE 1 = 1 {0} ) SELECT * FROM t WHERE IndexNum > @startIndex AND indexnum < @endIndex", sqlWhere); sqlParameters.Add(new SqlParameter("@startIndex", model.Start)); sqlParameters.Add(new SqlParameter("@endIndex", model.Start + model.Length)); DataTable dt = _sqlHelper.ExecuteDataTable(sql.ToString(), sqlParameters.ToArray()); return DataTableTools<LogModel>.DataTableToList(dt); } public int GetxxxLogTotalCount(SM_LogModel model) { StringBuilder sql = new StringBuilder(); List<SqlParameter> sqlParameters = new List<SqlParameter>(); sql.Append(@" SELECT COUNT(*) FROM [HdPubLog] h where 1=1 "); if (!string.IsNullOrWhiteSpace(model.LogStartTime)) { sqlParameters.Add(new SqlParameter("@LogStartTime", model.LogStartTime)); sql.Append(@" AND h.LogDate > @LogStartTime"); } if (!string.IsNullOrWhiteSpace(model.LogEndTime)) { sqlParameters.Add(new SqlParameter("@LogEndTime", model.LogEndTime)); sql.Append(@" AND h.LogDate < @LogEndTime"); } if (!string.IsNullOrWhiteSpace(model.LogLevel)) { sqlParameters.Add(new SqlParameter("@LogLevel", model.LogLevel)); sql.Append(@" AND h.LogLevel = @LogLevel"); } if (!string.IsNullOrWhiteSpace(model.LogModule)) { sqlParameters.Add(new SqlParameter("@LogModule", model.LogModule)); sql.Append(@" AND h.LogModule = @LogModule"); } return _sqlHelper.ExecuteScalar<int>(sql.ToString(), sqlParameters.ToArray()); } [HttpPost] public LogModel GetxxxxSignelLog(int id) { string sql = @" SELECT [Id] , CONVERT(VARCHAR(30), [LogDate], 21) AS [LogDate] , [UserName] , [Description] , [LogMsg] , [LogLevel] , [LogModule] , [Id] IndexNum FROM [LogSystem].[dbo].[xxxxLog] h WHERE h.id = @Id"; var row = _sqlHelper.ExecuteDataRow(sql, new SqlParameter("@Id", id)); return DataTableTools<LogModel>.DataRowToModel(row); } }
以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,同時(shí)也希望多多支持腳本之家!
相關(guān)文章
ASP.NET MVC中解析淘寶網(wǎng)頁(yè)出現(xiàn)亂碼問(wèn)題的解決方法
最近在使用MVC解析淘寶網(wǎng)頁(yè)出現(xiàn)亂碼問(wèn)題,原因就是中文字符格式出現(xiàn)沖突,ASP.NET MVC 默認(rèn)采用utf-8,但是淘寶網(wǎng)頁(yè)采用gbk。在網(wǎng)上找了一下,最常用的解決方法,特分享下2013-04-04.NET5實(shí)現(xiàn)操作注冊(cè)表的方法
本文詳細(xì)講解了.NET5實(shí)現(xiàn)操作注冊(cè)表的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-02-02C#頁(yè)碼導(dǎo)航顯示及算法實(shí)現(xiàn)代碼
C#頁(yè)碼導(dǎo)航算法要求:頁(yè)數(shù)小于等于1時(shí)不顯示;頁(yè)數(shù)大于10時(shí),自動(dòng)縮短,需要的朋友可以了解下2012-12-12ASP.NET網(wǎng)站導(dǎo)航及導(dǎo)航控件如何使用
這篇文章主要介紹了ASP.NET網(wǎng)站導(dǎo)航及導(dǎo)航控件如何使用,需要的朋友可以參考下2015-09-09asp.net SqlHelper數(shù)據(jù)訪問(wèn)層的使用
如果不使用數(shù)據(jù)訪問(wèn)層,那么你的代碼里會(huì)出現(xiàn)很多SqlConnection、SqlCommand、SqlDataReader、Open、 Close……這些類和方法,而且代碼量很大,讓你不勝其煩,而且代碼寫起來(lái),其實(shí)都是體力活,沒(méi)有技術(shù)含量。2008-09-09.NET Core跨平臺(tái)串口通訊使用SerialPortStream基礎(chǔ)類庫(kù)問(wèn)題解決
這篇文章介紹了.NET Core跨平臺(tái)串口通訊使用SerialPortStream基礎(chǔ)類庫(kù)問(wèn)題解決,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-01-01