I. Write in front
This paper introduces the basic way, large data volume production environment can not be used, medium log volume please log single library. Hope you love technology and don't miss exceptionless and ELK. Of course, you can also use nosql + search technology.
Logging system is indispensable for any project. It plays an important role in debug, performance test, execution time, operation record, online problem checking, access record and so on. The purpose of this article is to help people in need to quickly build their own Log System. For reference only. First of all, I think the page is refreshing.
My Log System uses Log4net to store, and there is a lot of sharing on the internet, but few of them can run completely, so now we need to collect them with our little friends who can be used in the future.
2. Log4Net Custom Content Storage
Log4Net logs, the way people feel is not practical, the IT industry does not require an automation? Don't talk nonsense. Go to the code of Log4net storage system first.
LogSystem database structure, my recommendation is a project, a table.
In the Log component, you need these classes. The following code is given separately:
LogContent.cs, which defines the Log entity, creates the object by passing parameters to the constructor when it materializes the entity. The notes are very detailed.
1 using System; 2 3 namespace LogComponent 4 { 5 public class LogContent 6 { 7 8 public LogContent(string logLevel, string logMsg, string logModule, string description, string userName) 9 { 10 LogLevel = logLevel; 11 UserName = userName; 12 Description = description; 13 LogMsg = logMsg; 14 LogModule = logModule; 15 } 16 17 /// <summary> 18 /// log level 19 /// </summary> 20 public string LogLevel { get; set; } 21 22 /// <summary> 23 /// Log message 24 /// </summary> 25 public string LogMsg { get; set; } 26 27 /// <summary> 28 /// System login users 29 /// </summary> 30 public string UserName { get; set; } 31 32 /// <summary> 33 /// Log Description Information 34 /// </summary> 35 public string Description { get; set; } 36 37 /// <summary> 38 /// Recording time 39 /// </summary> 40 public DateTime LogDate { get; set; } 41 42 /// <summary> 43 /// Module name 44 /// </summary> 45 public string LogModule { get; set; } 46 } 47 }
LogHelper.cs, which defines log level and write method
1 [assembly: log4net.Config.XmlConfigurator(Watch = true,ConfigFile = "log4net.config")] 2 namespace LogComponent 3 { 4 public class LogHelper 5 { 6 static log4net.ILog log = log4net.LogManager.GetLogger("myLogger"); 7 8 /// <summary> 9 /// Abnormal log 10 /// </summary> 11 /// <param name="logMsg">log information</param> 12 /// <param name="logModule">Code module</param> 13 /// <param name="description">Other description</param> 14 /// <param name="userName">User name</param> 15 public static void LogError(string logMsg, string logModule, string description = "", string userName = "") 16 { 17 log.Error(new LogContent("Error", SubLogString(logMsg), logModule, SubLogString(description), userName)); 18 } 19 20 public static void LogInfo(string logMsg, string logModule, string description = "", string userName = "") 21 { 22 log.Info(new LogContent("Info", SubLogString(logMsg), logModule, SubLogString(description), userName)); 23 } 24 25 public static void LogWarn(string logMsg, string logModule, string description = "", string userName = "") 26 { 27 log.Warn(new LogContent("Warn", SubLogString(logMsg), logModule, SubLogString(description), userName)); 28 } 29 30 public static void LogDebug(string logMsg, string logModule, string description = "", string userName = "") 31 { 32 log.Debug(new LogContent("Debug", SubLogString(logMsg), logModule, SubLogString(description), userName)); 33 } 34 35 private static string SubLogString(string str) 36 { 37 if (str.Length > 1500) 38 { 39 return str.Substring(0, 1500); 40 } 41 return str; 42 } 43 } 44 }
MessagePartternConverter.cs
1 using log4net.Core; 2 using log4net.Layout.Pattern; 3 using System.IO; 4 using System.Reflection; 5 namespace LogComponent 6 { 7 class MessagePatternConverter : PatternLayoutConverter 8 { 9 protected override void Convert(TextWriter writer, LoggingEvent loggingEvent) 10 { 11 if (Option != null) 12 { 13 // Write the value for the specified key 14 WriteObject(writer, loggingEvent.Repository, LookupProperty(Option, loggingEvent)); 15 } 16 else 17 { 18 // Write all the key value pairs 19 WriteDictionary(writer, loggingEvent.Repository, loggingEvent.GetProperties()); 20 } 21 } 22 /// <summary> 23 /// Getting the value of an attribute of the incoming log object by reflection 24 /// </summary> 25 /// <param name="property"></param> 26 /// <returns></returns> 27 private object LookupProperty(string property, log4net.Core.LoggingEvent loggingEvent) 28 { 29 object propertyValue = string.Empty; 30 PropertyInfo propertyInfo = loggingEvent.MessageObject.GetType().GetProperty(property); 31 if (propertyInfo != null) 32 propertyValue = propertyInfo.GetValue(loggingEvent.MessageObject, null); 33 return propertyValue; 34 } 35 } 36 }
MyLayout.cs
1 using log4net.Layout; 2 namespace LogComponent 3 { 4 class MyLayout : PatternLayout 5 { 6 public MyLayout() 7 { 8 this.AddConverter("property", typeof(MessagePatternConverter)); 9 } 10 } 11 }
Actually, the most important thing is not the code. The core part of Log4net is written for us. The key is your configuration. Here is the content of log4net.config. It's just as useful to get your web project. But don't forget to refer to nuget: log4net in your project.
log4net.config is as follows: in which the main configuration log into the library parameters and sql statements, of course, there are sql connections. The annotations are very detailed.
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 <configSections> 4 <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/> 5 </configSections> 6 <log4net> 7 <root > 8 <level value="Debug"/> 9 <appender-ref ref="ADONetAppender"/> 10 </root> 11 <logger name="myLogger"> 12 <level value="Debug"/> 13 <appender-ref ref="ADONetAppender"/> 14 </logger> 15 <appender name="ADONetAppender" type="log4net.Appender.ADONetAppender,log4net"> 16 <!--BufferSize For buffer size, only log super value Only one bar is written to the database.--> 17 <bufferSize value="1"/> 18 <!--Or written as<param name="BufferSize" value="1" />--> 19 <!--Quote--> 20 <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/> 21 <!--Connect database string--> 22 <connectionString value="Data Source=115.29.54.31;Initial Catalog=LogSystem;uid=sa;pwd=sa.;MultipleActiveResultSets=True"/> 23 <!--Insert to table Log--> 24 <commandText value="INSERT INTO HdPubLog ([LogDate],[LogMsg],[UserName],[Description],[LogLevel],[LogModule]) VALUES (@log_date,@LogMsg,@UserName,@Description,@LogLevel,@LogModule)"/> 25 <parameter> 26 <parameterName value="@log_date"/> 27 <dbType value="DateTime"/> 28 <layout type="log4net.Layout.RawTimeStampLayout"/> 29 <!--Obtain log4net The log time provided in RawTimeStampLayout Output format for default time--> 30 </parameter> 31 <parameter> 32 <parameterName value="@LogMsg"/> 33 <dbType value="String"/> 34 <size value="1510"/> 35 <layout type="LogComponent.MyLayout, LogComponent"> 36 <param name="ConversionPattern" value="%property{LogMsg}"/> 37 </layout> 38 </parameter> 39 <parameter> 40 <parameterName value="@UserName"/> 41 <dbType value="String"/> 42 <size value="50"/> 43 <layout type="LogComponent.MyLayout, LogComponent"> 44 <param name="ConversionPattern" value="%property{UserName}"/> 45 </layout> 46 </parameter> 47 <parameter> 48 <parameterName value="@Description"/> 49 <dbType value="String"/> 50 <size value="1510"/> 51 <layout type="LogComponent.MyLayout, LogComponent"> 52 <param name="ConversionPattern" value="%property{Description}"/> 53 </layout> 54 </parameter> 55 <parameter> 56 <parameterName value="@LogLevel"/> 57 <dbType value="String"/> 58 <size value="50"/> 59 <layout type="LogComponent.MyLayout, LogComponent"> 60 <param name="ConversionPattern" value="%property{LogLevel}"/> 61 </layout> 62 </parameter> 63 <parameter> 64 <parameterName value="@LogModule"/> 65 <dbType value="String"/> 66 <size value="50"/> 67 <layout type="LogComponent.MyLayout, LogComponent"> 68 <param name="ConversionPattern" value="%property{LogModule}"/> 69 </layout> 70 </parameter> 71 </appender> 72 </log4net> 73 </configuration>
In this way, your configuration is complete and you can test the insertion directly:
3. Visualizing Log Information
My UI uses Datatables.js, the pop-up box is layer, the date component is like layDate, and the drop-down box is select2 after modifying the style. UI code is a framework of my own, too much content will not be posted out, you just need to look up the data from the library, as before, bound to any data table you like. Since the single page log system has no complicated operation, just check it with sqlHelper. The code and conditions are mosaic as follows
1 public class xxxDal 2 { 3 private SqlHelper _sqlHelper = new SqlHelper(); 4 5 /// <summary> 6 /// Obtain xxx Log 7 /// </summary> 8 /// <param name="model"></param> 9 /// <returns></returns> 10 public List<LogModel> GetxxxLog(SM_LogModel model) 11 { 12 StringBuilder sql = new StringBuilder(); 13 List<SqlParameter> sqlParameters = new List<SqlParameter>(); 14 StringBuilder sqlWhere = new StringBuilder(); 15 if (!string.IsNullOrWhiteSpace(model.LogStartTime)) 16 { 17 sqlParameters.Add(new SqlParameter("@LogStartTime", model.LogStartTime)); 18 sqlWhere.Append(@" AND h.LogDate > @LogStartTime"); 19 } 20 if (!string.IsNullOrWhiteSpace(model.LogEndTime)) 21 { 22 sqlParameters.Add(new SqlParameter("@LogEndTime", model.LogEndTime)); 23 sqlWhere.Append(@" AND h.LogDate < @LogEndTime"); 24 } 25 if (!string.IsNullOrWhiteSpace(model.LogLevel)) 26 { 27 sqlParameters.Add(new SqlParameter("@LogLevel", model.LogLevel)); 28 sqlWhere.Append(@" AND h.LogLevel = @LogLevel"); 29 } 30 if (!string.IsNullOrWhiteSpace(model.LogModule)) 31 { 32 sqlParameters.Add(new SqlParameter("@LogModule", model.LogModule)); 33 sqlWhere.Append(@" AND h.LogModule = @LogModule"); 34 } 35 sql.AppendFormat(@" 36 WITH t AS ( SELECT ROW_NUMBER() OVER ( ORDER BY id DESC ) AS IndexNum , 37 [Id] , 38 CONVERT(VARCHAR, [LogDate], 21) AS [LogDate] , 39 [UserName] , 40 SUBSTRING([Description], 0, 150) AS [Description] , 41 SUBSTRING([LogMsg], 0, 200) AS [LogMsg] , 42 [LogLevel] , 43 [LogModule] 44 FROM [LogSystem].[dbo].[xxxLog] h 45 WHERE 1 = 1 46 {0} 47 ) 48 SELECT * 49 FROM t 50 WHERE IndexNum > @startIndex 51 AND indexnum < @endIndex", sqlWhere); 52 sqlParameters.Add(new SqlParameter("@startIndex", model.Start)); 53 sqlParameters.Add(new SqlParameter("@endIndex", model.Start + model.Length)); 54 55 DataTable dt = _sqlHelper.ExecuteDataTable(sql.ToString(), sqlParameters.ToArray()); 56 return DataTableTools<LogModel>.DataTableToList(dt); 57 } 58 59 public int GetxxxLogTotalCount(SM_LogModel model) 60 { 61 StringBuilder sql = new StringBuilder(); List<SqlParameter> sqlParameters = new List<SqlParameter>(); 62 sql.Append(@" 63 SELECT COUNT(*) 64 FROM [HdPubLog] h where 1=1 "); 65 if (!string.IsNullOrWhiteSpace(model.LogStartTime)) 66 { 67 sqlParameters.Add(new SqlParameter("@LogStartTime", model.LogStartTime)); 68 sql.Append(@" AND h.LogDate > @LogStartTime"); 69 } 70 if (!string.IsNullOrWhiteSpace(model.LogEndTime)) 71 { 72 sqlParameters.Add(new SqlParameter("@LogEndTime", model.LogEndTime)); 73 sql.Append(@" AND h.LogDate < @LogEndTime"); 74 } 75 if (!string.IsNullOrWhiteSpace(model.LogLevel)) 76 { 77 sqlParameters.Add(new SqlParameter("@LogLevel", model.LogLevel)); 78 sql.Append(@" AND h.LogLevel = @LogLevel"); 79 } 80 if (!string.IsNullOrWhiteSpace(model.LogModule)) 81 { 82 sqlParameters.Add(new SqlParameter("@LogModule", model.LogModule)); 83 sql.Append(@" AND h.LogModule = @LogModule"); 84 } 85 return _sqlHelper.ExecuteScalar<int>(sql.ToString(), sqlParameters.ToArray()); 86 } 87 88 [HttpPost] 89 public LogModel GetxxxxSignelLog(int id) 90 { 91 string sql = @" 92 SELECT [Id] , 93 CONVERT(VARCHAR(30), [LogDate], 21) AS [LogDate] , 94 [UserName] , 95 [Description] , 96 [LogMsg] , 97 [LogLevel] , 98 [LogModule] , 99 [Id] IndexNum 100 FROM [LogSystem].[dbo].[xxxxLog] h 101 WHERE h.id = @Id"; 102 var row = _sqlHelper.ExecuteDataRow(sql, new SqlParameter("@Id", id)); 103 return DataTableTools<LogModel>.DataRowToModel(row); 104 } 105 }
IV. Write at the end
Keep learning and remember modesty. It's funny and dreamy.