.net 日志系統(tǒng)解析
一. 寫在前面
日志系統(tǒng)對于任何項目都是必不可少的,無論對于測試階段的debug,性能測試,執(zhí)行時間,操作記錄還是線上的問題排查,訪問記錄等,日志系統(tǒng)都扮演著重要的角色。本篇分享的目的是能幫助需要的人快速搭建自己的LogSystem.,僅供參考。 先上個圖唄,自認為頁面還算清爽吧:
我的LogSystem使用Log4net入庫的方式,網(wǎng)上特別多的分享,但是能完整運行下來的真是很少,所以現(xiàn)在需要和以后用得上的小伙伴抓緊收藏咯。


二. Log4Net自定義內(nèi)容入庫
Log4Net存日志的方式,給人的感覺實在是不實用,IT行業(yè)不都求一個自動化嗎?廢話不說了,先上Log4net入庫系統(tǒng)的代碼。
LogSystem數(shù)據(jù)庫結(jié)構(gòu),我的建議是一個項目一個表。

在Log組件中,你需要這樣幾個類。下面分別給出代碼:

LogContent.cs,這里定義了Log實體,在實體化實體的時候,通過給構(gòu)造函數(shù)傳參創(chuàng)建好這個對象。注釋很詳細了
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>
/// 日志級別
/// </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>
/// 記錄時間
/// </summary>
public DateTime LogDate { get; set; }
/// <summary>
/// 模塊名稱
/// </summary>
public string LogModule { get; set; }
}
}
LogHelper.cs,定義了日志級別,和寫入方法
[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>
/// 通過反射獲取傳入的日志對象的某個屬性的值
/// </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));
}
}
}
其實看到這里,最重要的并不是代碼了,核心部分Log4net都幫我們寫好了,關(guān)鍵在于你的配置,下面是log4net.config的內(nèi)容。拿到你的web項目里是一樣用的。但是不要忘了在你的項目中引用nuget:log4net喲。

log4net.config如下:在其中主要配置了log入庫的參數(shù)和sql語句,當然還有sql連接。注釋已經(jīng)很詳細了
<?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條才會一塊寫入到數(shù)據(jù)庫-->
<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ù)庫字符串-->
<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中提供的日志時間RawTimeStampLayout為默認的時間輸出格式-->
</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>
這樣一來,你的配置就完成了,你可以直接測試插入的情況:

三. 把Log信息可視化
我的UI使用的是Datatables.js,彈出框是layer,日期組件好像是layDate,下拉框是修改樣式后的select2。UI代碼是我自己的一個框架里的,內(nèi)容太多就不貼出來了,你只需要和以前一樣,把數(shù)據(jù)從庫里查出來,綁定給任意你喜歡的數(shù)據(jù)表格上。由于單頁面的日志系統(tǒng)沒有什么復雜操作,就用個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);
}
}
以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對大家的學習或者工作能帶來一定的幫助,同時也希望多多支持腳本之家!
相關(guān)文章
ASP.NET MVC中解析淘寶網(wǎng)頁出現(xiàn)亂碼問題的解決方法
最近在使用MVC解析淘寶網(wǎng)頁出現(xiàn)亂碼問題,原因就是中文字符格式出現(xiàn)沖突,ASP.NET MVC 默認采用utf-8,但是淘寶網(wǎng)頁采用gbk。在網(wǎng)上找了一下,最常用的解決方法,特分享下2013-04-04
asp.net SqlHelper數(shù)據(jù)訪問層的使用
如果不使用數(shù)據(jù)訪問層,那么你的代碼里會出現(xiàn)很多SqlConnection、SqlCommand、SqlDataReader、Open、 Close……這些類和方法,而且代碼量很大,讓你不勝其煩,而且代碼寫起來,其實都是體力活,沒有技術(shù)含量。2008-09-09
.NET Core跨平臺串口通訊使用SerialPortStream基礎(chǔ)類庫問題解決
這篇文章介紹了.NET Core跨平臺串口通訊使用SerialPortStream基礎(chǔ)類庫問題解決,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-01-01

