也用 Log4Net 之將日志記錄到數據庫的后台實現 (二)


 

也用 Log4Net 之將日志記錄到數據庫的后台實現 (二)

 

  大家下午好,昨天講了配置,今天我們講講后台實現,在完成了后台實現后,我們才能真正意義上的解決把自定義屬性字段值錄入到數據庫中。

 

  在開寫之前我先着重強調一下,“日志”的概念非常廣泛,有錯誤日志、操作日志、訪問日志、事件日志等等。我們並不提倡把所有的日志都記錄到數據庫,因為這樣做沒有必要。同時如果日志數據表與業務表同在一個數據庫的話,頻繁的記錄日志的操作會影響性能(Log4Net提供了緩存機制,可以在緩存日志數據達到設定值,比如200條時,Log4Net會批量將數據錄入到數據庫中。即便是這么好的機制,我還是建議大家一定要分清情況,一般錯誤日志和事件日志我們采用文件形式記錄,相應的操作日志我們可以采用數據庫記錄)。

 

  “通用日志記錄系統” 的重點是通用。能適應各種要求,比如要提供豐富的日志記錄形式(如:文件、數據庫等等),以及適應不同的業務需求,比如A業務希望記錄A1,A2,A3字段,B業務希望記錄B1,B2,B3字段。同時還要做到靈活性,能適應業務變更。Log4Net正是這樣的一種開源框架,說了這么多,我想表述的是:數據庫記錄日志的方式並不是唯一的和最好的,大家一定在酌情而定。

 

  好了,言歸正傳,我們現在開始講后台的處理代碼:

 

  (1)、日志對象,就是在存放日志的載體:

public class LogMessage  
{
    public int UserID { get; set; }
}

  

  在項目中 LogMessage 充當日志對象,大家一定很奇怪,為什么我的只有一個屬性UserID。原因是我在測試自定義屬性能不能記錄到日志數據庫中,所以弄太多的屬性也沒必要。

 

  Log4Net在將日志記錄到數據庫時會提供一些缺省的屬性,他們分別是:

[Id] [int] IDENTITY (1, 1) NOT NULL,        
[Date] [datetime]  NULL,        --異常記錄時間
[Thread] [varchar] (255)  NULL, --線程ID(數字)
[Level] [varchar] (50)  NULL,   --日志級別(FALAT,ERROR,WARN,INFO,DEBUG)
[Logger] [varchar] (255)  NULL,  --記錄的類
[Message] [varchar] (4000) NULL,   --消息

 

  這些缺省值我們最好在每個日志表里都加上,我測試的時候自行把 Message給刪除了,結果怎么也記錄不進去日志。所以我建議大家把這幾個都帶了。字段名字你可以自己改,比如,我就把Date改成了RecordTime,但是在配置文件中,RecordTime字段對應的值依然是@log_date,忘記了的同學回上一篇中去看配置去。

  

 

  (2)、CustomLayout 類

  CustomLayout 類繼承至 log4net.Layout.PatternLayout

 

  關於Layout大家應該不陌生,“Layout 組件用於向用戶顯示最后經過格式化的輸出信息。輸出信息可以以多種格式顯示,主要依賴於我們采用的Layout組件類型。可以是線性的或一個XML文件。Layout組件和一個Appender組件一起工作。API幫助手冊中有關於不同Layout組件的列表。一個Appender對象,只能對應一個Layout對象。要實現你自己的Layout類,你需要從log4net.Layout.LayoutSkeleton類繼承,它實現了ILayout接口。”

 

  因為我們要使用自定義屬性UserID,所以我們要實現自己的Layout類,我們來看代碼:

public class CustomLayout : log4net.Layout.PatternLayout
{
   public CustomLayout()
   {
        this.AddConverter("UserID", typeof(UserIDPatternConverter));
   }
}

  typeof(UserIDPatternConverter)語句中的UserIDPatternConverter實現了格式化的輸出信息。

internal sealed class UserIDPatternConverter : PatternLayoutConverter 
{
    override protected void Convert(TextWriter writer, LoggingEvent loggingEvent)
    {
        LogMessage logMessage = loggingEvent.MessageObject as LogMessage;
           
        if (logMessage != null)
             writer.Write(logMessage.UserID);
    }
}

 

  (3)、對Log4Net的簡單封裝

 

   public class LogHelper
    {
        public LogHelper()
        {

        }

        public static string LoggerName = string.Empty;

        private static LogMessage message = null;

        private static ILog _log;

        public static ILog log
        {
            get
            {
                string path = @"C:\Log4Net.config";
                log4net.Config.XmlConfigurator.Configure(new FileInfo(path));

                if (_log == null)
                {
                    //從配置文件中讀取Logger對象  
                    //WebLogger 里面的配置信息是用來將日志錄入到數據庫的
                    //做為擴展 做判斷來確定日志的記錄形式,數據庫也好,txt文檔也好,控制台程序也好。
                    _log = log4net.LogManager.GetLogger(LoggerName); //log4net.LogManager.GetLogger("WebLogger");
                }
                else
                {
                    if (_log.Logger.Name != LoggerName)
                    {
                        _log = log4net.LogManager.GetLogger(LoggerName);
                    }
                }

                return _log;
            }
        }


        /// <summary>
        /// 調試
        /// </summary>
        public static void debug()
        {
            if (log.IsDebugEnabled)
            {
                log.Debug(message);
            }
        }


        /// <summary>
        /// 錯誤
        /// </summary>
        public static void error()
        {
            if (log.IsErrorEnabled)
            {
                log.Error(message);
            }
        }

        /// <summary>
        /// 嚴重錯誤
        /// </summary>
        public static void fatal()
        {
            if (log.IsFatalEnabled)
            {
                log.Fatal(message);
            }
        }

        /// <summary>
        /// 記錄一般日志
        /// </summary>
        public static void info( )
        {
            if (log.IsInfoEnabled)
            {
                //log.Info("Jerry");
                log.Info(message);
            }
        }


        /// <summary>
        /// 記錄警告
        /// </summary>
        public static void warn()
        {
            if (log.IsWarnEnabled)
            {
                log.Warn(message);
            }
        }


        /// <summary>  
        /// 需要寫日志的地方調用此方法  
        /// </summary>  
        /// <param name="level">自定義級別</param>  
        public static void SaveMessage(LogMessage logMessage,int level)
        {
            message = logMessage;

            switch (level)
            {
                case 1:
                    info();
                    break;
                
                case 2: 
                    warn(); 
                    break;
                
                case 3:  
                    error();
                    break;
                
                case 4: 
                    fatal();
                    break;

                default: break;
            }
        }

    }

 

  Log4Net根據不同的日志級別提供了不同的記錄方法,對了,這里所說的日志級別就是對應的 Level 字段,我們來看一下 Log4Net的日志級別:

  這是我從別的網站上找到的圖,用來說明一下級別。好了,到此為此,我們就已經把 Log4Net 底層這好了,注意,你可以把上頁的這些類都統一寫到一個類庫中。這樣做的好處是,當其它項目要用到日志記錄功能的時候,直接引用你類庫的 dll 就可以了,是不是很方便。同時這樣做也實現了對Log4Net的簡單封裝,讓其它項目組的人更易使用。

 

  重點強調一下,記得在這個類庫中引用Log4Net.dll。畢竟我們是要用Log4Net來實現日志記錄的,別寫了半天都沒引用,那就要出問題了。

 

  (4)、好了,讓我們在Web展示層中調用他吧! Default.aspx

protected void Page_Load(object sender, EventArgs e)
{
    LogHelper.LoggerName = "WebLogger";
    LogMessage logMessage = new LogMessage();

    logMessage.UserID = 123456;
    LogHelper.SaveMessage(logMessage,1);
}


  因為我們在配置文件中設定了緩存數,<bufferSize value="10"/> 所以你刷新十下,這時候數據就進入到數據庫了。不過聰明的做法是,將bufferSize 的value值改為1

 

  (5)、數據庫中的信息

 

  (6)、對不起,剛才自己看的時候發現沒有建表的Sql語句,現在補上。

USE [LogSys]
GO

/****** Object:  Table [dbo].[Log]    Script Date: 08/29/2012 14:56:11 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

SET ANSI_PADDING ON
GO

CREATE TABLE [dbo].[Log](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [LevelName] [varchar](50) NULL,
    [UserID] [int] NULL,
    [Message] [varchar](4000) NULL,
    [Exception] [varchar](2000) NULL,
    [RecordTime] [varchar](50) NULL,
 CONSTRAINT [PK_Log_1] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

 

  好了,就寫到這里,我是百靈,祝大家天天好心情,身體健康。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM