共有アセンブリを使用しているときに log4net を構成するにはどうすればよいですか?
共通コンポーネントに依存する複数のコンポーネントがあります。各コンポーネントは、独自のアセンブリに存在します。すべてのコンポーネントは、ログに log4net を使用します。すべてのコンポーネントは単一のプロセス空間にロードされますが、コンポーネントの使用順序は異なります。すべての外部コンポーネントは、最初の使用時にそれぞれの log4net 構成をロードして、ログ データをそれらに送信しようとします。共通コンポーネントは構成をロードしません。さらに、共通コンポーネントを使用しないレガシー コンポーネントがあります。また、最初の使用時にその構成を外向きにしてロードします。このレガシー コンポーネントのコードや構成に直接触れることはできません。
私が直面している問題は、コンポーネントが最初の使用時に構成をロードするため、最後に構成をロードした人が勝つということです。これにより、ログが記録されますが、すべてのログ出力は最後に読み込まれた構成に出力されます。明らかに、自分のログ ファイルを調べて、他のコンポーネントのログ エントリがそこに書き込まれているのは見苦しいだけです。
私は、RepositoryAttribute と AliasRepositoryAttribute を使用して、部分的な解決策を見つけました。を使用すると、外部コンポーネントが構成を「ロガー リポジトリ」にロードし、互いに効果的に分離できます。レガシー コンポーネントは、自分のコンポーネントからのノイズなしで独自のログに問題なく書き込みを行うようになり、コンポーネントは他のログにノイズを生成することなく、独自のログに問題なく書き込んでいます。
共通コンポーネントのロギングの状況がまだ存在するため、部分的な解決策と言いました。AliasRepositoryAttribute を使用すると、共通コンポーネントを呼び出していた別のコンポーネントであっても、ロードされて共通コンポーネントにエイリアスを設定する最初のコンポーネントがすべてのログ出力を取得します。後のコンポーネントで重要なログ情報が失われ、最初のログには関連のないログ情報が含まれるため、これはひどいことです。
次のコードは、この問題を示しています。
共通: (共通コンポーネントの代用)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using log4net;
using log4net.Config;
[assembly: Repository("CommonLib")]
namespace CommonLib
{
public class CommonClass
{
static readonly ILog Log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public void DoCommon(string from)
{
Log.Debug("DoCommon:" + from);
}
}
}
ライブラリ A: (外部コンポーネントの 1 つに代わる)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using CommonLib;
using log4net;
using log4net.Config;
[assembly: Repository("ALib")]
[assembly: AliasRepository("CommonLib")]
namespace ALib
{
public static class LogPrep
{
static bool _loaded = false;
public static void Ensure()
{
if (_loaded)
return;
var doc = new XmlDocument();
doc.LoadXml(
@"<log4net xsi:noNamespaceSchemaLocation='http://csharptest.net/downloads/schema/log4net.xsd'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
debug='true'>
<appender name='ConsoleAppender' type='log4net.Appender.ColoredConsoleAppender'>
<mapping>
<level value='DEBUG' />
<foreColor value='White' />
<backColor value='Green' />
</mapping>
<layout type='log4net.Layout.PatternLayout'>
<conversionPattern value='ALib: %d{yyyy MMM dd HH:mm:ss} [%p] %c{1} %mdc - %m%n' />
</layout>
</appender>
<root>
<level value='DEBUG' />
<appender-ref ref='ConsoleAppender' />
</root>
</log4net>");
XmlConfigurator.Configure(doc.DocumentElement);
_loaded = true;
}
}
public class AClass
{
static readonly ILog Log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public void DoA()
{
LogPrep.Ensure();
Log.Debug("DoA");
var common = new CommonClass();
common.DoCommon("A");
}
}
}
ライブラリ B: (別の外部コンポーネントの代用)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using CommonLib;
using log4net;
using log4net.Config;
[assembly: Repository("BLib")]
[assembly: AliasRepository("CommonLib")]
namespace BLib
{
public class BClass
{
static readonly ILog Log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public static class LogPrep
{
static bool _loaded = false;
public static void Ensure()
{
if (_loaded)
return;
var doc = new XmlDocument();
doc.LoadXml(
@"<log4net xsi:noNamespaceSchemaLocation='http://csharptest.net/downloads/schema/log4net.xsd'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
debug='true'>
<appender name='ConsoleAppender' type='log4net.Appender.ColoredConsoleAppender'>
<mapping>
<level value='DEBUG' />
<foreColor value='White' />
<backColor value='Red' />
</mapping>
<layout type='log4net.Layout.PatternLayout'>
<conversionPattern value='BLib: %d{yyyy MMM dd HH:mm:ss} [%p] %c{1} %mdc - %m%n' />
</layout>
</appender>
<root>
<level value='DEBUG' />
<appender-ref ref='ConsoleAppender' />
</root>
</log4net>");
XmlConfigurator.Configure(doc.DocumentElement);
_loaded = true;
}
}
public void DoB()
{
LogPrep.Ensure();
Log.Debug("DoB");
var common = new CommonClass();
common.DoCommon("B");
}
}
}
実行可能コンテナ: (レガシー コンポーネントの代わり)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using ALib;
using BLib;
using log4net;
using log4net.Config;
namespace TestLog4NetRepositories
{
class Program
{
private static readonly ILog Log = LogManager.GetLogger(typeof(Program));
static void Main(string[] args)
{
// Set up a simple configuration that logs on the console.
var doc = new XmlDocument();
doc.LoadXml(
@"<log4net xsi:noNamespaceSchemaLocation='http://csharptest.net/downloads/schema/log4net.xsd'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
debug='true'>
<appender name='ConsoleAppender' type='log4net.Appender.ColoredConsoleAppender'>
<mapping>
<level value='DEBUG' />
<foreColor value='White' />
<backColor value='Blue' />
</mapping>
<layout type='log4net.Layout.PatternLayout'>
<conversionPattern value='Main: %d{yyyy MMM dd HH:mm:ss} [%p] %c{1} %mdc - %m%n' />
</layout>
</appender>
<root>
<level value='DEBUG' />
<appender-ref ref='ConsoleAppender' />
</root>
</log4net>");
XmlConfigurator.Configure(doc.DocumentElement);
Log.Info("Entering application.");
var a = new AClass();
a.DoA();
var b = new BClass();
b.DoB();
Log.Info("Exiting application.");
}
}
}
このコードを実行すると、Common の出力が緑で印刷され、赤で印刷されないことに注意してください。
log4net: Creating repository [BLib] using type [log4net.Repository.Hierarchy.Hierarchy]
log4net:ERROR Failed to alias repository [CommonLib] System.InvalidOperationException: Repository [CommonLib] is already aliased to repository [ALib]. Aliases cannot be redefined.
at log4net.Core.DefaultRepositorySelector.AliasRepository(String repositoryAlias, ILoggerRepository repositoryTarget)
at log4net.Core.DefaultRepositorySelector.LoadAliases(Assembly assembly, ILoggerRepository repository)
上記の実行可能コンテナーでは、A が B の前に表示されていますが、実際の状況では、B が A の前にある場合があります。
前に述べたように、私はより複雑な階層を持っていますが、上記は私が直面している最小限の問題を示しています。