一.   写在前面

本文Log4Net介绍了基础的方式,大数据量生产环境不能使用,中等日志量请日志单库。 希望爱技术的你不要错过exceptionless和ELK

第四节开始简单配置大牛们推荐的了ExceptionLess, 一款开源分布式日志系统。

日志系统对于任何项目都是必不可少的,无论对于测试阶段的debug,性能测试,执行时间,操作记录还是线上的问题排查,访问记录等,日志系统都扮演着重要的角色。本篇分享的目的是能帮助需要的人快速搭建自己的LogSystem.,仅供参考。 先上个图呗,自认为页面还算清爽吧:

我的LogSystem使用Log4net入库的方式,网上特别多的分享,但是能完整运行下来的真是很少,所以现在需要和以后用得上的小伙伴抓紧收藏咯。

二.  Log4Net自定义内容入库

Log4Net存日志的方式,给人的感觉实在是不实用,IT行业不都求一个自动化吗?废话不说了,先上Log4net入库系统的代码。

LogSystem数据库结构,我的建议是一个项目一个表。

在Log组件中,你需要这样几个类。下面分别给出代码:

LogContent.cs,这里定义了Log实体,在实体化实体的时候,通过给构造函数传参创建好这个对象。注释很详细了

 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 /// 日志级别
19 /// </summary>
20 public string LogLevel { get; set; }
21
22 /// <summary>
23 /// 日志消息
24 /// </summary>
25 public string LogMsg { get; set; }
26
27 /// <summary>
28 /// 系统登陆用户
29 /// </summary>
30 public string UserName { get; set; }
31
32 /// <summary>
33 /// 日志描述信息
34 /// </summary>
35 public string Description { get; set; }
36
37 /// <summary>
38 /// 记录时间
39 /// </summary>
40 public DateTime LogDate { get; set; }
41
42 /// <summary>
43 /// 模块名称
44 /// </summary>
45 public string LogModule { get; set; }
46 }
47 }

LogHelper.cs,定义了日志级别,和写入方法

 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 /// 异常日志
10 /// </summary>
11 /// <param name="logMsg">日志信息</param>
12 /// <param name="logModule">代码模块</param>
13 /// <param name="description">其他描述</param>
14 /// <param name="userName">用户名</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 /// 通过反射获取传入的日志对象的某个属性的值
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 }

其实看到这里,最重要的并不是代码了,核心部分Log4net都帮我们写好了,关键在于你的配置,下面是log4net.config的内容。拿到你的web项目里是一样用的。但是不要忘了在你的项目中引用nuget:log4net哟。

log4net.config如下:在其中主要配置了log入库的参数和sql语句,当然还有sql连接。注释已经很详细了

 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为缓冲区大小,只有日志记录超value条才会一块写入到数据库-->
17 <bufferSize value="1"/>
18 <!--或写为<param name="BufferSize" value="1" />-->
19 <!--引用-->
20 <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
21 <!--连接数据库字符串-->
22 <connectionString value="Data Source=115.29.54.31;Initial Catalog=LogSystem;uid=sa;pwd=sa.;MultipleActiveResultSets=True"/>
23 <!--插入到表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 <!--获取log4net中提供的日志时间RawTimeStampLayout为默认的时间输出格式-->
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>

这样一来,你的配置就完成了,你可以直接测试插入的情况:

三.   把Log信息可视化

我的UI使用的是Datatables.js,弹出框是layer,日期组件好像是layDate,下拉框是修改样式后的select2。UI代码是我自己的一个框架里的,内容太多就不贴出来了,你只需要和以前一样,把数据从库里查出来,绑定给任意你喜欢的数据表格上。由于单页面的日志系统没有什么复杂操作,就用个sqlHelper查一下就算了,代码和条件拼接如下

  1 public class xxxDal
2 {
3 private SqlHelper _sqlHelper = new SqlHelper();
4
5 /// <summary>
6 /// 获取xxx的日志
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 }

话说到这,Log4Net数据库日志系统已经完成。

四.  更好的方式—— ExceptionLess本地部署

还是先上个本地部署图:

部署的过程中,参考了官方文档和一位园友的文章。

http://www.cnblogs.com/savorboard/p/exceptionless.html

http://www.cnblogs.com/uptothesky/p/5864863.html

https://github.com/exceptionless/Exceptionless/wiki/Self-Hosting

实际上参照着参考文档的Production配置文档,把Java环境配置好,然后装好ES服务并启动. 你的self hosting基本都不会有问题。

五.   写在最后

不准备给自己搭建一个LogSystem吗?如果用得上抓紧收藏吧。有疑问欢迎留言。

统一日志系统 Log4Net/ExceptionLess的更多相关文章

  1. 磨刀不误砍柴工——统一日志系统 Log4Net/ExceptionLess

    本文版权归博客园和作者吴双本人共同所有,转载和爬虫必须注明原文地址:www.cnblogs.com/tdws . 一.   写在前面 本文Log4Net介绍了基础的方式,大数据量生产环境不能使用,中等 ...

  2. ELK统一日志系统的应用

    收集和分析日志是应用开发中至关重要的一环,互联网大规模.分布式的特性决定了日志的源头越来越分散, 产生的速度越来越快,传统的手段和工具显得日益力不从心.在规模化场景下,grep.awk 无法快速发挥作 ...

  3. 2.1 自定义日志系统-log4net

    说明 Prism中如果把日志级别设定为DEBUG,会显示框架加载信息 Prism默认是没有日志系统的 步骤 下载log4net包 Install-Package log4net; 在app.confi ...

  4. C# 日志系统 log4net 配置及使用

    1.引用Dll 版本是:1.2.10.0,下载Dll 2.Web.config文件配置 <?xml version="1.0" encoding="utf-8&qu ...

  5. ELK+FileBeat+Log4Net搭建日志系统

    ELK+FileBeat+Log4Net搭建日志系统 来源:https://www.zybuluo.com/muyanfeixiang/note/608470 标签(空格分隔): ELK Log4Ne ...

  6. .NET下日志系统的搭建——log4net+kafka+elk

    .NET下日志系统的搭建--log4net+kafka+elk 前言     我们公司的程序日志之前都是采用log4net记录文件日志的方式(有关log4net的简单使用可以看我另一篇博客),但是随着 ...

  7. 面试题:应用中很多jar包,比如spring、mybatis、redis等等,各自用的日志系统各异,怎么用slf4j统一输出?(上)

    一.问题概述 如题所说,后端应用(非spring boot项目)通常用到了很多jar包,比如spring系列.mybatis.hibernate.各类连接数据库的客户端的jar包.可能这个jar包用的 ...

  8. 【5】基于Log4Net的日志系统

    阅读目录 日志系统应具备的特性  Log4Net 配置文件:log4net.config 初始化 输出信息 对Log4Net的封装 log4net.config复杂配置   不管是Web应用程序还是W ...

  9. 统一日志监控系统 springboot websocket 简单版 王代军-作品

    http://git.oschina.net/redArmy/springboot-websocket-logs 目的: 统一监控 开发测试环境日志 如果需要可以拓展线上环境的日志(自己视情况而定) ...

随机推荐

  1. 基于傅里叶变换的音频重采样算法 (附完整c代码)

    前面有提到音频采样算法: WebRTC 音频采样算法 附完整C++示例代码 简洁明了的插值音频重采样算法例子 (附完整C代码) 近段时间有不少朋友给我写过邮件,说了一些他们使用的情况和问题. 坦白讲, ...

  2. VS2005源代码视图出现了小蓝点,怎么弄掉?

    VS2005源代码视图出现了小蓝点,怎么弄掉? 编辑->高级->查看空白行 就OK啦~ 这个查看空格的.. 或者Ctrl+E,S

  3. android stadio 编译报错:download fastutil-7.2.0.jar

    在Ubuntu上面,新安装的stadio,第一次编译项目的时候, 一直开在下载 fastutil-7.2.0.jar 原因是需要FQ.那么改一下你的buil.gradle buildscript { ...

  4. MySQL高级-慢查询日志

    一.慢查询日志是什么 1. 2. 3. 2.开启了慢查询日志后,什么样的SQL才会记录到慢查询日志里面呢? 3.案例 1.查看当前多少秒算慢 2.设置慢的阙值时间 3.为什么设置后看不出变化? 4.记 ...

  5. jQuery wordexport导出 word

    同事给我说了简单的导出word的插件,亲测了下,做个随笔. 这个导出插件是jQuery自带的的插件,通过调用wordexport.js来实现导出功能. 1.引入的js <script type= ...

  6. libevent学习三(Getting an event_base)

    1.一个event_base持有了一系列的事件,并监控和决定哪些事件需要激活, 2.每一个event_base背后都有一个支持其工作的方法(诸如select,poll,epoll,kquene...) ...

  7. pygame安装【在pycharm的IDE project下】

    pygame安装[在pycharm的IDE project下] 首先更新电脑的pip.exe[命令行下面] 然后进入IDE project ——>setting 中查找是否安装pygame 我的 ...

  8. VIN码识别/车架号OCR识别:快速占领汽车后市场数据入口

    大数据时代,企业在数据入口方面的竞争越来越激烈,这种对于入口级的大数据“争夺战”,让很多企业在数据挖掘和收集的技术方面开始加快更新速度. 在当前IT行业激烈竞争环境之下,对于入口产品的控制成为了大数据 ...

  9. Qt-第一个QML程序-3-自定义一个按钮

    项目基本信息前两个已经说了,这里直接放下运行截图, 对的,这里就是说上面的那个红色的按钮,这里需要了解Qml的动画和状态 这里先把整个按钮的代码写出来,一点一点写 Rectangle { id:clo ...

  10. 微信小程序如何性能测试?

    背景: 微信小程序作为手机页面的一种,相比传统的网站和应用来说存在比较特殊的地方: 1.  开发者往往对程序做了限制,只能通过微信客户端访问 2.  通过微信的Oauth进行认证 这样往往会导致我们的 ...