MemoryMappedFileとFilesystemWatcherを使用して、LogFileへの新しいエントリを検出する
-
11-10-2019 - |
質問
サードパーティのアプリケーションによって書かれたLogFileがあります。アプリケーションは、そのログファイルを実際/近距離で「読み取り」、新しいログエントリを解析し、特定のイベントに基づいて行動したいと思います。
私の考えは、ファイルシステムウォッチャー(ファイルの変更を信号する)とメモリマップファイル(特定のオフセットから読み続けるため)の組み合わせでこれを達成できるということでした。
ただし、メモリマップファイルを使用しているのはこれが初めてであるため、おそらく概念を正しく理解しないことから生じるいくつかの問題に遭遇します(たとえば、他のプロセスで使用されているため、既存のファイルを開くことができません)。
誰かがメモリマップファイルを使用して別のプロセスによってロックされているファイルを読む方法の例を持っているかどうか疑問に思っていましたか?
ありがとう、
トム
編集:
コメントから、メモリマッピングされたファイルは、排他的ロックを備えたファイルにアクセスするのに役立つように見えます。ただし、たとえばBaretail(http://www.baremetalsoft.com/baretail/index.php)のような「テール」ツールはまさにそれを行うことができます。 1S間隔で別のアプリケーションからの排他的ロックがあるファイルを読み取るのに問題はありません)。それで、これを行うには何らかの方法が必要ですか?
編集:
私自身の質問に答えるために、ロックされたファイルを開く際のトリックは、次のアクセスフラグを持つFilestreamを作成することです。
fileStream = new System.IO.FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.ReadWrite);
解決
私自身の質問に答えるために、ロックされたファイルを読む際のトリックは、次のアクセスフラグを持つFilestreamを作成することです。
FileStream fileStream = new System.IO.FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.ReadWrite);
今では、インターバルベースのポーリングを行うか、ファイルの変更を検出するためにファイルシステムウォッチャーの変更イベントを探しているだけの問題です
他のヒント
メモリマップファイルがあなたを助けるかどうかはわかりません。 Filestreamを見てください:
var stream = new FileStream(path, FileMode.Open, FileShare.Read);
stream.Seek(offset, SeekOrigin.Begin);
サードパーティのアプリケーションにファイルが独占的にロックされている場合、それについてできることはあまりありません...
2回目の編集を開始
もう1つのアイデア...
サードパーティのアプリがたまたまnlog、log4net、またはsystem.diagnosticsなどのロギングフレームワークを使用している場合でも、独自のターゲット/appender/traceListenerを記述し、それらを見ることができるメッセージをどこかにルーティングできます(ファイルなどのファイルなど別のプロセスなどに独占的に開かれていません)。
サードパーティのアプリがロギングフレームワークを使用している場合、おそらく今までに聞いたことがあるでしょう;-)
終了編集
編集を開始
私は質問を誤解したと思います。最初は、ロギングが実装されていたサードパーティライブラリを使用していたように聞こえ、ロギングを生成しているプログラム内からこの解析を行いたいと思っていました。質問を読み直したので、アプリケーションの外部からログファイルを「聞いている」ように聞こえます。その場合、私の答えはおそらくあなたを助けません。ごめん。
編集を終了
MemoryMappedFilesについては何も提供していませんが、サードパーティのロギングシステムのカスタムリスナー/ターゲット/Appenderを書くことで、自分が何であるかを達成できるのだろうかと思いますか?
たとえば、NLOGを使用している場合、カスタムターゲットを書き込み、すべてのロギングメッセージをそこに向けることができます(「実際の」ターゲットにも向けます)。これにより、ログが記録されると、各ログメッセージでクラックが表示されます(実際、リアルタイムではなく、リアルタイムではありません)。 log4netとsystem.diagnosticsで同じことをすることができます。
NLOGには「MethodCall」ターゲットもあることに注意してください。それを使用するには、正しい署名を使用して静的メソッドを作成するだけです。 Log4Netがこれと同様の概念を持っているかどうかはわかりません。
これは、サードパーティのソフトウェアによって記述されているため、ログファイルを読み取って解析しようとするよりも、確実に機能する方が簡単だと思われます。
ファイルが「使用中」である場合、それについてできることは何もありません。それは本当に「使用中」です。メモリマップファイルは、ドライブから大量のデータを読み取るか、他のプログラムとデータを共有するためのものです。 「使用中」の制限を回避するのに役立ちません。
メモリマップされたファイルは、Filestreamと同じ制限の下にあります。
var readerstream = new fileStream(Path、filemode.open、fileaccess.read、fileshare.readwrite);
var mmf = memorymappedfile.createfromfile(readerstream、null、0、memorymappedfileaccess.read、null、handleInheritability.none、false);
他のプロセスがそれを完全にロックした場合でも、あなたは不運に陥っているので、それを回避する方法があるかどうかはわかりません。おそらく、プロセスが書き込みを停止したときに検出するタイマーを使用してください。
コンソール上のログファイルを監視するためだけに似たようなことをしました(処理とは対照的に)が、原則は同じです。あなたと同じように、私はFilesystemWatcherを使用しています。重要なロジックは、私の変化したイベントハンドラーにあります。
case WatcherChangeTypes.Changed:
{
System.IO.FileInfo fi = new FileInfo(e.FullPath);
long prevLength;
if (lastPositions.TryGetValue(e.FullPath, out prevLength))
{
using (System.IO.FileStream fs = new FileStream(
e.FullPath, FileMode.Open, FileAccess.Read))
{
fs.Seek(prevLength, SeekOrigin.Begin);
DumpNewData(fs, (int)(fi.Length - prevLength));
lastPositions[e.FullPath] = fs.Position;
}
}
else
lastPositions.Add(e.FullPath, fi.Length);
break;
}
ラストポジションがある場所
Dictionary<string, Int64> lastPositions = new Dictionary<string, long>();
そして、dumpnewdataは単純です
private static void DumpNewData(FileStream fs, int bytesToRead)
{
byte[] bytesRead = new byte[bytesToRead];
fs.Read(bytesRead, 0, bytesToRead);
string s = System.Text.ASCIIEncoding.ASCII.GetString(bytesRead);
Console.Write(s);
}