2014年11月11日 星期二

LOG製作方法


http://blog.kkbruce.net/2011/11/aspnet-mvc-log.html#.VGFhafmUdBH

ASP.NET MVC - 凡走過,必留下痕跡之LOG記錄

LOG記錄的方式

要留下Log記錄,基本方向可以有:
  1. System Log記錄
  2. File Log記錄
  3. Database Log記錄
  4. Log Server
System Log記錄指的是像IIS Log記錄就是System Log記錄。或撰寫程式碼,向Windows本身的事件檢視器來發送Log記錄。

File Log記錄指的是透過 System.IO 寫一支程式,將你要的Log記錄到一個純文字檔,例如, FileLogs.txt,因為程式自己寫,你能控制什麼是你要,什麼是你不要,與System Log記錄相比,可以免除太大、太亂的問題。檔案太大還是有可能,這部分可能要寫程式自動處理,或是手動處理。

Database Log記錄,即將Log記錄直接記錄在Database之中,與System Log記錄與File Log記錄相較,Database本來就是儲存與管理資料所在地,而且與撰寫發送Windows Log記錄事件檢視器程式碼和File Log記錄程式碼來看,資料庫 Log記錄程式碼簡單多了。。

Log Server一般而言,是當伺服器群成長到一定數量,會架一台專門處理Log記錄的硬體伺服器,例如,Linux平台的Syslog,Windows下的Kiwi Syslog Server來架設,或是買專門機架硬體式Log Server,來統一收集、分析、管理這些Server Log記錄。

真是可大可小。

以下,我會使用 ASP.NET MVC來實作一個Database Log記錄範例。


DATABASE LOG記錄 - SCHEMA準備

針對我們檔案管理系統部分,我們會有兩張 Table,一張是記錄有權限的人員做了什麼動作,一張是記錄使用者下載了那些資料。

KKBruceFileLog Schema

這是檔案下載的Log記錄表,要注意的只有 HiterIP 長度為 50,為什訂那麼長?我們事先把 IPv6 考慮進去。這樣,不管我們的 .NET Framwork 程式是抓到 IPv4 或 IPv6 ,記錄進資料庫都不會有問題。

01-- 請切換至你的資料庫 --
02USE [KKBruce]
03GO
04
05/****** Object:  Table [dbo].[KKBruceFileLog]    Script Date: 11/08/2011 14:31:52 ******/
06SET ANSI_NULLS ON
07GO
08
09SET QUOTED_IDENTIFIER ON
10GO
11
12CREATE TABLE [dbo].[KKBruceFileLog](
13 [FilesLogId] [int] IDENTITY(1,1) NOT NULL,
14 [FileId] [intNOT NULL,
15 [HiterIP] [nvarchar](50) NOT NULL,
16 [CreateTime] [datetime2](7) NOT NULL,
17 CONSTRAINT [PK_FilesLogs] PRIMARY KEY CLUSTERED
18(
19 [FilesLogId] ASC
20)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  =ON, ALLOW_PAGE_LOCKS  = ONON [PRIMARY]
21ON [PRIMARY]
22
23GO
24
25/*
26我的資料表裡有外來鍵及其他設定,
27你可以依需求設定,單純測試不需要。
28*/
29
30/*
31EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'檔案編號' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'KKBruceFileLog', @level2type=N'COLUMN',@level2name=N'FileId'
32GO
33
34EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'檔案下載Log表' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'KKBruceFileLog'
35GO
36
37ALTER TABLE [dbo].[KKBruceFileLog]  WITH CHECK ADD  CONSTRAINT [FK_FilesLogs_Files] FOREIGNKEY([FileId])
38REFERENCES [dbo].[ProductFile] ([FileId])
39GO
40
41ALTER TABLE [dbo].[KKBruceFileLog] CHECK CONSTRAINT [FK_FilesLogs_Files]
42GO
43
44ALTER TABLE [dbo].[KKBruceFileLog] ADD  CONSTRAINT [DF_FilesLogs_HitIPv4]  DEFAULT (N'下載者IPv4')FOR [HiterIP]
45GO
46*/

KKBruceEmployeeLog Schema

人員Log記錄表,記錄人員操作的任何動作,我們記錄登入人員的Id、動作、說明、IP、時間等資訊。另外補充,為了與 Entity Framework 有比較配合度,日期時間建議使用 datetime2 格式

01-- 請切換至你的資料庫 --
02USE [KKBruce]
03GO
04
05/****** Object:  Table [dbo].[KKBruceEmployeeLog]    Script Date: 11/08/2011 14:44:35 ******/
06SET ANSI_NULLS ON
07GO
08
09SET QUOTED_IDENTIFIER ON
10GO
11
12CREATE TABLE [dbo].[KKBruceEmployeeLog](
13 [EmployeeLogID] [int] IDENTITY(1,1) NOT NULL,
14 [EmployeeId] [intNOT NULL,
15 [ActionName] [nvarchar](250) NOT NULL,
16 [Description] [nvarchar](maxNOT NULL,
17 [ClientIP] [nvarchar](50) NOT NULL,
18 [CreateTime] [datetime2](7) NOT NULL,
19 CONSTRAINT [PK_KKBruceEmployeesLogs] PRIMARY KEY CLUSTERED
20(
21 [EmployeeLogID] ASC
22)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  =ON, ALLOW_PAGE_LOCKS  = ONON [PRIMARY]
23ON [PRIMARY]
24
25GO
26
27/*
28我的資料表裡有外來鍵及其他設定,
29你可以依需求設定,單純測試不需要。
30*/
31
32/*
33EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'人員Log記錄檔' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'KKBruceEmployeeLog'
34GO
35
36ALTER TABLE [dbo].[KKBruceEmployeeLog]  WITH CHECK ADD  CONSTRAINT [FK_EmployeesLogs_Employees]FOREIGN KEY([EmployeeId])
37REFERENCES [dbo].[KKBruceEmployee] ([EmployeeId])
38GO
39
40ALTER TABLE [dbo].[KKBruceEmployeeLog] CHECK CONSTRAINT [FK_EmployeesLogs_Employees]
41GO
42*/

ASP.NET MVC實作LOG記錄

如果拿ASP.NET與ASP.NET MVC比較,要在 ASP.NET MVC裡實作Log記錄,老實說,沒有太大難度。因為ASP.NET MVC架構上非常容易實作與執行這一類程式碼。ASP.NET麻煩了些。

什麼「這一類程式碼」?即需要「大量且重覆使用的程式碼」。在ASP.NET MVC裡有個機制稱 ActionFilter,就是專門在處理這種事,透過 ActionFilter 機制,我們可以很容易且簡單的去重覆使用我們的過濾器。因為我們要寫Log記錄,我們可以稱我們寫的為 Log ActionFilter、Log過濾器。

實作人員Log記錄


  • 新增一目錄「ActionFilters」→ 新增一類別「EmployeeLogAttribute.vb」→ 繼承「ActionFilterAttribute 屬性類別」→ 覆寫「OnActionExecuting 副程式」。

EmployeeLogAttribute.vb


01Public Class EmployeeLogAttribute
02    Inherits ActionFilterAttribute
03
04    ' 由開發人員設定傳入相關Action的說明
05    Public Property Description() As String
06
07    Public Sub New()
08    End Sub
09
10    Public Overrides Sub OnActionExecuting(filterContext As ActionExecutingContext)
11        ' 有使用者登入訊息
12        If filterContext.HttpContext.User IsNot Nothing Then
13            Using db As New KKBruceEntities
14
15                ' 設定Log相關資訊
16                Dim log As New KKBruceEmployeeLog() With
17                {
18                    .EmployeeId = (From e In db.KKBruceEmployee
19                                   Where e.Account = filterContext.HttpContext.User.Identity.Name
20                                   Select e.EmployeeId).First(),
21                    .ActionName = filterContext.RouteData.Values("controller") & "/" & _
22                                  filterContext.RouteData.Values("action"),
23                    .Description = Me.Description,
24                    .ClientIP = filterContext.HttpContext.Request.UserHostAddress,
25                    .CreateTime = DateTime.Now.ToString()
26                }
27
28                ' 寫入資料庫
29                db.KKBruceEmployeeLog.Add(log)
30                db.SaveChanges()
31
32                ' 邀免Log成長太大,保留六個月的Log
33
34                ' --- 補充 ---
35                ' 這一段會造成大量的Scan,Log越大,效能影響越明顯,
36                ' 原因在每個人員的每一個操作,我們就會執行一次這段程式,
37                ' 可在 Database 設定 Index、減少保留日期 … 來處理,
38    ' 或改使用排程來週期性的刪除。
39                ' EF 效能考量,可參考MSDN:
40                http://msdn.microsoft.com/zh-tw/library/cc853327.aspx
41
42                Dim DeleteLogs = From logs In db.KKBruceEmployeeLog
43                                 Where logs.CreateTime <= DateTime.Now.AddMonths(-6)
44                                 Select logs
45
46                ' EF批次相關資料:
49
50                For Each DelLog In DeleteLogs
51                    db.Entry(DelLog).State = EntityState.Deleted
52                Next
53                db.SaveChanges()
54            End Using
55        End If
56    End Sub
57End Class

如果你想測試這一段程式碼,你還必須建立會員登入相關資料表及程式碼才會運作。你可以先
  1. 註解第12 ( filterContext.HttpContext.User )、18 ( EmployeeId )、55 ( End If )行;
  2. 還有 KKBruceEmployeeLog Schema 裡的 EmployeeId 也必須把 NOT NULL 關鍵字移除。
先不進行會員相關資料的取得及寫入,即可測試。

使用Log ActionFilter

針對我們寫好的Log ActionFilter,使用有非常簡單,開啟你要設定的 Controller,然後在Action上設定 Log ActionFilter屬性。

上傳檔案Log ActionFilter設定


01#Region "上傳"
02
03 "上傳檔案")>
04 Function Create(upfile As HttpPostedFileBase) As ActionResult
05  ' 略,請參考之前文章
06  Return View()
07 End Function
08  
09
10 "上傳多個檔案")>
11 Function CreateMultiFile(form As FormCollection) As ActionResult
12  ' 略,請參考之前文章
13  Return View()
14 End Function
15#End Region

有進到 HttpPost 代表有Submit,我們只需一一為相關Action設定好EmployeeLog及說明,然後測試一下相關動作,再到資料庫或另寫一頁顯示Log記錄的頁面查詢,應該就能看到如下Log記錄:
EmployeeLogID EmployeeId ActionName Description ClientIP CreateTime
1 1 Account/LogOff 登出系統 ::1 2011-06-30 11:22:49.0000000
2 1 Account/Index 查看員工資料 ::1 2011-06-30 11:23:56.0000000
3 1 Account/Edit 修改人員資料 ::1 2011-06-30 11:24:16.0000000
4 1 Account/Index 查看員工資料 ::1 2011-06-30 11:24:16.0000000
5 1 Account/Edit 修改人員資料 ::1 2011-06-30 11:24:28.0000000

檔案下載的LOG ACTIONFILTER

一般檔案下載是匿名的,當我們把 EmployeeLogAttribute.vb 裡取得會員資料相關程式碼註解後,就差不多是檔案下載的 Log ActionFilter,把「設定Log相關資訊」及Entity Framework對應的「資料表名稱」改一改即可。然後,設定到檔案下載相關 Controller/Action 去,即可。

就算是採會員制,上面那個Log ActionFilter一樣寫好了,就拿去用吧!

一樣的東西,留給你去做。^_^

LOG記錄結論

System Log或IIS Log說真的,要看也沒幾個人看得懂,就算看得懂,要從數萬、數十萬、數百萬行裡找出問題點,那本身就是一件高難度任務。透過ASP.NET MVC裡的ActionFilter幫忙,讓我們很簡單且快速就完成有效的Log記錄,不論是稽核、分析、統計、舉證…都更有力,且存放於Database,不論是透過 SSMS 或網頁,我們都能快速的查詢我們所需的資訊。


[ASP.NET]即時創建一個TXT文檔,並寫入資料


http://www.dotblogs.com.tw/shinyo.her/archive/2012/02/14/69206.aspx

使用Asp.Net MVC打造Web Api (17) - 使用Nlog記錄系統訊息
http://ithelp.ithome.com.tw/question/10138479

沒有留言: