Utilizzando file mappato in memoria e FileSystemWatcher di individuare nuove voci al logfile

StackOverflow https://stackoverflow.com/questions/4198692

  •  11-10-2019
  •  | 
  •  

Domanda

Ho un file di log che è stato scritto da un'applicazione 3rd party e mi piacerebbe la mia domanda di "leggere" che file di log in / near-real time, analizzare i nuovi voci di registro e agire su determinati eventi.

Il mio pensiero era che avrei potuto raggiungere questo obiettivo con una combinazione di FileSystemWatcher (per le modifiche di file segnale) e file mappato in memoria (per continuare a leggere da un offset di certo).

Tuttavia, dal momento che questa è la prima volta che sto utilizzando MemoryMappedFiles io incorrere in alcuni problemi che probabilmente derivano dal non comprendere il concetto in modo corretto (per esempio io sono in grado di aprire il file esistente come è in uso da parte l'altro processo ).

Mi chiedevo se qualcuno ha un esempio di come utilizzare MemoryMappedFiles di leggere un file che è bloccato da un altro processo?

Grazie,

Tom

EDIT:

Dai commenti, sembra che file mappati in memoria non mi aiuterà l'accesso ai file che hanno un blocco esclusivo. Tuttavia, "coda" Strumenti come, ad esempio BareTail (http://www.baremetalsoft.com/baretail/index.php) sono in grado di fare proprio questo. Non ha alcun problema di lettura del file che ha un blocco esclusivo da un'altra applicazione in intervalli di 1 secondo). Quindi, ci deve essere un modo per fare questo?

EDITEDIT :

Per rispondere alla mia domanda, il trucco ad aprire un file bloccato viene, creando il FileStream con le bandiere di accesso seguenti:

fileStream = new System.IO.FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.ReadWrite);
È stato utile?

Soluzione

Per rispondere alla mia domanda, il trucco nella lettura di un file bloccato sta creando il FileStream con le bandiere di accesso seguenti:

FileStream fileStream = new System.IO.FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.ReadWrite);

Ora è solo una questione di fare o di polling basato intervallo o alla ricerca di eventi di modifica FileSystemWatcher per rilevare i cambiamenti dei file

Altri suggerimenti

Non sono sicuro se MemoryMappedFiles stanno andando per aiutarvi. Date un'occhiata a FileStream:

var stream = new FileStream(path, FileMode.Open, FileShare.Read);
stream.Seek(offset, SeekOrigin.Begin);

Anche se se l'applicazione 3rd-party ha il file bloccato in modo esclusivo, non c'è molto che si può fare al riguardo ...

[Inizia 2nd EDIT]

Ancora un'idea ...

Se l'applicazione di terze parti capita di utilizzare un quadro di registrazione come NLog, log4net, o System.Diagnostics, si potrebbe ancora scrivere il proprio target / Appender / TraceListener e instradare i messaggi da qualche parte che si potrebbe guardare a loro (come ad esempio un file che non è aperto in modalità esclusiva, a un altro processo, ecc).

Se il suo partito app di terze utilizza un quadro di registrazione, probabilmente avrebbe sentito parlare ormai; -)

[Fine 2 ° EDIT]

[Inizia EDIT]

Penso che ho letto male la domanda. Sembrava in un primo momento, come si stesse utilizzando una libreria di terze parti che si erano logging implementata e si voleva fare questo parsing dall'interno del programma che è stato generando la registrazione. Avendo riletto la tua domanda, suona come si desidera "ascoltare" il file di log al di fuori dell'applicazione. Se questo è il caso, la mia risposta probabilmente non vi aiuterà. Siamo spiacenti.

[Fine EDIT]

Non ho nulla da offrire su MemoryMappedFiles, ma mi chiedo se si poteva ottenere che cosa siete dopo scrivendo un listener personalizzato / target / appender per il 3 ° sistema di registrazione del partito?

Ad esempio, se si utilizza NLog, si potrebbe scrivere un target personalizzato e dirigere tutti i messaggi di registrazione lì (mentre anche indirizzandoli ai "veri" Target (s)). In questo modo si ottiene crepa in ogni messaggio di log in quanto viene registrato (quindi in realtà è in tempo reale, senza quasi in tempo reale). Si potrebbe fare la stessa cosa con log4net e System.Diagnostics.

Si noti che NLog ha anche un obiettivo "methodCall". Per utilizzare che uno è sufficiente scrivere un metodo statico con la firma corretta. Non so se log4net ha un concetto simile a questo.

Questo mi sembra che sarebbe più facile da far funzionare in modo affidabile che cercare di leggere e analizzare il file di log mentre viene scritto dal software di terze parti.

Se il file è "in uso", non c'è niente che si può fare al riguardo. E 'veramente "in uso". MemoryMappedFiles sono sia per la lettura di grandi quantità di dati dal disco o la condivisione dei dati con altri programmi. Non aiuterà ottenere intorno alla "in uso" limitazione.

I file Memorymapped sono sotto le stesse restrizioni della FileStream si inizializza con, essere sicuri che si inizializza la vostra memory-mapped-file come questo

var readerStream = new FileStream (percorso, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

var MMF = MemoryMappedFile.CreateFromFile (readerStream, null, 0, MemoryMappedFileAccess.Read, null, HandleInheritability.None, false);

Se qualche altro processo hanno completamente bloccato ancora da scrivere siete nella sfortuna, non so se c'è un modo per aggirare questo. Forse utilizzare alcuni timer vengono rilevati da quando il processo ha smesso di scrivere ad esso.

Ho fatto qualcosa di simile solo per il monitoraggio dei file di log su una console (al contrario di trasformazione), ma i principi sono gli stessi. Come voi, io uso un FileSystemWatcher, e la logica importante è nel mio gestore di eventi OnChanged:

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;
}

dove lastPositions è

Dictionary<string, Int64> lastPositions = new Dictionary<string, long>();

e DumpNewData è semplicemente

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);
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top