🗂

【C#】log4netを利用したログ出力

2024/12/11に公開

仕事でlog4netを利用したログ出力処理に手直しをする必要がでてきたのですが、そもそもlog4netの使い方がわからなかったため、調べてみました。

↓ Log4netの公式マニュアル
https://logging.apache.org/log4net/

※執筆中です。

環境

  • VisualStudio 2022
  • C# 10.0
  • .Net 6.0
  • ログ出力ライブラリ:log4net(2.0.15)

log4netとは

log4netとはログ出力機能を提供するライブラリです。
ログ出力機能を提供するライブラリはほかにもさまざまなものありますが、今回はlog4netについて見ていきたいと思います。

さて、log4netには以下の2つの特徴があります。

  • ロガーとアペンダーの組み合わせでログを処理
  • 階層構造でロガーを管理

ロガーとアペンダー

log4netでは、ロガーとアペンダーの組み合わせによってログを処理します。

まず、アペンダーはログを実際に出力する機能を持っています。ロガーから渡されたログをさまざまな方法で出力します。ファイルに出力するのか、コンソール画面に出力するのか、はたまた別の出力形式なのかはこのアペンダーによって変わります。なお、ログレベルによってどのログを出力するのかを制御します。

ロガーとはログをアペンダーに渡す機能を持っています。ログレベル(のちほど紹介します)によってどのログをアペンダーに渡すのかを制御(フィルタリング)します。

構造的にはロガーがアペンダー(の参照)を持っているカタチになります。

なお1つのロガーに複数のアペンダーを持たせることもできるため、同じログメッセージを複数の出力先に送ることもできます。

階層型ロガー

log4netでは複数のロガーを管理することができ、ロガーは階層型に管理されています。

親ロガーの設定(ログレベルなど)が子ロガーの設定に適用されます。そのうえで子ロガー独自の設定に一部変更することもできます。

イメージとしてはクラスの継承と同じです。クラスの継承では基底クラスが持っているメンバ変数やメソッドなどを、そのクラスを継承した派生クラスでも使えます。また、オーバーライドすることでメソッドを派生クラス独自の処理に変更できると思います。ロガーも同じような感じで、親ロガーの設定が子ロガーに適用され、子ロガーでそれ独自の設定に変えることができます。

このような階層化されてロガーが管理されていることを「階層型ロガー」とよび、log4netではそのようにロガーを管理することができます。

ログレベルによる制御(フィルタリング)

ログの出力処理を実装するうえで重要になるのが「ログレベル」です。
ログレベルとは、かんたんに言うとログの種類をその内容によって分別できるようにしたものです。ログレベルを使うことでログ出力を制御できるようになります。

さて、log4netにはログの種類ごとに主に以下の5つのログレベルがあります。ログの内容によって適切なログレベルを設定する必要があります。

  • DEBUG
  • INFO
  • WARN
  • ERROR
  • FATAL

log4netのロガーには「Debug()」や「Info()」などのログ処理用メソッドが用意されています。たとえば「Debug()」を使うとレベルがDEBUGのログを作成されます。

log4netのロガーとアペンダーには処理対象とするログレベルを設定することができます。

  • ALL
  • DEBUG
  • INFO
  • WARN
  • ERROR
  • FATAL
  • OFF

設定したログレベルよりも高いレベルのログが記録・出力されます。

ここで、「ロガーとアペンダーにそれぞれ別のログレベルを設定できる」点に注目しましょう。
例としてロガーのログレベルを「INFO」に設定し、アペンダーのログレベルを「WARN」た場合で考えてみましょう。この場合「DEBUG」ログはロガーではじかれて出力さません。「INFO」ログはロガーにはじかれずアペンダーに渡されますが出力はされません。「WARN」「ERROR」「FATAL」ログのみ出力されます。

なお「ALL」に設定するとすべてのレベルのログが処理され、「OFF」はすべてのレベルのログが処理されません。

適切なログレベルを設定するで適切なログが記録・出力できるようになるわけです。

log4netの使い方

[1]log4netのインストール

まずは、NuGetを利用してlog4netをインストールします。

ログ出力機能を使いたいプロジェクトを右クリックして、「依存関係」>「NuGetパッケージの追加」をクリックします。

すると「Nugetパッケージマネージャー」が表示されるので、左上の「参照」をクリックします。
検索欄に「log4net」と入力すると、検索欄に唐辛子みたいなアイコンの「log4net」というパッケージが表示されます。
今回はバージョン選択コンボボックスで「2.0.15」を選択して、インストールをクリックしてインストールします。

インストールボタンを押すと「変更のプレビュー」なるダイアログが表示されるので、「適用」をクリックしてインストールを進めます。

インストールにかかる時間は人によって変わりますが、だいたい10秒ほどで終わるはずです。
「インストール済み」タブに「log4net」が表示されていればインストール完了です。

なおインストールが完了すると、ソリューションエクスプローラーで「プロジェクト名」>「依存関係」>「パッケージ」に「log4net(2.0.15)」が追加されていることも確認できます。

[2]ログを出力できるようにしよう

前述したように、ログを出力するには「ロガー」と「アペンダー」を作成し、ロガーにアペンダーを登録する必要があります。

実際のソースコードを見る前にまず、log4netでどのようにロガーを管理しているのかざっくりとイメージしておく必要があります。

1つのアプリ上で複数のロガーを作成し利用することができます。各ロガーはログリポジトリと呼ばれるアセンブリに紐づけられるものによって管理されており、さらに複数のログリポジトリがログマネージャーと呼ばれるものによって管理されています。なお複数のロガーたちはログリポジトリ内で「階層型」で管理されています。

【参考】
ログリポジトリ

log4netでロガーがどのように管理されているのかがイメージできたところで、さっそく実際のソースコードを見てみましょう。今回はログファイルにログを出力するロガーを1つ作成して、ログを出力してみたいと思います。

public class Program
{
    static void Main(string[] args)
    {
        // Mainという名前のロガーを取得(ロガーの作成も行われます)
        var logger = LogManager.GetLogger("Main");

        // アペンダー(ログの出力を担当するオブジェクト)の作成
        var a = new RollingFileAppender()
        {
            Name = "RollingFileAppender",   // Appenderの名前
            File = "aa.log",            // 出力ファイル名
            AppendToFile = true,        // 追記モード
            Layout = new PatternLayout("%date %-5level %logger - %message%newline"),    // ログのフォーマット
            RollingStyle = RollingFileAppender.RollingMode.Size,    // ログローテーションのスタイル(サイズごと)
            MaxFileSize = 10 * 1024,    // 10KBごとにローテーション
            MaxSizeRollBackups = 5,     // 最大バックアップ数
            StaticLogFileName = true,   // ログファイル名を固定にする
            Threshold = log4net.Core.Level.Info     //ログレベルの設定
        };

        // アペンダーをロガーに登録
        var mainLogger = (Logger)logger.Logger;
        mainLogger.AddAppender(rollingFileAppender);
        rollingFileAppender.ActivateOptions();

        // ロガーの設定を有効にする
        var hierarchy = (Hierarchy)LogManager.GetRepository();
        hierarchy.Configured = true;

        // ロガーを使ってログ出力要求
        logger.Debug("これはデバッグメッセージです。");
        logger.Info("これは情報メッセージです。");
        logger.Warn("これは警告メッセージです。");
        logger.Error("これはエラーメッセージです。");
        logger.Fatal("これは致命的なエラーメッセージです。");
    }
}

ログを出力できるようにするためには以下の手順を踏みます

  1. ロガーの作成
  2. アペンダーの作成
  3. ロガーにアペンダーを登録
  4. 設定の有効化
    (5. ロガーを使ってログ出力要求)

[2-1]ロガーの作成

// Mainという名前のロガーを取得(生成も行われます)
var logger = LogManager.GetLogger("Main");

LogManager.GetLogger()を使用することで、現在のアセンブリに対応したログリポジトリからロガーを取得できます。引数にロガーの名前を指定でき、その名前のロガーを取得できます。
もしログリポジトリにその名前のロガーが存在しない場合は新しく作られたうえで取得できます。

[2-2]アペンダー(ログの出力を担当するオブジェクト)の作成

// Appender(ログ出力先の設定)
var rollingFileAppender = new RollingFileAppender()
{
    Name = "RollingFileAppender",   // Appenderの名前
    File = "aa.log",            // 出力ファイル名
    AppendToFile = true,        // 追記モード
    Layout = new PatternLayout("%date %-5level %logger - %message%newline"),    // ログのフォーマット
    RollingStyle = RollingFileAppender.RollingMode.Size,    // ログローテーションのスタイル(サイズごと)
    MaxFileSize = 10 * 1024,    // 10KBごとにローテーション
    MaxSizeRollBackups = 5,     // 最大バックアップ数
    StaticLogFileName = true,   // ログファイル名を固定にする
    Threshold = log4net.Core.Level.Info     //ログレベルの設定
};

前述したようにアペンダーとはログの出力を担当するオブジェクトです。
log4netでは20種類くらいのアペンダーが用意されています。今回はローリングをしながらログファイルにログを出力したいためRollingFileAppenderを使ってみました。

ローリングとはログの無制限の生成を防ぐためのモノです。単純にファイルに出力するだけではログが無制限に出力されてしまい、HDDやSSDなどの記憶領域を埋め尽くしてしまう危険があります。そのためファイルにログを出力したいときは上記のようにRollingFileAppenderを使ってローリングされるようにするべきです。

なお、log4netが提供しているアペンダー(IAppederを実装しているクラス)は以下のサイトで確認できます。
https://logging.apache.org/log4j/1.x/apidocs/org/apache/log4j/Appender.html

[2-3]ロガーにAppederを登録

// アペンダーを設定するためにLoggerオブジェクトを取得
var mainLogger = (Logger)logger.Logger;

// AddAppender()を利用してアペンダーを登録
mainLogger.AddAppender(rollingFileAppender);

// アペンダーを有効化
rollingFileAppender.ActivateOptions();

ロガーの出力設定であるAppenderを作成したら、それをロガーに登録します。

ロガーのLoggetプロパティにアクセスして、Appederを設定するメソッドを持ったLoggerオブジェクトを取得します。そのLoggerオブジェクトのAddAppender()を使用してAppederを登録します。
なお、AppederはActiveOptions()で有効化しておくことも忘れないようしましょう。

[3-4]設定の有効化

// ログリポジトリを取得
var hierarchy = (Hierarchy)LogManager.GetRepository();

// 設定の有効化
hierarchy.Configured = true;

ロガーにAppederを登録して有効化したら「設定の完了」処理を実行してあげる必要があります。

LogManager.GetRepository()でログリポジトリを取得します。しかしそのままだと設定の有効化をするためのプロパティ(Configuredプロパティ)にアクセスできません。なのでHierarchyオブジェクトにキャストします。
Hierarchyとはロガーを管理しているクラスで、ログリポジトリは内部的にはHierarchyオブジェクトになっています。

Configuredプロパティにtrueを設定することでロガーの設定が有効化されます。

[3]ロガーを使ってログを処理・出力

ここまでくればあとはロガー使ってログを処理・出力できます。

ロガーには以下のように、ログレベルに応じた5つのメソッドが用意されています。

// いろんなログ出力
logger.Debug("これはデバッグメッセージです。");
logger.Info("これは情報メッセージです。");
logger.Warn("これは警告メッセージです。");
logger.Error("これはエラーメッセージです。");
logger.Fatal("これは致命的なエラーメッセージです。");

たとえば「Debug("ログメッセージ")」を使うと、DEBUGレベルのログを処理するようにロガーに要求できます。ロガーは受け取ったログをログレベルによって制御(フィルタリング)して記録しアペンダーに渡します。アペンダーは渡されたログのうち、出力すべきログレベルのログのみ出力します。

Discussion