本文版权归博客园和作者吴双本人共同所有,转载和爬虫必须注明原文地址:www.cnblogs.com/tdws 。

一.   写在前面

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

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

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

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

二.  Log4Net自定义内容入库

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

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

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

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

 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>
/// 系统登陆用户
/// </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 > )
{
return str.Substring(, );
}
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都帮我们写好了,关键在于你的配置,下面是log4net.config的内容。拿到你的web项目里是一样用的。但是不要忘了在你的项目中引用nuget:log4net哟。

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

 <?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为缓冲区大小,只有日志记录超value条才会一块写入到数据库-->
<bufferSize value="1"/>
<!--或写为<param name="BufferSize" value="1" />-->
<!--引用-->
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<!--连接数据库字符串-->
<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代码是我自己的一个框架里的,内容太多就不贴出来了,你只需要和以前一样,把数据从库里查出来,绑定给任意你喜欢的数据表格上。由于单页面的日志系统没有什么复杂操作,就用个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);
}
}

话说到这,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吗?如果用得上抓紧收藏吧。有疑问欢迎留言。

如果我的点滴分享对你有点滴帮助,欢迎点击下方红色按钮关注,我将持续输出干货分享。也欢迎为我也为你自己点赞支持。

  2017.05.21补充  日志系统已升级为Mongo

                                                  --保持学习,谨记谦虚。不端不装,有趣有梦。

自用LogSystem入库分享的更多相关文章

  1. XSS相关Payload及Bypass的备忘录(上)

    翻译学习准备自用,同时分享给大家, 来自于: https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XSS%20Injecti ...

  2. 【分享】 一款自用的Anki卡片模板:黄子涵单词卡片 v1

    [分享] 一款自用的Anki卡片模板:黄子涵单词卡片 v1 说明 第一代的功能 主要有两部分组成:英文和含义,目前主要是为自己记忆Web前端一些常用的单词而服务 有美美哒背景图,本来想修改为随机背景图 ...

  3. 自用 Pycharm 主题配色分享(主题才是开发第一生产力)

    写在前面的话 是的,我又回来了,上一篇[使用 Visual Studio Code(VSCode)搭建简单的 Python + Django 开发环境]才说真香,结果用两天就发现很多恶心的问题拦住了菜 ...

  4. Assassin暗杀者-自用短小精悍的webshell管理工具分享

    Assassin Assassin是一款精简的基于命令行的webshell管理工具,它有着多种payload发送方式和编码方式,以及精简的payload代码,使得它成为隐蔽的暗杀者,难以被很好的防御. ...

  5. 【WPF】分享自用 白板窗口(空窗口) 控件 BlankWindow,基于WindowChrome。

    一.背景 吃产品的亏,上设计的当,最后死在变化上. 现在的产品和设计都喜欢在窗口上做一些事,比如让Title做很多事,好像跟人家用一样的窗口很Low似的,好像真的挺Low的. 所以,还不如弄一个黑板似 ...

  6. 分享一个自用的 Inno Setup 软件打包脚本

    此脚本支持打包mysql.安装mysql服务.安装windows服务.操作ini文件.操作注册表.高效压缩文件等功能,基本能满足常用的软件打包需求. ;定义各种常量 #define MyAppName ...

  7. mac常用软件,自用找了很久的分享一下相信很多人需要

    CleanMyMac 3.1.1.dmg比较好用的清理软件.破解版!http://pan.baidu.com/s/1i4mo7jvNTFS读写 Tuxera NTFS for Mac.rar也是破解的 ...

  8. 阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处

    本文引用了唐小智发表于InfoQ公众号上的“钉钉企业级IM存储架构创新之道”一文的部分内容,收录时有改动,感谢原作者的无私分享. 1.引言 业界的 IM 产品在功能上同质化较高,而企业级的 IM 产品 ...

  9. 分享一个与ABP配套使用的代码生成器源码

    点这里进入ABP系列文章总目录 分享一个与ABP配套使用的代码生成器源码 真对不起关注我博客的朋友, 因最近工作很忙, 很久没有更新博客了.以前答应把自用的代码生成器源码共享出来, 也一直没有时间整理 ...

随机推荐

  1. iOS 程序间跳转传参(支付和地图)

    两个APP之间的跳转是通过[[UIApplication sharedApplication] openURL:url]这种方式来实现的. 1.首先设置第一个APP的url地址 2.接着设置第二个AP ...

  2. 计算机学院大学生程序设计竞赛(2015’12) 1004 Happy Value

    #include<cstdio> #include<cstring> #include<cmath> #include<vector> #include ...

  3. oracle 函数的创建和调用

    以下已经测试通过 创建函数: create or replace function get_annual_sal(in_name varchar2) return number is annual_s ...

  4. hibernate--联合主键--annotation

    有3种方式: 1.@Embeddedable 2.@EmbeddedId 3. @IdClass 2,3 最常用 一, @Embeddedable 1.新建TeacherPK.java, 加入@Emb ...

  5. 照着例子学习 protobuf-lua

    参考文章:cocos2dx使用lua和protobuf 首先得下载protobuf-gen-lua的插件,插件Git地址在此. 下载完之后进入到protoc-gen-lua\plugin这个目录,并在 ...

  6. 安装PIL遇到的问题

    配置:Win7 64位 不过折腾到最后,没有使用PIL,官方的PIL很久木有更新了,换了Pillow,是PIL的衍生吧,一直有更新,但是两者不可在同一环境共存. 1 Python version 2. ...

  7. kafka第三篇--安装使用

    说明:直接下载二进制包可省略安装过程,省略很多麻烦. 1单机 安装 安装过程,参考官网: > tar xzf kafka-<VERSION>.tgz > cd kafka-&l ...

  8. NULL、nil、Nil、NSNull的区别

    标志 值 含义 NULL (void *)0 C指针的字面零值 nil (id)0 Objecve-C对象的字面零值 Nil (Class)0 Objecve-C类的字面零值 NSNull [NSNu ...

  9. Mac OS X窗口最小化方法的几个快捷键

    大家都知道在 OS X 系统中,点击窗口左上角中间的小黄按钮就可以最小化当前窗口.而事实上,还有一些比点击这个按钮更快的窗口最小化方法.这里一起分享给大家! 使用快捷键 Command+M,可以实现快 ...

  10. Excel每隔10行取得一个数字

    index(a:a,row(a1)*10) 然后下拉 将一列数字分为好多列 =OFFSET($B$1,(ROW(A1)-1)*11+COLUMN(A1)-1,,) row()返回当前的行,比如A则返回 ...