log4net的大名早有耳闻,一直没真正用过,这次开发APP项目准备在服务端使用log4net。 日志的数据量较大,频繁的写数据库容易影响系统整体性能,所以独立将日志写到mongodb数据库是不错的选择。---经过2天的摸索,总结出本文档。
 
github有个开源项目log4mongo-net,另一位斯克迪亚作者根据开源项目又做了修改http://skyd.sinaapp.com/archives/1282
所以直接拿斯克迪亚的代码来使用。
 
1、将log4net和mongodb驱动升级为最新版本。log2net: 1.2.15   mongodb: 2.2.3.3
2、新加了一个LogHelper类,所有的日志通过LogHelper的静态方法来写。

 public class Helper
{
private static readonly Helper instance = new Helper();
private static ILog apiLog = null;
private static ILog dbLog = null; private Helper()
{
// XmlConfigurator.Configure();
LogLog.InternalDebugging = true; }
public static ILog ApiLog()
{
if (apiLog == null)
{
apiLog = LogManager.GetLogger("ApiLog");
}
return apiLog; }
public static ILog DbLog()
{
if (dbLog == null)
{
dbLog = LogManager.GetLogger("ApiLog");
}
return dbLog; }
}
 调用
 Log4Mongo.Helper.DbLog().Info("abc");

 
3、自定义日志内容字段。网上能找到很多Log4net添加字段的方法,但因为我用的是修改过的log4mongo。而且简化了配置,默认就是显示所有字段。所以基本上通过改配置的都不适用。
开始准备使用 LogicalThreadContext.Properties["CustomColumn"] = "Custom value" ,可以将更多自定义的内容写到日志。
 执行写日志log.Debug(object)之前,先把各种自定义内容通过LogicalThreadContext设置好。然后再执行log.Debug(object)。
这种方式虽然可以达到目的,但感觉不是很方便。另一个问题是设置LogicalThreadContext后,这些值会一直存在,在同一个线程里再次执行 log.Debug(object)时,任然会记录这些自定义的属性值,不太好控制,容易写错内容。
 
另一种办法是通过 log.Debug(object)里的object来实现,一般情况下都是直接 log.Debug("this is message")这种方式来写日志,也可以将一个对象传递给 log.Debug。在往数据库写数据前,可以通过loggingEvent.RenderedMessage来读取传递过来的对象,
  public  class LogInfo
    {
        public string AppKey { set; get; }
 
        public string UserID { set; get; }
        public string HostName { set; get; }
        public string IPAddress { set; get; }
        public string Message { set; get; }
 
        public override string ToString()
        {
            var bsonDoc = this.ToBsonDocument();
            return bsonDoc.ToString();
        }
    }
默认loggingEvent.RenderedMessage是获取object 的ToString()的值,这里需要重写一下ToString(),将类转化为BsonDocument。
loggingEvent.RenderedMessage获取BsonDocument后再拆分为具体的属性。
 
        private static void BuildCustomMessage(string message,ref Log log)
        {
            try
            {
                var bson = BsonDocument.Parse(message);
                foreach (var item in bson.Elements)
                {
                    string value = item.Value.ToString();
                    if (item.Value.IsBsonNull)
                    {
                        value = string.Empty;
                    }
                    log.Properties.Add(item.Name, value);
                }
            }
            catch (Exception)
            {
                log.RenderedMessage = message;
            }
 
        }
为了方便,直接用 BsonDocument.Parse(message)来判断是复杂对象还是String。直接用try catch来处理,对性能会有一点影响。做了测试相比直接传递String不需要BuildCustomMessage ,传递复杂对象时性能相差6%左右。这6%主要是对象ToString()转化为BsonDocument,和BuildCustomMessage两部份。
 
 
4、在测试时发生一个奇怪的问题,单独一个语句log.Debug(string)可以输出到控制台,但死活写不到数据库。而用一个循环来执行log.Debug(string),却能正常写到数据库。  log4net有输出Shutdown called on Hierarchy的提示,但不明白是什么意思,也不知道是否有相关。
解决办法是将写数据库的操作由异步改为同步。具体原因没找到。log4net自身问题、  mongodb驱动 、 log4net缓存等等都没法排除。
 //collection.InsertOneAsync(BuildBsonDocument(loggingEvent));
 collection.InsertOne(BuildBsonDocument(loggingEvent));
 
 
5、为了方便日后的维护,将数据库名和Collection(表名)设置到配置文件。
<appender name="MongoDBAppender" type="Log4Mongo.MongoDBAppender, Log4Mongo">
  <connectionString value="mongodb://root:123456@localhost:27017"/>
  <DatabaseName value="log4mongo"/>
  <CollectionName value="yyyyMM"/>
</appender>
配置的值在public class MongoDBAppender : AppenderSkeleton这个类里会直接获取,不需要做额外处理
    public string ConnectionStringName { get; set; }
    public string DatabaseName { get; set; }
     public string CollectionName { get; set; }
  <CollectionName value="yyyyMM"/>这么写的目的是让日志根据日期来自动分表。通过修改配置就能按日、按月、按年来分表。
 
        private IMongoCollection<Log> GetCollection()
{
            string tableName;
            tableName = CollectionName ?? "yyyyMM";
            tableName = "log"+ string.Format("{0:" + tableName + "}", DateTime.Now);
            return GetDatabase().GetCollection<Log>(tableName); 
}
 
 
 
 
 
 
 
 
 
 
 
 
 

如何将Log4Net 日志保存到mongodb数据库之实践的更多相关文章

  1. apache log4j将日志保存在mongodb数据库中(转)

    og4j与mongodb整合 Mongo Java driver jar包 log4mongo-java jar包 配置log4j.properties文件,使之整合mongodb: #将Mongod ...

  2. 使用官方组件下载图片,保存到MySQL数据库,保存到MongoDB数据库

    需要学习的地方,使用官方组件下载图片的用法,保存item到MySQL数据库 需要提前创建好MySQL数据库,根据item.py文件中的字段信息创建相应的数据表 1.items.py文件 from sc ...

  3. 获取豆瓣读书所有热门标签并保存到mongodb数据库

    目标url:https://book.douban.com/tag/?view=type&icn=index-sorttags-all 目的:抓取所有标签名称(tag_name),标签链接(t ...

  4. 5分钟掌握智联招聘网站爬取并保存到MongoDB数据库

    前言 本次主题分两篇文章来介绍: 一.数据采集 二.数据分析 第一篇先来介绍数据采集,即用python爬取网站数据. 1 运行环境和python库 先说下运行环境: python3.5 windows ...

  5. vue+node+mongoDB 火车票H5(六)---城市列表保存到MongoDB数据库并且启用node.js服务

    把车站列表保存到数据库,并且从本地创建服务 node.js创建httpserver 1.搭建基于express的运行环境 全局安装express-gengerator cnpm install -g ...

  6. 记录python爬取猫眼票房排行榜(带stonefont字体网页),保存到text文件,csv文件和MongoDB数据库中

    猫眼票房排行榜页面显示如下: 注意右边的票房数据显示,爬下来的数据是这样显示的: 网页源代码中是这样显示的: 这是因为网页中使用了某种字体的缘故,分析源代码可知: 亲测可行: 代码中获取的是国内票房榜 ...

  7. log4net 控制台和文件和数据库输出三种方式

    1.新建console应用项目SendEvaluateDataToProvinceConsole 2.选择SendEvaluateDataToProvinceConsole项目右键 选择 管理NuGe ...

  8. 【代码笔记】iOS-将log日志保存到文件

    代码: #import "AppDelegate.h" #import "RootViewController.h" @implementation AppDe ...

  9. iOS - NSLog、UncaughtException日志保存到文件

    转:http://blog.csdn.net/marujunyy/article/details/12005767 对于真机,日志没法保存,不好分析问题.所以有必要将日志保存到应用的Docunment ...

随机推荐

  1. 技术随笔 查找速度最快的Google IP

    转:http://www.xiumu.org/technology/the-find-the-fastest-in-the-google-ip.shtml 体验秒开GOOGLE的感觉! 在http:/ ...

  2. Transact-SQL三值逻辑

    /*===========================<一>========================== 在SQL中逻辑表达式的值有三种: 1.TRUE 2.FALSE 3.U ...

  3. c++ 设计模式8 (Factory Method 工厂方法)

    5. “对象创建”类模式 通过“对象创建”类模式绕开new,来避免对象创建(new)过程中所导致的紧耦合(依赖具体类),从而支持对象创建的稳定.它是接口抽象之后的第一步工作. 5.1 工厂方法 动机: ...

  4. C# 之 判断或设置以管理员身份运行程序

    一.判断程序是否以管理员权限运行 using System.Security.Principal; public bool IsAdministrator() { WindowsIdentity cu ...

  5. NSBlockOperation添加多个任务

    //创建一个队列 NSOperationQueue *operation=[[NSOperationQueue alloc]init]; //把任务放在NSBlockOperation里面 NSBlo ...

  6. 判断某个对象是不是DOM对象

    在写js代码时有时需要判断某个对象是不是DOM对象,然后再进行后续的操作,这里我给出一种兼容各大浏览器,同时又算是比较稳妥的一种方法. 要判断一个对象是否DOM对象,首先想到的无非就是它是否具有DOM ...

  7. python用装饰器实现缓存函数执行结果

    根据调用的函数名和调用的参数,对函数的结果进行缓存,下次执行的时候就不用重复计算   可以用装饰器来实现   import time import hashlib import pickle cach ...

  8. Linux下C/C++程序开发管理(makefile)

    一.引言          从我们刚开始编写一个简单的C/C++ "Hello,World!",到将其编译.运行处结果—这部分工作IDE(集成开发环境)帮我们做了,包括语法错误检查 ...

  9. 对象(类)的封装方式(面向对象的js基本知识)

    上一个月一直忙于项目,没写过笔记,今天稍微空下来了一点 前几天在写项目的时候关于怎么去封装每一个组件的时候思考到几种方式,这里总结一下: 1.构造函数方式(类似java写类的方式):把所有的属性和方法 ...

  10. 在Eclipse中导入文件和文件夹

    一. 将JAVA文件夹导入Eclipse中的方法: 方法一:直接将java文件夹复制,然后粘贴到项目下: 方法二:(1)打开Eclipse,点击项目的空白处,现在import: (2)现在Existi ...