NLogは、.NETアプリケーション向けの堅牢で高機能なログライブラリです。コンソール、ファイル、クラウドサービスなど、様々な出力先(ターゲット)にログを記録する機能を提供しますが、特にデータベースへのログ記録は、集中的なログ管理において非常に有用です。本記事では、NLogを使用してログをSQL Serverデータベースに記録するための設定と実装方法を解説します。
NLogのインストールと初期設定
まず、新しい.NETプロジェクト(例えば、コンソールアプリケーション)を作成し、NuGetパッケージマネージャーを使用してNLogをインストールします。
Install-Package NLog
NLogパッケージがインストールされると、プロジェクトにNLog.configというXML設定ファイルが自動的に追加されます。このファイルがNLogの動作を制御する中心となります。
データベースターゲットの構成
NLog.configファイルを開き、<targets>セクション内にデータベースへのログ記録を設定するターゲットを追加します。
<target xsi:type="Database"
name="databaseLog"
connectionString="Data Source=.;Initial Catalog=LogDB;Integrated Security=True">
<commandText>
INSERT INTO ApplicationLogs ([Timestamp], [OriginCaller], [LogLevel], [MessageText], [StackTraceInfo])
VALUES (@timestamp, @originCaller, @logLevel, @messageText, @stackTraceInfo);
</commandText>
<parameter name="@timestamp" layout="${longdate}" /> <!-- ログ発生時刻 -->
<parameter name="@originCaller" layout="${callsite}" /> <!-- ログ呼び出し元 -->
<parameter name="@logLevel" layout="${level}" /> <!-- ログレベル -->
<parameter name="@messageText" layout="${message}" /> <!-- ログメッセージ -->
<parameter name="@stackTraceInfo" layout="${stacktrace}" /> <!-- スタックトレース情報 -->
</target>
上記の構成では、以下の点を設定しています:
xsi:type="Database": ターゲットがデータベースであることを指定します。name="databaseLog": このターゲットを一意に識別する名前です。connectionString: データベースへの接続文字列です。ここではSQL ServerのローカルインスタンスにあるLogDBデータベースを指定しています。commandText: ログをデータベースに挿入するためのSQLINSERT文です。<parameter>: SQL文の各パラメータと、NLogのレイアウトレンダラをマッピングします。例えば、${longdate}は現在の日時、${level}はログレベルに置き換えられます。
ログを記録する前に、指定したデータベースにログ情報を格納するためのテーブルを作成しておく必要があります。以下にApplicationLogsテーブルの作成例を示します。
CREATE TABLE ApplicationLogs (
LogID INT IDENTITY(1,1) PRIMARY KEY,
Timestamp DATETIME NOT NULL,
OriginCaller NVARCHAR(500),
LogLevel NVARCHAR(10) NOT NULL,
MessageText NVARCHAR(MAX),
StackTraceInfo NVARCHAR(MAX)
);
ロギングルールの定義
次に、どのログメッセージをどのターゲットに送るかを指定するルールを<rules>セクションに追加します。
<rules>
<logger name="*" minlevel="Info" writeTo="databaseLog" />
</rules>
このルールは、「すべてのロガー(name="*")からのInfoレベル以上のログを、databaseLogという名前のターゲットに書き込む」ことを意味します。
C#コードからのログ記録
NLogの設定が完了したら、C#コードからログを記録します。以下は簡単なコンソールアプリケーションの例です。
using NLog;
using System;
public class Program
{
private static readonly Logger appLogger = LogManager.GetCurrentClassLogger();
public static void Main(string[] args)
{
// ログレベルFatalのメッセージを記録
appLogger.Fatal("アプリケーションで致命的なエラーが発生しました。詳細はログを確認してください。");
// ログレベルErrorのメッセージを記録
appLogger.Error(new Exception("Null参照エラー"), "ユーザー情報の取得中に予期せぬ問題が発生しました。");
Console.WriteLine("ログメッセージをデータベースに送信しました。");
Console.ReadKey();
}
}
このコードを実行すると、設定に応じてデータベースにログエントリが追加されます。
複数のターゲットへのログ記録とデバッグ設定
NLogでは、ログレベルに応じて異なるターゲットにログを振り分けることができます。例えば、すべてのログをファイルに、エラーレベル以上のログをデータベースに記録するといった設定が可能です。
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
throwExceptions="true" internalLogFile="c:\nlog_internal_errors.txt" internalLogLevel="Debug">
<targets>
<target name="fileLog" xsi:type="File"
fileName="${basedir}/logs/application-${shortdate}.txt"
layout="${longdate} | ${level:uppercase=true} | ${callsite} | ${message} ${exception:format=tostring}" />
<target name="databaseLog" xsi:type="Database"
connectionString="Data Source=.;Initial Catalog=LogDB;Integrated Security=True">
<commandText>
INSERT INTO ApplicationLogs ([Timestamp], [OriginCaller], [LogLevel], [MessageText], [StackTraceInfo])
VALUES (@timestamp, @originCaller, @logLevel, @messageText, @stackTraceInfo);
</commandText>
<parameter name="@timestamp" layout="${longdate}" />
<parameter name="@originCaller" layout="${callsite}" />
<parameter name="@logLevel" layout="${level}" />
<parameter name="@messageText" layout="${message}" />
<parameter name="@stackTraceInfo" layout="${stacktrace}" />
</target>
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="fileLog" /> <!-- 全てのログをファイルに -->
<logger name="*" minlevel="Error" writeTo="databaseLog" /> <!-- エラー以上のログをデータベースに -->
</rules>
</nlog>
<nlog>ルート要素のthrowExceptions="true"、internalLogFile、internalLogLevel属性は、NLog自身の内部エラーやデバッグ情報を指定したファイルに出力するためのもので、ログ設定の問題を診断する際に非常に役立ちます。
カスタムプロパティの利用
NLogが提供する標準のログ情報だけではなく、アプリケーション固有の追加情報をログに含めたい場合があります。NLogでは、event-contextレイアウトレンダラを使用してカスタムプロパティを定義し、ログに含めることができます。
まず、データベーステーブルに新しいカスタムカラムを追加します。例えば、AppName、ModuleName、CorrelationIDなどです。
CREATE TABLE ExtendedApplicationLogs (
LogID INT IDENTITY(1,1) PRIMARY KEY,
AppName NVARCHAR(100),
ModuleName NVARCHAR(100),
CorrelationID NVARCHAR(50),
Timestamp DATETIME NOT NULL,
LogLevel NVARCHAR(10) NOT NULL,
MessageText NVARCHAR(MAX),
StackTraceInfo NVARCHAR(MAX)
);
次に、NLog.configを更新してこれらのカスタムプロパティをデータベースターゲットにマッピングします。
<target name="customDatabaseLog" xsi:type="Database"
connectionString="Data Source=.;Initial Catalog=LogDB;Integrated Security=True">
<commandText>
INSERT INTO ExtendedApplicationLogs ([AppName], [ModuleName], [CorrelationID], [Timestamp], [LogLevel], [MessageText], [StackTraceInfo])
VALUES (@appName, @moduleName, @correlationId, @timestamp, @logLevel, @messageText, @stackTraceInfo);
</commandText>
<parameter name="@appName" layout="${event-context:item=AppName}" />
<parameter name="@moduleName" layout="${event-context:item=ModuleName}" />
<parameter name="@correlationId" layout="${event-context:item=CorrelationID}" />
<parameter name="@timestamp" layout="${longdate}" />
<parameter name="@logLevel" layout="${level}" />
<parameter name="@messageText" layout="${message}" />
<parameter name="@stackTraceInfo" layout="${stacktrace}" />
</target>
そして、C#コードからこれらのカスタムプロパティを設定してログを記録します。LogEventInfoクラスを使用し、Propertiesディクショナリを介して値を渡します。
using NLog;
using System;
public class Program
{
private static readonly Logger customLogger = LogManager.GetLogger("CustomLog"); // 新しいロガー名
// カスタムプロパティを含むログを記録するメソッド
public static void LogCustomEvent(LogLevel level, string appName, string moduleName, string correlationId, string message)
{
LogEventInfo logEvent = new LogEventInfo(level, customLogger.Name, message);
logEvent.Properties["AppName"] = appName;
logEvent.Properties["ModuleName"] = moduleName;
logEvent.Properties["CorrelationID"] = correlationId;
customLogger.Log(logEvent);
}
public static void Main(string[] args)
{
LogCustomEvent(LogLevel.Info, "OrderProcessingApp", "PaymentModule", Guid.NewGuid().ToString(), "支払い処理が正常に完了しました。");
LogCustomEvent(LogLevel.Warn, "OrderProcessingApp", "InventoryModule", Guid.NewGuid().ToString(), "在庫レベルが閾値を下回りました。");
Console.WriteLine("カスタムログメッセージをデータベースに送信しました。");
Console.ReadKey();
}
}
このアプローチにより、アプリケーションのニーズに合わせて柔軟にログデータを拡張し、データベースに保存することが可能になります。