22using LogExpert . Entities ;
33using LogExpert . Entities . EventArgs ;
44using LogExpert . Interface ;
5-
65using NLog ;
7-
86using System ;
97using System . Collections . Generic ;
108using System . IO ;
@@ -22,7 +20,17 @@ public class LogfileReader : IAutoLogLineColumnizerCallback
2220
2321 private readonly GetLogLineFx _logLineFx ;
2422
25- private readonly string _fileName ;
23+ private string FileName
24+ {
25+ get ; init
26+ {
27+ var uri = new Uri ( value ) ;
28+ if ( uri . IsFile )
29+ {
30+ field = uri . LocalPath ; // Convert the URI to a local file path
31+ }
32+ }
33+ }
2634 private readonly int _MAX_BUFFERS = 10 ;
2735 private readonly int _MAX_LINES_PER_BUFFER = 100 ;
2836
@@ -39,7 +47,6 @@ public class LogfileReader : IAutoLogLineColumnizerCallback
3947 private long _fileLength ;
4048
4149 private Task _garbageCollectorTask ;
42- private Task _monitorTask ;
4350 private readonly CancellationTokenSource cts = new ( ) ;
4451
4552 private bool _isDeleted ;
@@ -51,7 +58,7 @@ public class LogfileReader : IAutoLogLineColumnizerCallback
5158
5259 private ReaderWriterLock _lruCacheDictLock ;
5360
54-
61+ private FileSystemWatcher _watcher ;
5562 private bool _shouldStop ;
5663 private ILogFileInfo _watchedILogFileInfo ;
5764
@@ -66,7 +73,7 @@ public LogfileReader(string fileName, EncodingOptions encodingOptions, bool mult
6673 return ;
6774 }
6875
69- _fileName = fileName ;
76+ FileName = fileName ;
7077 EncodingOptions = encodingOptions ;
7178 IsMultiFile = multiFile ;
7279 _MAX_BUFFERS = bufferCount ;
@@ -120,7 +127,7 @@ public LogfileReader(string[] fileNames, EncodingOptions encodingOptions, int bu
120127 }
121128
122129 _watchedILogFileInfo = fileInfo ;
123- _fileName = fileInfo . FullName ;
130+ FileName = fileInfo . FullName ;
124131
125132 StartGCThread ( ) ;
126133 }
@@ -268,7 +275,7 @@ public void ReadFiles()
268275 /// <returns></returns>
269276 public int ShiftBuffers ( )
270277 {
271- _logger . Info ( "ShiftBuffers() begin for {0}{1}" , _fileName , IsMultiFile ? " (MultiFile)" : "" ) ;
278+ _logger . Info ( "ShiftBuffers() begin for {0}{1}" , FileName , IsMultiFile ? " (MultiFile)" : "" ) ;
272279 AcquireBufferListWriterLock ( ) ;
273280 int offset = 0 ;
274281 _isLineCountDirty = true ;
@@ -571,28 +578,142 @@ public int GetRealLineNumForVirtualLineNum(int lineNum)
571578 return result ;
572579 }
573580
574- public void StartMonitoring ( )
581+ public async Task StartMonitoring ( )
575582 {
576- _logger . Info ( "startMonitoring()" ) ;
577- _monitorTask = Task . Run ( MonitorThreadProc , cts . Token ) ;
583+ _logger . Info ( "StartMonitoring() for file ${_watchedILogFileInfo.FullName}" ) ;
584+
585+ await Task . Run ( ( ) =>
586+ {
587+ _logger . Info ( "MonitorThreadProc() for file {0}" , _watchedILogFileInfo . FullName ) ;
588+
589+ long oldSize = 0 ;
590+ try
591+ {
592+ OnLoadingStarted ( new LoadFileEventArgs ( FileName , 0 , false , 0 , false ) ) ;
593+ ReadFiles ( ) ;
594+ if ( ! _isDeleted )
595+ {
596+ oldSize = _fileLength ;
597+ OnLoadingFinished ( ) ;
598+ }
599+ }
600+ catch ( Exception e )
601+ {
602+ _logger . Error ( e ) ;
603+ }
604+ } ) ;
605+
606+ try
607+ {
608+ _watcher = new FileSystemWatcher
609+ {
610+ NotifyFilter = //NotifyFilters.Attributes
611+ //| NotifyFilters.CreationTime
612+ //| NotifyFilters.DirectoryName
613+ //|
614+ NotifyFilters . FileName
615+ //| NotifyFilters.LastAccess
616+ | NotifyFilters . LastWrite
617+ //| NotifyFilters.Security
618+ | NotifyFilters . Size ,
619+
620+ Path = Path . GetDirectoryName ( FileName ) ?? throw new ArgumentException ( "Invalid file path" ) ,
621+ Filter = Path . GetFileName ( FileName ) , // Sets filter to the specific
622+ EnableRaisingEvents = true
623+ } ;
624+ }
625+ catch ( UnauthorizedAccessException ex )
626+ {
627+ Console . WriteLine ( $ "Access denied: { ex . Message } ") ;
628+ }
629+ catch ( ArgumentException ex )
630+ {
631+ Console . WriteLine ( $ "Invalid argument: { ex . Message } ") ;
632+ }
633+ catch ( Exception ex )
634+ {
635+ Console . WriteLine ( $ "An error occurred: { ex . Message } ") ;
636+ }
637+
638+ _watcher . Error += ( sender , e ) =>
639+ {
640+ Console . WriteLine ( $ "Error occurred: { e . GetException ( ) . Message } ") ;
641+ Task . Delay ( 5000 ) . ContinueWith ( _ =>
642+ {
643+ try
644+ {
645+ Console . WriteLine ( "Attempting to restart the watcher..." ) ;
646+ _watcher . EnableRaisingEvents = true ;
647+ }
648+ catch ( Exception ex )
649+ {
650+ Console . WriteLine ( $ "Failed to restart the watcher: { ex . Message } ") ;
651+ }
652+ } ) ;
653+ } ;
654+ _watcher . Changed += OnFileChanged ;
655+ _watcher . Created += OnCreated ;
656+ _watcher . Deleted += OnFileDeleted ;
657+ _watcher . Renamed += OnFileRenamed ;
658+ _watcher . Error += OnFileError ;
659+
578660 _shouldStop = false ;
579661 }
580662
663+ private void OnFileError ( object sender , ErrorEventArgs e )
664+ {
665+ throw new NotImplementedException ( ) ;
666+ }
667+
668+ private void OnFileRenamed ( object sender , RenamedEventArgs e )
669+ {
670+ throw new NotImplementedException ( ) ;
671+ }
672+
673+ private void OnCreated ( object sender , FileSystemEventArgs e )
674+ {
675+ //TODO: This should be deleted before merge?
676+ throw new NotImplementedException ( ) ;
677+ }
678+
679+ private void OnFileDeleted ( object sender , FileSystemEventArgs e )
680+ {
681+ MonitoredFileNotFound ( ) ;
682+ }
683+
684+ private void OnFileChanged ( object sender , FileSystemEventArgs e )
685+ {
686+ try
687+ {
688+ _watchedILogFileInfo . FileHasChanged ( ) ;
689+ _fileLength = _watchedILogFileInfo . Length ;
690+ FileChanged ( ) ;
691+ }
692+ catch ( FileNotFoundException ex )
693+ {
694+ MonitoredFileNotFound ( ) ;
695+ }
696+ catch ( Exception ex )
697+ {
698+ throw new NotImplementedException ( ) ;
699+ }
700+ }
701+
581702 public void StopMonitoring ( )
582703 {
583704 _logger . Info ( "stopMonitoring()" ) ;
584705 _shouldStop = true ;
585706
586- Thread . Sleep ( _watchedILogFileInfo . PollInterval ) ; // leave time for the threads to stop by themselves
587-
588- if ( _monitorTask != null )
707+ if ( _watcher != null )
589708 {
590- if ( _monitorTask . Status == TaskStatus . Running ) // if thread has not finished, abort it
591- {
592- cts . Cancel ( ) ;
593- }
709+ _watcher . EnableRaisingEvents = false ; // Stop watching
710+ _watcher . Dispose ( ) ; // Release resources
711+ _watcher = null ; // Clear the reference
712+
594713 }
595714
715+ Thread . Sleep ( _watchedILogFileInfo . PollInterval ) ; // leave time for the threads to stop by themselves
716+
596717 if ( _garbageCollectorTask . IsCanceled == false )
597718 {
598719 if ( _garbageCollectorTask . Status == TaskStatus . Running ) // if thread has not finished, abort it
@@ -630,11 +751,11 @@ public void DeleteAllContent()
630751 {
631752 if ( _contentDeleted )
632753 {
633- _logger . Debug ( "Buffers for {0} already deleted." , Util . GetNameFromPath ( _fileName ) ) ;
754+ _logger . Debug ( "Buffers for {0} already deleted." , Util . GetNameFromPath ( FileName ) ) ;
634755 return ;
635756 }
636757
637- _logger . Info ( "Deleting all log buffers for {0}. Used mem: {1:N0}" , Util . GetNameFromPath ( _fileName ) , GC . GetTotalMemory ( true ) ) ; //TODO [Z] uh GC collect calls creepy
758+ _logger . Info ( "Deleting all log buffers for {0}. Used mem: {1:N0}" , Util . GetNameFromPath ( FileName ) , GC . GetTotalMemory ( true ) ) ; //TODO [Z] uh GC collect calls creepy
638759 AcquireBufferListWriterLock ( ) ;
639760 _lruCacheDictLock . AcquireWriterLock ( Timeout . Infinite ) ;
640761 _disposeLock . AcquireWriterLock ( Timeout . Infinite ) ;
@@ -701,7 +822,7 @@ internal void LogBufferInfoForLine(int lineNum)
701822 if ( buffer == null )
702823 {
703824 ReleaseBufferListReaderLock ( ) ;
704- _logger . Error ( "Cannot find buffer for line {0}, file: {1}{2}" , lineNum , _fileName , IsMultiFile ? " (MultiFile)" : "" ) ;
825+ _logger . Error ( "Cannot find buffer for line {0}, file: {1}{2}" , lineNum , FileName , IsMultiFile ? " (MultiFile)" : "" ) ;
705826 return ;
706827 }
707828
@@ -726,7 +847,7 @@ internal void LogBufferDiagnostic()
726847 _lruCacheDictLock . ReleaseReaderLock ( ) ;
727848
728849 AcquireBufferListReaderLock ( ) ;
729- _logger . Info ( "File: {0}\r \n Buffer count: {1}\r \n Disposed buffers: {2}" , _fileName , _bufferList . Count , _bufferList . Count - cacheCount ) ;
850+ _logger . Info ( "File: {0}\r \n Buffer count: {1}\r \n Disposed buffers: {2}" , FileName , _bufferList . Count , _bufferList . Count - cacheCount ) ;
730851 int lineNum = 0 ;
731852 long disposeSum = 0 ;
732853 long maxDispose = 0 ;
@@ -782,7 +903,7 @@ private Task<ILogLine> GetLogLineInternal(int lineNum)
782903 if ( logBuffer == null )
783904 {
784905 ReleaseBufferListReaderLock ( ) ;
785- _logger . Error ( "Cannot find buffer for line {0}, file: {1}{2}" , lineNum , _fileName , IsMultiFile ? " (MultiFile)" : "" ) ;
906+ _logger . Error ( "Cannot find buffer for line {0}, file: {1}{2}" , lineNum , FileName , IsMultiFile ? " (MultiFile)" : "" ) ;
786907 return null ;
787908 }
788909
@@ -1147,7 +1268,7 @@ private void GarbageCollectLruCache()
11471268#if DEBUG
11481269 if ( diff > 0 )
11491270 {
1150- _logger . Info ( "Removing {0} entries from LRU cache for {1}" , diff , Util . GetNameFromPath ( _fileName ) ) ;
1271+ _logger . Info ( "Removing {0} entries from LRU cache for {1}" , diff , Util . GetNameFromPath ( FileName ) ) ;
11511272 }
11521273#endif
11531274 SortedList < long , int > useSorterList = [ ] ;
@@ -1464,74 +1585,6 @@ private LogBuffer GetFirstBufferForFileByLogBuffer(LogBuffer logBuffer)
14641585 return resultBuffer ;
14651586 }
14661587
1467- private void MonitorThreadProc ( )
1468- {
1469- Thread . CurrentThread . Name = "MonitorThread" ;
1470- //IFileSystemPlugin fs = PluginRegistry.GetInstance().FindFileSystemForUri(this.watchedILogFileInfo.FullName);
1471- _logger . Info ( "MonitorThreadProc() for file {0}" , _watchedILogFileInfo . FullName ) ;
1472-
1473- long oldSize = 0 ;
1474- try
1475- {
1476- OnLoadingStarted ( new LoadFileEventArgs ( _fileName , 0 , false , 0 , false ) ) ;
1477- ReadFiles ( ) ;
1478- if ( ! _isDeleted )
1479- {
1480- oldSize = _fileLength ;
1481- OnLoadingFinished ( ) ;
1482- }
1483- }
1484- catch ( Exception e )
1485- {
1486- _logger . Error ( e ) ;
1487- }
1488-
1489- while ( ! _shouldStop )
1490- {
1491- try
1492- {
1493- int pollInterval = _watchedILogFileInfo . PollInterval ;
1494- //#if DEBUG
1495- // if (_logger.IsDebug)
1496- // {
1497- // _logger.logDebug("Poll interval for " + this.fileName + ": " + pollInterval);
1498- // }
1499- //#endif
1500- Thread . Sleep ( pollInterval ) ;
1501- }
1502- catch ( Exception e )
1503- {
1504- _logger . Error ( e ) ;
1505- }
1506-
1507- if ( _shouldStop )
1508- {
1509- return ;
1510- }
1511-
1512- try
1513- {
1514- if ( _watchedILogFileInfo . FileHasChanged ( ) )
1515- {
1516- _fileLength = _watchedILogFileInfo . Length ;
1517- if ( _fileLength == - 1 )
1518- {
1519- MonitoredFileNotFound ( ) ;
1520- }
1521- else
1522- {
1523- oldSize = _fileLength ;
1524- FileChanged ( ) ;
1525- }
1526- }
1527- }
1528- catch ( FileNotFoundException )
1529- {
1530- MonitoredFileNotFound ( ) ;
1531- }
1532- }
1533- }
1534-
15351588 private void MonitoredFileNotFound ( )
15361589 {
15371590 long oldSize ;
@@ -1563,7 +1616,7 @@ private void FileChanged()
15631616 long newSize = _fileLength ;
15641617 //if (this.currFileSize != newSize)
15651618 {
1566- _logger . Info ( "file size changed. new size={0}, file: {1}" , newSize , _fileName ) ;
1619+ _logger . Info ( "file size changed. new size={0}, file: {1}" , newSize , FileName ) ;
15671620 FireChangeEvent ( ) ;
15681621 }
15691622 }
@@ -1586,7 +1639,7 @@ private void FireChangeEvent()
15861639 {
15871640 // ReloadBufferList(); // removed because reloading is triggered by owning LogWindow
15881641 // Trigger "new file" handling (reload)
1589- OnLoadFile ( new LoadFileEventArgs ( _fileName , 0 , true , _fileLength , true ) ) ;
1642+ OnLoadFile ( new LoadFileEventArgs ( FileName , 0 , true , _fileLength , true ) ) ;
15901643
15911644 if ( _isDeleted )
15921645 {
0 commit comments