1

目標は、ロギングクラスを作成し、ストレージにRavenDBを使用することです。私はもともとRavenDbターゲットに付属していないNLogを使用したかったのですが、簡単に追加できます。私もそうしましたが、ターゲットが意図したとおりに動作していなかったので、それを理解しようとして車輪を回し、最終的に独自のサービスを作成することにしました。

私の意図は、StructureMapを使用してこのロギングサービスをクライアントに注入することでもあります。これが私の初期SM構成です。

x.For<ILogger>().Use<Logger>()
     .Ctor<IDocumentStore>("store").Is(c => c.GetInstance<IDocumentStore>())
     .Ctor<ILogEntry>("logEntry").Is(c => c.GetInstance<ILogEntry>())
     .Ctor<ILogLevelConfig>("logLevelConfig")
     .Is(c => c.GetInstance<ILogLevelConfig>());

x.For<IDocumentStore>()
     .Singleton()
     .Use(() => new DocumentStore { Url="http://localhost:8080/" })
     .OnCreation<IDocumentStore>(c => c.Initialize());

// ILogEntry is implemented by a class, which will eventually be saved in Raven
// ILogLevelConfig is used for configuration purposes

:の簡略化されたバージョンは次のLoggerとおりです。

public class Logger : ILogger
{
    private readonly ILogEntry _logEntry;
    private readonly IDocumentStore _store;
    private readonly ILogLevelConfig _logLevelConfig;

    public Logger(IDocumentStore store, ILogEntry logEntry, ILogLevelConfig logLevelConfig)
    {
        _logEntry = logEntry;
        _logEntry.TimeStamp = new DateTimeOffset(DateTime.UtcNow);
        _logLevelConfig = logLevelConfig;
        _store = store;
    }

    public void Info(string message, string userId = null)
    {
        if (!_logLevelConfig.IsAllEnabled && !_logLevelConfig.IsInfoEnabled) return;
        _logEntry.LogLevel = LogLevel.Info;
        _logEntry.Message = message;
        _logEntry.UserIdentity = userId;
        Write();
    }

    private void Write()
    {
        using(var session = _store.OpenSession())
        {
            session.Store(_logEntry);
            session.SaveChanges();
        }
    }

Loggerそれでは、クライアントへの注入をシミュレートしてみましょう。

var logger = ObjectFactory.GetInstance<ILogger>();
logger.Info("info 1");
logger.Info("info 2");

質問:

  1. 実装方法Write()は、ロガーがデータベースに2回ヒットします['info 1'の場合、次に'info2'の場合。ロギングを非常に詳細に行うことにした場合、これは非常におしゃべりなアプローチになります。すべてlogger.Info(...)を1つにまとめてから、session.SaveChanges()一度呼び出してすべてのエントリを一度に保存するにはどうすればよいですか?
  2. IDocumentStoreこのように実装 を置き換えるx.For<IDocumentStore>().Singleton().Use(() => new EmbeddableDocumentStore { RunInMemory = true, UseEmbeddedHttpServer = true }).OnCreation<IDocumentStore>(c => c.Initialize());と、2番目の呼び出しのみlogger.Info(..)が実際にデータベースに保存されます。なんで?
4

1 に答える 1

2

オブジェクトモデルの問題の1つは、インスタンスがログ要求ごとに作成されるのではなくILogEntry、インスタンスに関連付けられていることです。ILoggerNLogまたはlog4netがどのように実装されているかを見ると、すべてのログ要求に対応するログエントリインスタンスが作成されていることがわかります。

  1. 一般的なロギング/トレースの実装では、フラッシュの概念がわかります。これは、まだフラッシュされていないログエントリを「フラッシュ」するものです。これにより、複数のログエントリのバッチ処理が可能になります。繰り返しますが、既存のロギング実装にはこの概念がすでに実装されているため、既存のクラスをオーバーライドするだけで済みます。たとえば、NLogには、まさにこの目的のためのBufferingWrapperターゲットがあります。

  2. これは、上記のようにオブジェクトモデルを更新することで解決できる場合があります。

全体として、私は、独自のログフレームワークを作成するのではなく、RavenDBターゲット/アペンダーを使用して既存のログフレームワークを拡張しようとします。ロギングはフレームワークとしてうまく機能するものであり、ロギングの実践全般について、それらを使用することでかなり学ぶことができます。

于 2012-09-21T14:29:24.310 に答える