public int FillCache(LogFileStream logFileStream, int endindex) { if (endindex > FirstIndex + Items.Count) return -1; int lastItem = Items.Count - 1; for (int i = 0; i < Items.Count; i++) { if (FirstIndex + i > endindex) { lastItem = i - 1; break; } if (Items[i] != null) continue; // Already cached if (i == 0) { // We are filling the cache if (FillCacheEvent != null) FillCacheEvent(this, null); } string line = logFileStream.ReadLine(FirstIndex + i + 1); if (line == null) { lastItem = i - 1; break; } Items[i] = new ListViewItem(line); Items[i].SubItems.Add(""); } // We are done filling the cache if (FillCacheEvent != null) FillCacheEvent(null, null); if (lastItem != Items.Count - 1) return lastItem; else return Items.Count - 1; }
public void LoadConfig(TailFileConfig tailConfig, string configPath) { _configPath = configPath; try { new DirectoryInfo(Path.GetDirectoryName(Path.Combine(configPath, tailConfig.FilePath))); } catch (System.ArgumentException ex) { MessageBox.Show(this, String.Format("Failed to open file:\n\n{0}\n\nError:{1}", tailConfig.FilePath, ex.Message), "Invalid filename", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); Close(); return; } if (tailConfig.FileCacheSize <= 0) tailConfig.FileCacheSize = 1000; if (tailConfig.FormBackColor != null) _tailListView.BackColor = tailConfig.FormBackColor.Value; if (tailConfig.FormTextColor != null) _tailListView.ForeColor = tailConfig.FormTextColor.Value; if (tailConfig.FormFont != null) _tailListView.Font = tailConfig.FormFont; if (tailConfig.FormBookmarkBackColor != null) _bookmarkBackColor = tailConfig.FormBookmarkBackColor.Value; if (tailConfig.FormBookmarkTextColor != null) _bookmarkTextColor = tailConfig.FormBookmarkTextColor.Value; if (tailConfig.FileChangeCheckInterval > 0) _tailTimer.Interval = tailConfig.FileChangeCheckInterval; _externalTools = tailConfig.ExternalTools; externalToolsToolStripMenuItem.DropDownItems.Clear(); externalToolsToolStripMenuItem.Enabled = false; if (_externalTools != null) { foreach (ExternalToolConfig externalTool in _externalTools) { ToolStripMenuItem toolItem = externalToolsToolStripMenuItem.DropDownItems.Add(externalTool.Name) as ToolStripMenuItem; if (toolItem != null) { toolItem.Tag = externalTool; toolItem.Click += new EventHandler(externalToolMenuItem_Click); if (externalTool.ShortcutKeyEnum.HasValue) toolItem.ShortcutKeys = externalTool.ShortcutKeyEnum.Value; } externalToolsToolStripMenuItem.Enabled = true; } } _loghitCounter = -1; _keywordHighlight = tailConfig.KeywordHighlight; if (_keywordHighlight != null) { foreach (TailKeywordConfig keyword in _keywordHighlight) { if (keyword.MatchRegularExpression) { if (keyword.MatchCaseSensitive) keyword.KeywordRegex = new System.Text.RegularExpressions.Regex(keyword.Keyword); else keyword.KeywordRegex = new System.Text.RegularExpressions.Regex(keyword.Keyword, System.Text.RegularExpressions.RegexOptions.IgnoreCase); } else keyword.KeywordRegex = null; if (keyword.LogHitCounter) _loghitCounter = 0; if (!string.IsNullOrEmpty(keyword.ExternalToolName)) { keyword.ExternalToolConfig = _externalTools.Find((externalTool) => string.Compare(externalTool.Name, keyword.ExternalToolName) == 0); if (_threadPoolQueue == null) _threadPoolQueue = new ThreadPoolQueue(); // Prepare the threadpool for use } } } Encoding fileEncoding = tailConfig.EnumFileEncoding; if (_logTailStream != null) _logTailStream.Reset(); if (_logFileStream == null || _logFileStream.FilePath != tailConfig.FilePath || _logFileStream.FileEncoding != fileEncoding || _logFileStream.FileCheckInterval != tailConfig.FileCheckInterval || _logFileStream.FileCheckPattern != tailConfig.FileCheckPattern) { if (_logFileStream != null) _logFileStream.Dispose(); _logFileStream = new LogFileStream(configPath, tailConfig.FilePath, fileEncoding, tailConfig.FileCheckInterval, tailConfig.FileCheckPattern); } if (_logTailStream == null || _logTailStream.FilePath != tailConfig.FilePath || _logTailStream.FileEncoding != fileEncoding || _logTailStream.FileCheckInterval != tailConfig.FileCheckInterval || _logTailStream.FileCheckPattern != tailConfig.FileCheckPattern) { if (_logTailStream != null) _logTailStream.Dispose(); _logTailStream = new LogFileStream(configPath, tailConfig.FilePath, fileEncoding, tailConfig.FileCheckInterval, tailConfig.FileCheckPattern); if (_logTailStream.Length > 500 * 1024 * 1024) { if (MessageBox.Show(this, String.Format("The file is very large, sure you want to open it?\n\nFile Name: {0}\nFile Size: {1} Megabytes", _logTailStream.FilePath, _logTailStream.Length / 1024 / 1024), "Large file detected", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No) { Close(); return; } } if (_logFileCache != null) { _logFileCache.Reset(); _logFileCache = null; // Reset Cache, as the file contents can have changed } } _logTailStream.FileReloadedEvent += new EventHandler(_logTailStream_FileReloadedEvent); if (_logFileCache != null) _logFileCache.Reset(); if (_logFileCache == null || _logFileCache.Items.Count != tailConfig.FileCacheSize) { _logFileCache = new LogFileCache(tailConfig.FileCacheSize); _logFileCache.LoadingFileEvent += new EventHandler(_logFileCache_LoadingFileEvent); _logFileCache.FillCacheEvent += new EventHandler(_logFileCache_FillCacheEvent); // Add loading of cache while counting lines in file int lineCount = _logFileCache.FillTailCache(_logTailStream); _tailListView.VirtualListSize = lineCount; } else { _logFileCache.LoadingFileEvent += new EventHandler(_logFileCache_LoadingFileEvent); _logFileCache.FillCacheEvent += new EventHandler(_logFileCache_FillCacheEvent); } if (_taskMonitor != null) { _taskMonitor.Dispose(); _taskMonitor = null; } if (!string.IsNullOrEmpty(tailConfig.ServiceName)) _taskMonitor = new TaskMonitor(tailConfig.ServiceName); _formTitleMatchFilename = tailConfig.TitleMatchFilename; if (_formTitleMatchFilename) _formTitle = Path.GetFileName(_logTailStream.Name); else if (tailConfig.Title != null) _formTitle = tailConfig.Title; else _formTitle = Path.GetFileName(tailConfig.FilePath); UpdateFormTitle(true); _displayTabIcon = tailConfig.DisplayTabIcon; if (!string.IsNullOrEmpty(tailConfig.IconFile)) { _formIconFile = tailConfig.IconFile; string formIconFilePathAbsolute = System.IO.Path.Combine(configPath, _formIconFile); try { _formCustomIcon = System.Drawing.Icon.ExtractAssociatedIcon(formIconFilePathAbsolute); _formMaximizedIcon = Icon; Icon = _formCustomIcon; } catch (Exception ex) { MessageBox.Show(this, "Failed to load icon\n\n " + formIconFilePathAbsolute + "\n\n" + ex.Message, null, MessageBoxButtons.OK, MessageBoxIcon.Error); } } UpdateFormTitle(true); if (Visible) { if (_tailListView.VirtualListSize > 0) { _tailListView.EnsureVisible(_tailListView.VirtualListSize - 1); _tailListView.FocusedItem = _tailListView.Items[_tailListView.VirtualListSize - 1]; _tailListView.SelectedIndices.Add(_tailListView.VirtualListSize - 1); _tailListView.Invalidate(); _tailListView.Update(); } } }
public void CheckLogFile(bool forceReload) { _lastFileCheck = DateTime.Now; try { // Refreshes the directory of the file, to ensure that we see the latest changes // If the directory is on a network share, then this can be a long blocking operation if (_threadPool != null) { _threadPool.CheckResult(); } DirectoryInfo dirInfo = null; try { dirInfo = new DirectoryInfo(Path.GetDirectoryName(_filePathAbsolute)); } catch (System.ArgumentException ex) { // Any problems with the path should also be detected with the synchronous LoadFile-check System.Diagnostics.Debug.WriteLine("Failed to refresh directory path: " + ex.Message); } catch (System.Security.SecurityException ex) { // Any problems with the path should also be detected with the synchronous LoadFile-check System.Diagnostics.Debug.WriteLine("Failed to access directory path: " + ex.Message); } catch (System.IO.IOException ex) { // Any problems with the path should also be detected with the synchronous LoadFile-check System.Diagnostics.Debug.WriteLine("Failed to read directory path: " + ex.Message); } if (dirInfo != null && _threadPool != null) { _threadPool.ExecuteRequest(RefreshDirectoryInfo, dirInfo); } } catch (ApplicationException ex) { // Any problems with the path should also be detected with the synchronous LoadFile-check System.Diagnostics.Debug.WriteLine(ex.Message); } if (_fileStream == null || forceReload) { LoadFile(_filePathAbsolute, _fileEncoding, _fileCheckPattern); if (_fileStream != null || forceReload) { if (FileReloadedEvent != null) { FileReloadedEvent(this, null); } } } else { string configPath = Path.GetDirectoryName(_filePathAbsolute); bool fileChanged = false; long fileCheckLength = 0; using (LogFileStream testLogFile = new LogFileStream(configPath, _filePathAbsolute, _fileEncoding, _fileCheckFrequency.Seconds, _fileCheckPattern)) { fileCheckLength = testLogFile.Length; long currentFileLength = Length; string name = testLogFile._fileStream != null ? testLogFile._fileStream.Name : null; if (fileCheckLength < currentFileLength) { fileChanged = true; } else if (Position > fileCheckLength) { fileChanged = true; } else if (_fileStream.Name != name) { fileChanged = true; } else if (_lastFileCheckLength <= fileCheckLength && _lastFileCheckLength > currentFileLength) { fileChanged = true; } } if (fileChanged) { // The file have been renamed / deleted (reload new file) LoadFile(_filePathAbsolute, _fileEncoding, _fileCheckPattern); if (FileReloadedEvent != null) { FileReloadedEvent(this, null); } } _lastFileCheckLength = fileCheckLength; } }
public void CheckLogFile(bool forceReload) { _lastFileCheck = DateTime.Now; try { // Refreshes the directory of the file, to ensure that we see the latest changes // If the directory is on a network share, then this can be a long blocking operation if (_threadPool != null) _threadPool.CheckResult(); DirectoryInfo dirInfo = null; try { dirInfo = new DirectoryInfo(Path.GetDirectoryName(_filePathAbsolute)); } catch (System.ArgumentException ex) { // Any problems with the path should also be detected with the synchronous LoadFile-check System.Diagnostics.Debug.WriteLine("Failed to refresh directory path: " + ex.Message); } catch (System.Security.SecurityException ex) { // Any problems with the path should also be detected with the synchronous LoadFile-check System.Diagnostics.Debug.WriteLine("Failed to access directory path: " + ex.Message); } catch (System.IO.IOException ex) { // Any problems with the path should also be detected with the synchronous LoadFile-check System.Diagnostics.Debug.WriteLine("Failed to read directory path: " + ex.Message); } if (dirInfo != null && _threadPool != null) _threadPool.ExecuteRequest(RefreshDirectoryInfo, dirInfo); } catch (ApplicationException ex) { // Any problems with the path should also be detected with the synchronous LoadFile-check System.Diagnostics.Debug.WriteLine(ex.Message); } if (_fileStream == null || forceReload) { LoadFile(_filePathAbsolute, _fileEncoding, _fileCheckPattern); if (_fileStream != null || forceReload) { if (FileReloadedEvent != null) FileReloadedEvent(this, null); } } else { string configPath = Path.GetDirectoryName(_filePathAbsolute); bool fileChanged = false; long fileCheckLength = 0; using (LogFileStream testLogFile = new LogFileStream(configPath, _filePathAbsolute, _fileEncoding, _fileCheckFrequency.Seconds, _fileCheckPattern)) { fileCheckLength = testLogFile.Length; string name = testLogFile._fileStream != null ? testLogFile._fileStream.Name : null; if (fileCheckLength < Length) fileChanged = true; else if (Position > fileCheckLength) fileChanged = true; else if (_fileStream.Name != name) fileChanged = true; else if (_lastFileCheckLength <= fileCheckLength && _lastFileCheckLength > Length) fileChanged = true; } if (fileChanged) { // The file have been renamed / deleted (reload new file) LoadFile(_filePathAbsolute, _fileEncoding, _fileCheckPattern); if (FileReloadedEvent != null) FileReloadedEvent(this, null); } _lastFileCheckLength = fileCheckLength; } }
public int FillTailCache(LogFileStream logFileStream) { int lineCount = 0; int readLines = 0; // Quickly fast forward to near the file bottom do { readLines = lineCount; lineCount = logFileStream.SkipLines(Items.Count); readLines = lineCount - readLines; if (LoadingFileEvent != null) LoadingFileEvent(logFileStream, null); } while (readLines == Items.Count); // We are almost finished with loading the file if (LoadingFileEvent != null) LoadingFileEvent(null, null); if (lineCount <= 0) return 0; // Read the last lines of the file into the cache bool continueReading = false; PrepareCache(lineCount, lineCount, true); do { int lastCacheIndex = FillCache(logFileStream, FirstIndex + Items.Count); System.Diagnostics.Debug.Assert(lastCacheIndex != -1 || logFileStream.Length == 0); continueReading = (lastCacheIndex == Items.Count - 1); lineCount = FirstIndex + lastCacheIndex + 1; if (continueReading) PrepareCache(lineCount + Items.Count / 2, lineCount + Items.Count / 2, true); } while (continueReading); return lineCount; }
public int FillTailCache(LogFileStream logFileStream) { int lineCount = 0; // Quickly fast forward to near the file bottom if (!logFileStream.CloseToEnd(Items.Count)) { do { if (logFileStream.ReadLine(lineCount + 1) != null) lineCount++; // We have read a good part of the file if (lineCount % Items.Count == 0) { if (LoadingFileEvent != null) LoadingFileEvent(logFileStream, null); } } while (!logFileStream.CloseToEnd(Items.Count)); // We are almost finished with loading the file if (LoadingFileEvent != null) LoadingFileEvent(null, null); } // Read the last lines of the file into the cache bool continueReading = false; PrepareCache(lineCount, lineCount, true); do { int lastCacheIndex = FillCache(logFileStream, FirstIndex + Items.Count); System.Diagnostics.Debug.Assert(lastCacheIndex != -1 || logFileStream.Length == 0); continueReading = (lastCacheIndex == Items.Count - 1); lineCount = FirstIndex + lastCacheIndex + 1; if (continueReading) PrepareCache(lineCount + Items.Count / 2, lineCount + Items.Count / 2, true); } while (continueReading); return lineCount; }