前回までで、ざっとWPF アプリを作成したので、今回は Log4net を実装します。
Log4net インストール
NuGet パッケージマネージャーで Log4net を取得します。
AssemblyInfo.cs に Log4net の定義を追加
AssemblyInfo.cs ファイルがない場合は追加しましょう。
[SampleWPF]プロジェクトを右クリック⇒[追加...]⇒[アセンブリ構成ファイル]
- 設定ファイルのパスを指定する。ここではプロジェクト直下の log4net.xmlと指定。
AssemblyInfo.cs
using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
[assembly: log4net.Config.XmlConfigurator(ConfigFile = @"log4net.xml", Watch = true)]
Log4net 設定ファイルを作成
- log4net.config.xml ファイルを追加する
[SampleWPF]プロジェクトを右クリック⇒[追加...]⇒[XML ファイル]
以下、ログレベルによる出力ファイルを切り分ける設定のサンプルです。
log4net.xml
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<log4net>
<!-- Appender 設定 -->
<!-- DEBUG level -->
<appender name="DebugAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value=".\logs\DEBUG" />
<param name="AppendToFile" value="true" />
<param name="RollingStyle" value="Date" />
<param name="StaticLogFileName" value="false" />
<param name="DatePattern" value="_yyyyMMdd'.log'" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%date{ISO8601} [%-5level] %message%n" />
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="DEBUG" />
<levelMax value="DEBUG" />
</filter>
</appender>
<!-- INFO/WARN level -->
<appender name="InfoWarnAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value=".\logs\INFO" />
<param name="AppendToFile" value="true" />
<param name="RollingStyle" value="Date" />
<param name="StaticLogFileName" value="false" />
<param name="DatePattern" value="_yyyyMMdd'.log'" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%date{ISO8601} [%-5level] %message%n" />
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="INFO" />
<levelMax value="WARN" />
</filter>
</appender>
<!-- ERROR/FATAL level -->
<appender name="ErrorFatalAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value=".\logs\ERROR" />
<param name="AppendToFile" value="true" />
<param name="RollingStyle" value="Date" />
<param name="StaticLogFileName" value="false" />
<param name="DatePattern" value="_yyyyMMdd'.log'" />
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%date{ISO8601} [%-5level] %message%n" />
</layout>
<filter type="log4net.Filter.LevelRangeFilter">
<levelMin value="ERROR" />
<levelMax value="FATAL" />
</filter>
</appender>
<!-- Appender 指定 -->
<root>
<level value="DEBUG" />
<appender-ref ref="DebugAppender" />
<appender-ref ref="InfoWarnAppender" />
<appender-ref ref="ErrorFatalAppender" />
</root>
</log4net>
</configuration>
MainWindowVM に実装してみる
- Log4net.ILog を定義
private static readonly log4net.ILog logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
- 「CS8603 null 参照の可能性」警告を抑制
#pragma warning disable CS8603
- テストなので、MainWindowVM コンストラクタで確認
// Log4net テスト
logger.Debug("DEBUG level log");
logger.Info("INFO level log");
logger.Warn("WARN level log");
logger.Error("ERROR level log");
logger.Fatal("FATAL level log");
以下、MainWindowVM.cs のソースです。
ViewModels\MainWindowVM.cs
using SampleWPF.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace SampleWPF.ViewModels
{
public class MainWindowVM {
#pragma warning disable CS8602 // null 参照の可能性があるものの逆参照です。
private static readonly log4net.ILog logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
#pragma warning restore CS8602
public static ObservableCollection<User>? userList { get; set; }
public ObservableCollection<User> UserList
{
#pragma warning disable CS8603 // Null 参照戻り値である可能性があります。
get => userList;
#pragma warning restore CS8603
set
{
userList = value;
}
}
// Insert用データ
private string insertFirstName;
public string InsertFirstName
{
get => insertFirstName;
set
{
insertFirstName = value;
}
}
private string insertLastName;
public string InsertLastName
{
get => insertLastName;
set
{
insertLastName = value;
}
}
private void UpdateUserList()
{
using (var dbcx = new SampleDbContext())
{
UserList.Clear();
ObservableCollection<User> uList = new ObservableCollection<User>(dbcx.Users.ToList());
foreach (var user in uList) this.UserList.Add(user);
}
}
// DelegateCommand
public ICommand InsertCommand { get; private set; }
public void ExecuteInsert()
{
using (var dbcx = new SampleDbContext())
{
// LocalDB 更新
User insertUser = new()
{
// Id は LocalDB で自動的に付与される
FirstName = InsertFirstName,
LastName = InsertLastName
};
dbcx.Users.Add(insertUser);
dbcx.SaveChanges();
}
UpdateUserList();
}
public ICommand ListTrashCommand { get; private set; }
public void ExecuteTrash(int id)
{
using (var dbcx = new SampleDbContext())
{
// LocalDB 更新
var user = dbcx.Users.Single(x => x.Id == id);
dbcx.Users.Remove(user);
dbcx.SaveChanges();
}
UpdateUserList();
}
public MainWindowVM()
{
UserList = new ObservableCollection<User>();
InsertCommand = new ForwardedCommand(ExecuteInsert);
ListTrashCommand = new ForwardedCommand<int>(ExecuteTrash);
// CS8618 対応
insertFirstName = "";
insertLastName = "";
// UserList 初期化
UpdateUserList();
// Log4net テスト
logger.Debug("DEBUG level log");
logger.Info("INFO level log");
logger.Warn("WARN level log");
logger.Error("ERROR level log");
logger.Fatal("FATAL level log");
}
}
}
実行してログを確認
DEBUG_20220405.log
2022-04-05 22:24:04,732 [DEBUG] DEBUG level log
ERROR_20220405.log
2022-04-05 22:24:04,741 [ERROR] ERROR level log
2022-04-05 22:24:04,741 [FATAL] FATAL level log
INFO_20220405.log
2022-04-05 22:24:04,740 [INFO ] INFO level log
2022-04-05 22:24:04,741 [WARN ] WARN level log
以上で、Log4net の実装を完了します。
次回予告
次回は、一通りアプリっぽくなったので、WiX を使って Windows Installer を作成する予定です。