private void ProcessNewOrExpandedFiles(string filePath, string relativeFilePath, long fileSize) { //Only process new or expanded files if (_logFiles.TryGetValue(relativeFilePath, out TContext context)) { // If there is no registered bookmark and we're bookmarking on buffer flush, // that means the file was read and events buffered, but never uploaded by the source. var position = this.bookmarkOnBufferFlush ? (BookmarkManager.GetBookmark(this.GetBookmarkName(filePath)) ?? BookmarkManager.RegisterBookmark(this.GetBookmarkName(filePath), 0, (pos) => this.SaveBookmark())).Position : context.Position; if (fileSize > position) { // The file is expanded compared with position saved in bookmark AddToBuffer(relativeFilePath); } } else { //New file _logFiles.Add(relativeFilePath, CreateLogSourceInfo(filePath, 0)); if (this.bookmarkOnBufferFlush) { BookmarkManager.RegisterBookmark(this.GetBookmarkName(filePath), 0, (pos) => this.SaveBookmark()); } AddToBuffer(relativeFilePath); } }
protected virtual void OnRenamed(object source, RenamedEventArgs e) { try { // this is for Subdirectories check only if (this.includeSubdirectories && this.ShouldSkip(e.FullPath)) { return; } //Sometimes we receive event where e.name is null so we should just skip it if (string.IsNullOrEmpty(e.Name) || string.IsNullOrEmpty(e.OldName) || ShouldExclude(e.Name) || ShouldExclude(e.OldName) || (!ShouldInclude(e.Name) && !ShouldInclude(e.OldName))) { return; } //File name rotation RemoveFromBuffer(e.OldName); if (_logFiles.ContainsKey(e.OldName)) { var newSourceInfo = CreateLogSourceInfo(e.FullPath, _logFiles[e.OldName].Position); newSourceInfo.LineNumber = _logFiles[e.OldName].LineNumber; _logFiles[e.Name] = newSourceInfo; _logFiles.Remove(e.OldName); var bookmark = BookmarkManager.GetBookmark(this.GetBookmarkName(e.OldFullPath)); if (bookmark != null) { BookmarkManager.RemoveBookmark(bookmark.Id); BookmarkManager.RegisterBookmark(this.GetBookmarkName(e.FullPath), bookmark.Position, (id) => this.SaveBookmark()); } } else { var newSource = CreateLogSourceInfo(e.FullPath, 0); _logFiles.Add(e.Name, newSource); BookmarkManager.RegisterBookmark(this.GetBookmarkName(e.FullPath), 0, (id) => this.SaveBookmark()); } } catch (Exception ex) { _logger?.LogError(ex.ToMinimized()); } finally { AddToBuffer(e.Name); _logger?.LogInformation("File: {0} renamed to {1}", e.OldFullPath, e.FullPath); } }
public void SaveBookmark() { if (this.InitialPosition == InitialPositionEnum.EOS || !this._started) { return; } // We don't gather the contents of the bookmark file outside of the lock because // we want to avoid a situation where two threads capture position info at slightly different times, and then they write the file out of sequence // (older collected data after newer collected data) since that would lead to out of date bookmarks recorded in the bookmark file. In other words // the gathering of position data and writing the file needs to be atomic. lock (_bookmarkFileLock) { try { using (var fs = new FileStream(this.bookmarkPath, FileMode.Create, FileAccess.Write, FileShare.None)) using (var sw = new StreamWriter(fs)) { foreach (var logFile in _logFiles.Values) { long position; if (this.bookmarkOnBufferFlush) { position = BookmarkManager.GetBookmark(this.GetBookmarkName(logFile.FilePath))?.Position ?? logFile.Position; } else { position = logFile.Position; } sw.WriteLine($"{logFile.FilePath},{position}"); } } } catch (Exception ex) { _logger?.LogError($"Failed saving bookmark: {ex.ToMinimized()}"); } } }