5

Windsor Logging Facility と NLog 統合を使用して、プロジェクトにログを追加する作業を行っています。

Logロギングをサポートしたいすべてのクラスにプロパティを追加するという Windsor ドキュメントの推奨プラクティスに従うのではなく、動的インターセプトを使用してそれを行う方法を試すことにしました。これまでのところ、インターセプターはかなり基本的なものです。コンストラクター注入を使用してのインスタンスを取得するだけですILogger:

class LoggingInterceptor : IInterceptor
{
    private readonly ILogger _logger;
    public LoggingInterceptor(ILogger logger)
    {
        if (logger == null) throw new ArgumentNullException("logger");
        _logger = logger;
    }

    public void Intercept(IInvocation invocation)
    {
        // just a placeholder implementation, I'm not actually planning to do this ;)
        _logger.Info(invocation.Method.Name);
        invocation.Proceed();
    }
}  

それ以上は、インターセプターを登録してコンポーネントに適用するための最低限の作業を行っただけで、残りはロギング機能によって処理されます。

container.Register(Component.For<LoggingInterceptor>().LifeStyle.Transient);

container.Register(
    Component.For<IEmployeeRepository>()
    .ImplementedBy<EmployeeRepository>()
    .Interceptors(InterceptorReference.ForType<LoggingInterceptor>()).First);

これまでのところ、まあまあです。私が取得したロガーは、クラスごとに 1 つのロガーという NLog の推奨プラクティスに従っています。この場合、それはあまり良い選択ではないと思います。これは、すべてのメッセージが「MyApplication.Interceptors.LoggingInterceptor」という名前のログに送られることを意味しますが、これはあまり役に立ちません。

ロガーが適用された抽象化に基づいてログに名前を付けたいと思います。たとえば、ロガーが の実装に適用されている場合IEmployeeRepository、ログの名前はEmployeeRepository. これは実行可能ですか?

編集:ILoggerFactoryカスタムを実装し、代わりにそれを使用するようにコンテナーに指示 しようとしました。しかし、私はすぐに障害にぶつかりました。Windsor がファクトリを呼び出したときに提供される情報は、ロガーが取得されているオブジェクトのタイプだけです。オブジェクトに関するその他の情報は提供されないため、ILoggerFactoryはインターセプターが適用された抽象化について知る方法がありません。

ILoggerFactory.Create()文字列を引数として受け入れるの 2 つのオーバーロードがあることに気付きました。ウィンザーはどちらも直接使用していないようですが、何らかの理由でそこにいる必要があると推測できます。特定の文字列を使用することを指定するために使用できる流暢な登録 API には何かありますか?

4

1 に答える 1

6

これはあなたの質問に非常によく似た質問で、受け入れられた回答があります。リンクで、回答を投稿した人は、インターセプターを ILoggerFactory に依存させることを提案し、 Intercept メソッドでは、タイプとして IInvocation.TargetType を使用して ILoggerFactory に送信し、適切なロガーを取得します。

私はCastleを使用していないので、この提案についてこれ以上コメントすることはできません.

public class LoggingInterceptor : IInterceptor
{
    private readonly ILoggerFactory _loggerFactory;

    public LoggingInterceptor(ILoggerFactory loggerFactory)
    {
        _loggerFactory = loggerFactory;
    }

    public void Intercept(IInvocation invocation)
    {
        var logger = _loggerFactory.Create(invocation.TargetType);
        if (logger.IsDebugEnabled)
        {
            logger.Debug(CreateInvocationLogString(invocation));
        }
        try
        {
            invocation.Proceed();
        }
        catch (Exception e)
        {
            logger.Warn(CreateInvocationLogString(invocation));
            throw;
        }
        logger.Info(CreateInvocationLogString(invocation));
    }

    private static String CreateInvocationLogString(IInvocation invocation)
    {
        var sb = new StringBuilder(100);
        sb.AppendFormat("Called: {0}.{1}(", invocation.TargetType.Name, invocation.Method.Name);
        foreach (var argument in invocation.Arguments)
        {
            var argumentDescription = argument == null ? "null" : argument.ToString();
            sb.Append(argumentDescription).Append(",");
        }
        if (invocation.Arguments.Any())
        {
            sb.Length--;
        }
        sb.Append(")");
        return sb.ToString();
    }
}

Castle: ロギング インターセプターで正しい ILogger を取得するにはどうすればよいですか?

おそらくすでにこれを見たことがあるでしょうが、ロギングインターセプターを作成する方法と、ラップされた型のロガーを作成する方法を示すキャッスルの例へのリンクを次に示します。

http://docs.castleproject.org/Windsor.Introduction-to-AOP-With-Castle.ashx

編集: nlog の ILoggerFactory の実装は ExtendedNLogFactory で、Castle.Core-NLog nuget パッケージ ( http://www.nuget.org/packages/Castle.Core-NLog )にあります。

于 2012-12-12T21:11:32.423 に答える