2011年10月15日 星期六

使用NLog - Advanced .NET Logging (2)


將Log資料存放到資料庫(MS SQL Server)中

在上一篇文章「使用NLog - Advanced .NET Logging (1)」裡面,我們是把Log資料給存放到文字檔中,

文章範例程式中的NLog.Config,有兩個target type是使用了File而另一個是使用EventLog

其實NLog的taget有預設提供了多達25種,但不見得每個都有機會去使用到,

而且你還可以依據NLog提供的API,讓你可以建立你自己想要的target,

除了已經介紹的File與EventLog外,最常用的也是最多人想要使用的就是「Database」。

 

以下就將會介紹如何修改target設定,把Log資料存放到資料庫中。


本篇文章將會以MS SQL Server為存放的裝置。


NLog Documentation - Database target
http://nlog-project.org/wiki/Database_target


我們先看看NLog所提供的設定範例:

<?xml version="1.0" ?>
<nlog autoReload="true">
    <targets>
        <target name="database" type="Database">
 
            <dbprovider>mssql</dbprovider>
 
            <!-- database connection parameters -->
            <!-- alternatively you could provide a single 'connectionstring' parameter -->
 
            <dbhost>.</dbhost> 
            <dbdatabase>NLogDatabase</dbdatabase>
            <dbusername>nloguser</dbusername>
            <dbpassword>nlogpassword</dbpassword>
 
            <commandText>
                insert into LogTable(time_stamp,level,logger,message) values(@time_stamp, @level, @logger, @message);
            </commandText>
 
            <parameter name="@time_stamp" layout="${date}" />
            <parameter name="@level" layout="${level}" />
            <parameter name="@logger" layout="${logger}" />
            <parameter name="@message" layout="${message}" />
        </target>
    </targets>
 
    <rules>
        <logger name="*" minlevel="Debug" appendTo="database" />
    </rules>
</nlog>

以下是NLog所提供的LogTable Schema:

預設事先建立DB「NLogDatabase」以及Table「LogTable」,DB名稱以及Table名稱都可以修改為自己想要的名稱,

修改後也請務必記得要去修改Database target的資料。

use master;
go
 
create database NLogDatabase
/*
on primary (name='NLogDatabase
filename='***insert_path_here***\NLogDatabase.mdf', 
size=10MB) 
log on (name='NLogDatabase_log',
filename='***insert_path_here***\NLogDatabase_log.ldf',
size=10MB)
*/
go
 
exec sp_addlogin 'nloguser','nlogpassword',NLogDatabase
go
 
use NLogDatabase;
go
 
create table LogTable
(
    sequence_id integer not null primary key identity(1,1),
    time_stamp datetime not null,
    level varchar(5) not null,
    logger varchar(80) not null,
    message varchar(4095) not null,
)
go
 
exec sp_grantdbaccess 'nloguser','nloguser'
go
 
grant insert,select on LogTable to nloguser
go

 

將上面的NLog.Config設定複製貼上你的NLog.Config,然後執行T-SQL指令後,先別急著去執行你的網站,

先說明一下NLog的Database target設定,

dbProvider

預設使用MS SQL Server的話,可以是「mssql」也可以是「sqlserver」「microsoft」「msde」,

如果你是使用其他類型的資料庫,就需要你所使用的資料庫的database provider名稱,例如NLog文件就這樣寫著:

The parameter name should be a provider invariant name as registered in machine.config or app.config. Common values are:

  • System.Data.SqlClient -
  • System.Data.SqlServerCe.3.5 -
  • System.Data.OracleClient - (deprecated in .NET Framework 4)
  • Oracle.DataAccess.Client -
  • System.Data.SQLite -
  • Npgsql -
  • MySql.Data.MySqlClient -
(Note that provider invariant names are not supported on .NET Compact Framework). Alternatively the parameter value can be be a fully qualified name of the provider connection type (class implementing IDbConnection) or one of the following tokens:
  • sqlserver, mssql, microsoft or msde - SQL Server Data Provider
  • oledb - OLEDB Data Provider
  • odbc - ODBC Data Provider

假如你的資料庫是使用Oracle Native的話,那麼dbProvider就會是:

dbProvider="System.Data.OracleClient.OracleConnection,System.Data.OracleClient, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"

 

dbhost, dbdatabase, dbusername, dbpassword

dbhost:你所使用的資料庫位置,可以輸入host名稱,但是不能接受IP

dbdatabase:DB名稱

dbusername:DB使用者名稱

dbpassword:DB使用者密碼

其實上面的NLog.Config中已經說明,你也可以使用「connectionString」的方式輸入資料庫連線,取代上面四個屬性,

<!-- database connection parameters -->
<!-- alternatively you could provide a single 'connectionstring' parameter -->

使用個別屬性設定:

    <dbhost>localhost</dbhost>
    <dbdatabase>NLogDatabase</dbdatabase>
    <dbusername>nloguser</dbusername>
    <dbpassword>nlogpassword</dbpassword>

使用connectionString屬性:

這邊的Data Source也無法指定IP

<connectionString>Data Source=localhost;Initial Catalog=NLogDatabase;Persist Security Info=True;User ID=nloguser;Password=nlogpassword;MultipleActiveResultSets=True;</connectionString>

 

commandText, parameter

commandText:就要把資料寫入資料庫的指令碼(SQL Statement),而這個部分需要與parameter來配合。

parameter:參數,這邊的參數名稱是要給commandText的Values使用,而資料的內容則是需要搭配layout renderers。

<commandText>
    insert into LogTable(time_stamp,level,logger,message) values(@time_stamp, @level, @logger, @message);
</commandText>
<parameter name="@time_stamp" layout="${date}" />
<parameter name="@level" layout="${level}" />
<parameter name="@logger" layout="${logger}" />
<parameter name="@message" layout="${message}" />

在commandText的SQL Statement裡面,Values的四個parameter是對應資料表LogTable的四個欄位,

而四個parameter則分別以Layout Renderers定義的格式帶入,

看我們在LogTable中的欄位騎定義是什麼,再去選擇要放入的資料內容,

參考:NLog Documentation – Layout Renderers

像上面的四個parameter所使用的layout分別是:

${date}:目前記錄的日期與時間

${level}:Log資料的等級

${logger}:logger的名稱

${message}:Log的訊息內容

 

將資料庫連線設定修改好並重新建置方案之後,直接執行網站來看看,

以下就是實際存入資料庫的內容:

image

而這是有記錄到自訂Fatal訊息的內容:

image

 

所以,要存哪些Log資料內容到資料庫裡面,是可以讓我們自己去決定的,可以依據實際的狀況來決定。

如果說我們要自訂Table、Column,自己定義要存放哪些資料,需要注意幾點:

1. 正確的授與資料庫使用者操作權限

如果你一開始是用NLog範例所提供的Create_nlog_database.sql來建立DB與Table的話,

因為預設建立的使用者 nloguser 對 LogTable 只被Grant Select 與Insert 兩種操作,

如要另外建立Table來記錄資料的話,也讓 nloguser (或是另外建立的user) Grant Select 與 Insert 就可以。

2. 使用正確的方式記錄Log

程式中的try…catch…,使用logger來記錄exception的方法可以改用以下的方法:

  • TraceException()
  • DebugException()
  • InfoException()
  • WarnException()
  • ErrorException()
  • FatalException()
  • LogException() – takes log level as a parameter

參考NLog Documentation - How to properly log exceptions?

3. 加強對於${exception} layout的認識

${exception} 可以增加一些條件格式,可以很清楚的知道要記錄Exception的哪些資料,

例如:${exception:format=type} 這可以記錄到Exception的類別。

例如:${exception:stacktrace} 會記錄Exception內的stacktrace資訊。

參考

NLog Documentation - Exception layout renderer

NLog Documentation - How to properly log exceptions?

NLog Documentation - Exception logging enhancements

 

以下是調整後的Database target設定內容:

在Table [ NLog ] 中,我還多增加了一個 [ Detail ] 欄位,用來記錄Exception的完整訊息。

  <target name="database" type="Database">
    <dbprovider>mssql</dbprovider>
    <connectionString>Data Source=localhost;Initial Catalog=NLogDatabase;Persist Security Info=True;User ID=nloguser;Password=nlogpassword;MultipleActiveResultSets=True;</connectionString>
    <commandText>
      insert into NLog (time_stamp, level, host, type, source, logger, message, stacktrace, Detail) Values(@time_stamp, @level, @host, @type, @source, @logger, @message, @stacktrace, @detail);
    </commandText>
    <parameter name="@time_stamp" layout="${date}" />
    <parameter name="@level" layout="${level}" />
    <parameter name="@host" layout="${machinename}" />
    <parameter name="@type" layout="${exception:format=type}" />
    <parameter name="@source" layout="${callsite:className=true}" />
    <parameter name="@logger" layout="${logger}" />
    <parameter name="@message" layout="${message}" />
    <parameter name="@stacktrace" layout="${exception:stacktrace}" />
    <parameter name="@detail" layout="${exception:format=tostring}" />
    
  </target>

 

而實際執行網站後,在資料庫的Table [ NLog ] 中的記錄:

image

 

大致上NLog使用Database Target的基本設定方式就介紹到這裡,其實Database Taget或是Target還有很多地方可以在加以說明,

所以下一篇文章中會再針對Database Target的一些進階設定做說明。

 

參考連結:

NLog Documentation – Configuration file

NLog Documentation – Database target

NLog Documentation – Layout renderers

NLog Documentation – Exception layout render

NLog Documentation – Exception logging enhancements

NLog Documentation – How to property log exceptions?

 

以上

6 則留言:

  1. Dear m大:

    請教一下您在NLogDB內新增的欄位型態及長度大小怎麼開
    可否給個建議
    謝謝

    回覆刪除
    回覆
    1. 我在本文裡有提供 LogTable Schema,每個欄位的資料型態與長度大小都有載明。
      或者是在以下 NLog 的 GitHub 中也有提供,
      https://github.com/jkowalski/NLog/tree/master/examples/targets/Configuration%20File/Database/MSSQL

      如果說是要這篇文章最後的進階 NLog LogTable Schema 的話,在 twMVC 官網中的活動記錄「2012_06_14 攻略 ASP.NET MVC ─ 從無到有 與 偵測監控」http://mvc.tw/Event/2012/6/14
      網頁下面的範例程式「ASP.NET MVC 偵錯與監控 範例下載」則是有提供。

      刪除
  2. 謝謝大大
    看完這系列的文章
    受益良多

    回覆刪除
  3. 請問 文中的
    dbhost:你所使用的資料庫位置,可以輸入host名稱,但是不能接受IP
    但我輪入IP卻是可以連線的耶

    回覆刪除
    回覆
    1. Hello
      因為這篇文章已經快五年了,這五年的技術有所更迭與套件功能更新,
      所以與你目前所使用的最新版本內容會有所差異,這部分還需要以官網所公布的技術文件為主。

      刪除

提醒

千萬不要使用 Google Talk (Hangouts) 或 Facebook 及時通訊與我聯繫、提問,因為會掉訊息甚至我是過了好幾天之後才發現到你曾經傳給我訊息過,請多多使用「詢問與建議」(在左邊,就在左邊),另外比較深入的問題討論,或是有牽涉到你實作程式碼的內容,不適合在留言板裡留言討論,請務必使用「詢問與建議」功能(可以夾帶檔案),謝謝。