ログ

環境　Visual Studio Community 2017
言語　C#

##インストール
Nugetで「log4net」をキーワードに検索し、作成者「The Apache Software Foundation」のものをインストール。(2017/8/22現在のバージョンは2.0.8)

##バージョン1.*系と2.*系の違い
リリースノート
https://logging.apache.org/log4net/release/release-notes.html
1.2.15と2.0.6と同じで、NuGet対応したのでバージョン番号を調整したとのこと。
基本的に1.2.15の資料を参考にして問題なし。

##使い方
###1.設定ファイルを作成する。

設定ファイルの作り方は以下のページを参照する。
[HIRO's.NET Blog](http://blog.hiros-dot.net/?p=5468)

NuGetでインストールすると、コンパイル時にlog4net.dllの他にlog4net.xmlも出力先フォルダにコピーされる。
そのため、設定ファイルをApp.configに記載する方法もあるが、今回は自分で「log4net.xml」という名前でファイルを作成して、上書きするようにする。

###2.設定ファイルの保存場所を設定する

上記で作成した設定ファイルを使うようAssemblyInfo.csに記載する。

```csharp:AssemblyInfo.cs
[assembly: log4net.Config.XmlConfigurator(Watch = true, ConfigFile = "log4net.xml")]
```

ソリューションの中に複数のプロジェクトがある場合でも、共通モジュール用のプロジェクトのAssemblyInfo.csのみ修正するだけでOK。

###3.ログ管理用クラスの作成
上記でAssemblyInfo.csを設定したプロジェクトの中に以下のようなログ管理用クラスを作成する。(namespaceは省略)

```csharp:ログ管理用クラス.cs
using log4net;

public class CustomLog
{
    private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    public static ILog GetILog()
    {
        return log;
    }
}
```

###4.使い方

上記で作成したログ管理用クラスを使用してILogを取得する。

```csharp:ログ出力したいクラス.cs
public partial class MainWindow : Window
{
    ILog log;

    public MainWindow()
    {
        log = CustomLog.GetILog();
        InitializeComponent();
    }

    private void sample()
    {
        log.Debug("ログ出力します");
    }
}
```

##TIPS
###プロセスIDを出力
ソース上に

```csharp:プロセスIDを出力
log4net.GlobalContext.Properties["pid"] = System.Diagnostics.Process.GetCurrentProcess().Id;
```
と書いて、ログ設定ファイルで

```xml:log4net.xml
<ConversionPattern value="%date [%property{pid}][%thread] [%-5level] (%method) - %message%n" />
```
とする。
先ほどのログ管理用クラスを拡張したもの。

```csharp:ログ管理用クラス2.cs
    public class CustomLog
    {
        private static CustomLog instance = new CustomLog();

        private CustomLog()
        {
            log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
            log4net.GlobalContext.Properties["pid"] = System.Diagnostics.Process.GetCurrentProcess().Id;
        }

        private ILog log;
        public static ILog Log
        {
            get { return instance.log; }
        }
    }
```

###複数プロセスから同じログファイルに出力
Appenderの設定部分にて

```xml:log4net.xml
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
```
を追加する。

###ログファイル名を動的に変更

設定されているリポジトリを取得し、上書きする。

```csharp:ログ管理用クラス3.cs
    public class CustomLog
    {
        private static CustomLog instance = new CustomLog();

        private CustomLog()
        {
            log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

            // ログファイルにプロセス番号も出力できるようにする
            int pid = System.Diagnostics.Process.GetCurrentProcess().Id;
            log4net.GlobalContext.Properties["pid"] = pid;

            // 出力するログファイル名を動的に変更するため設定されているFileAppenderを取得する
            const string APPENDER_NAME = "test1";
            FileAppender fileAppender = LogManager.GetRepository().GetAppenders().OfType<FileAppender>().First((e) => e.Name.Equals(APPENDER_NAME));

            // ファイル名を「MyLog_{YYYYMMDD}_{pid}.log」の形式に置き換え、変更前のファイルを削除する
            string file = fileAppender.File;
            if (!string.IsNullOrEmpty(file) && file.Contains("MyLog"))
            {
                fileAppender.File = file.Replace("MyLog", string.Format("MyLog_{0}_{1}.log", DateTime.Now.ToString("yyyyMMdd"), pid));
                fileAppender.ActivateOptions();
                File.Delete(file);
            }
        }

        private ILog log;
        public static ILog Log
        {
            get { return instance.log; }
        }
    }
```

```xml:log4net.xml
    <appender name="test1" type="log4net.Appender.RollingFileAppender">
      <!-- ログ・ファイル名の先頭部分 -->
      <File value="C:\Work\MyLog" />
      <!-- 追加書き込み -->
      <appendToFile value="true" />

      <!-- 複数プロセスから書けるように -->
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
      <!-- ログの書式 -->
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%d[%t][%property{pid}] (%M)%p - %m%n"/>
      </layout>
    </appender>
```