程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 如何將Log4Net 日志保存到mongodb數據庫之實踐,log4netmongodb

如何將Log4Net 日志保存到mongodb數據庫之實踐,log4netmongodb

編輯:C#入門知識

如何將Log4Net 日志保存到mongodb數據庫之實踐,log4netmongodb


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 LogHelper
  {
private static readonly LogHelper instance=new LogHelper();
  private static ILog log = null;     private Logger()   {       // XmlConfigurator.Configure();           LogLog.InternalDebugging = true;                   } public  static LogHelper getInstance()
  {       if (log == null)       {           log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);       }           return instance;   }
public void Debug(Object message, Exception exception)
{
  
    log.Debug(message);
}
public void Debug(Object message)
{
  
    log.Debug(message);
}
}
結果發現會有問題,log4net本來可以記錄日志發生所在的類名,和具體的行號。如果使用了單獨的類來寫日志,那麼記錄下來的類和行號都是LogHelper的內容,沒法定位到錯誤具體發生的位置。原因就在ILog是通過LogManger.GetLogger(Type)方法來獲的,要想獲取錯誤的類和行號,那麼必須在每個類裡單獨調用LogManger.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType)。(自己的理解,不一定准確)   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); 
		}
                         

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved