protected virtual bool UpdateFilePath(LogFileInfo logFile, FileLogEntry entry, CancellationToken cancellationToken) { string filePath = FormatFilePath(logFile, entry); if (logFile.MaxSize > 0) { while (!CheckFileSize(filePath, logFile, entry)) { cancellationToken.ThrowIfCancellationRequested(); logFile.Counter++; var newFilePath = FormatFilePath(logFile, entry); if (filePath == newFilePath) { break; } filePath = newFilePath; } } if (logFile.CurrentPath == filePath) { return(false); } logFile.CurrentPath = filePath; return(true); }
protected virtual bool CheckFileSize(string filePath, LogFileInfo logFile, FileLogEntry entry) { long currentFileSize; if (logFile.AppendStream == null || logFile.CurrentPath != filePath) { IFileInfo fileInfo = logFile.FileAppender.FileProvider.GetFileInfo(Path.Combine(logFile.BasePath, filePath)); if (!fileInfo.Exists) { return(true); } if (fileInfo.IsDirectory) { return(false); } currentFileSize = fileInfo.Length; } else { currentFileSize = logFile.AppendStream.Length; } long expectedFileSize = currentFileSize > 0 ? currentFileSize : logFile.Encoding.GetPreamble().Length; expectedFileSize += logFile.Encoding.GetByteCount(entry.Text); return(expectedFileSize <= logFile.MaxSize); }
internal LogEntryWriteFailed(object source, FileLoggerProcessor.LogFileInfo logFile, FileLogEntry logEntry, Exception exception) { Source = source; _logFile = logFile; _logEntry = logEntry; Exception = exception; }
string GetPostfix(LogFileInfo logFile, Encoding fileEncoding, FileLogEntry entry) { if (HasPostfix(logFile, entry)) { var sb = stringBuilder; stringBuilder = null; if (sb == null) { sb = new StringBuilder(); } while (true) { BuildPostfix(sb, logFile, entry); var postfix = sb.ToString(); sb.Clear(); if (CheckLogFile(logFile, postfix, fileEncoding, entry)) { if (sb.Capacity > 64) { sb.Capacity = 64; } stringBuilder = sb; return(postfix); } } } else { return(null); } }
protected virtual async Task WriteEntryCoreAsync(LogFileInfo logFile, FileLogEntry entry, CancellationToken cancellationToken) { if (logFile.AppendStream.Length == 0) { var preamble = logFile.Encoding.GetPreamble(); await logFile.AppendStream.WriteAsync(preamble, 0, preamble.Length, cancellationToken).ConfigureAwait(false); } var data = logFile.Encoding.GetBytes(entry.Text); await logFile.AppendStream.WriteAsync(data, 0, data.Length, cancellationToken).ConfigureAwait(false); }
protected virtual void BuildPostfix(StringBuilder sb, LogFileInfo logFile, FileLogEntry entry) { if (!string.IsNullOrEmpty(logFile.Settings.DateFormat)) { sb.Append('-'); sb.Append(entry.Timestamp.ToLocalTime().ToString(logFile.Settings.DateFormat, CultureInfo.InvariantCulture)); } if (logFile.Settings.MaxFileSize > 0) { sb.Append('-'); sb.Append(logFile.Counter.ToString(logFile.Settings.CounterFormat, CultureInfo.InvariantCulture)); } }
async Task WriteEntryAsync(LogFileInfo logFile, FileLogEntry entry, CancellationToken disposeToken) { // discarding remaining entries if queue got disposed disposeToken.ThrowIfCancellationRequested(); Encoding fileEncoding; string filePath; bool ensureBasePath; _settingsLock.EnterReadLock(); try { fileEncoding = GetFileEncoding(logFile, entry); var postfix = GetPostfix(logFile, fileEncoding, entry); filePath = logFile.GetFilePath(postfix); ensureBasePath = Settings.EnsureBasePath; } finally { _settingsLock.ExitReadLock(); } var fileInfo = Context.FileProvider.GetFileInfo(filePath); while (true) { try { await Context.AppendAllTextAsync(fileInfo, entry.Text, fileEncoding).ConfigureAwait(false); return; } catch { if (ensureBasePath) { try { if (await Context.EnsureDirAsync(fileInfo).ConfigureAwait(false)) { await Context.AppendAllTextAsync(fileInfo, entry.Text, fileEncoding).ConfigureAwait(false); return; } } catch { } } } // discarding failed entry if queue got disposed await Task.Delay(1000, disposeToken).ConfigureAwait(false); } }
async Task WriteEntryAsync(LogFileInfo logFile, FileLogEntry entry, CancellationToken shutdownToken) { // discarding remaining entries on shutdown shutdownToken.ThrowIfCancellationRequested(); var fileAppender = GetFileAppender(logFile); var fileEncoding = GetFileEncoding(logFile, entry); var postfix = GetPostfix(logFile, fileAppender, fileEncoding, entry); var filePath = logFile.GetFilePath(postfix); var ensureBasePath = logFile.Settings.EnsureBasePath; var fileInfo = fileAppender.FileProvider.GetFileInfo(filePath); while (true) { try { await fileAppender.AppendAllTextAsync(fileInfo, entry.Text, fileEncoding, shutdownToken).ConfigureAwait(false); return; } catch { if (ensureBasePath) { try { if (await fileAppender.EnsureDirAsync(fileInfo, shutdownToken).ConfigureAwait(false)) { await fileAppender.AppendAllTextAsync(fileInfo, entry.Text, fileEncoding, shutdownToken).ConfigureAwait(false); return; } } catch { } } } // discarding failed entry on shutdown if (Context.WriteRetryDelay > TimeSpan.Zero) { await Task.Delay(Context.WriteRetryDelay, shutdownToken).ConfigureAwait(false); } else { shutdownToken.ThrowIfCancellationRequested(); } } }
protected virtual string FormatFilePath(LogFileInfo logFile, FileLogEntry entry) { return(Regex.Replace(logFile.PathFormat, @"<(date|counter)(?::([^<>]+))?>", match => { var inlineFormat = match.Groups[2].Value; switch (match.Groups[1].Value) { case "date": return GetDate(inlineFormat.Length > 0 ? inlineFormat : null, logFile, entry); case "counter": return GetCounter(inlineFormat.Length > 0 ? inlineFormat : null, logFile, entry); default: throw new InvalidOperationException(); } })); }
public void Enqueue(string fileName, FileLogEntry entry) { LogFileInfo logFile; lock (_logFiles) { if (_isDisposed) { throw new ObjectDisposedException(nameof(FileLoggerProcessor)); } if (Context.CompleteToken.IsCancellationRequested) { return; } if (!_logFiles.TryGetValue(fileName, out logFile)) { logFile = CreateLogFile(); logFile.BasePath = Settings.BasePath; logFile.FileName = Path.ChangeExtension(fileName, null); logFile.Extension = Path.GetExtension(fileName); logFile.Queue = new ActionBlock <FileLogEntry>( e => WriteEntryAsync(logFile, e, _disposeTokenSource.Token), new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 1, BoundedCapacity = Settings.MaxQueueSize, }); _logFiles.Add(fileName, logFile); } } logFile.Queue.Post(entry); }
public void Enqueue(FileLogEntry entry, ILogFileSettings fileSettings, IFileLoggerSettings settings) { LogFileInfo logFile; lock (_logFiles) { if (_status == Status.Completed) { throw new ObjectDisposedException(nameof(FileLoggerProcessor)); } if (_status != Status.Running) { return; } if (!_logFiles.TryGetValue(fileSettings, out logFile)) { _logFiles.Add(fileSettings, logFile = CreateLogFile(fileSettings, settings)); } } logFile.Queue.Post(entry); }
public void Enqueue(string fileName, FileLogEntry entry) { LogFileInfo logFile; lock (_logFiles) { if (_isDisposed) { throw new ObjectDisposedException(nameof(FileLoggerProcessor)); } if (Context.CompleteToken.IsCancellationRequested) { return; } if (!_logFiles.TryGetValue(fileName, out logFile)) { _logFiles.Add(fileName, logFile = CreateLogFile(fileName)); } } logFile.Queue.Post(entry); }
public LogFilePathFormatContext(FileLoggerProcessor processor, LogFileInfo logFile, FileLogEntry logEntry) { _processor = processor; _logFile = logFile; _logEntry = logEntry; }
protected virtual string GetCounter(string inlineFormat, LogFileInfo logFile, FileLogEntry entry) { return(logFile.Counter.ToString(inlineFormat ?? logFile.CounterFormat, CultureInfo.InvariantCulture)); }
internal LogEntryDropped(object source, FileLoggerProcessor.LogFileInfo logFile, FileLogEntry logEntry) { Source = source; _logFile = logFile; _logEntry = logEntry; }
private async Task WriteEntryAsync(LogFileInfo logFile, FileLogEntry entry, CancellationToken cancellationToken) { // discarding remaining entries on forced complete cancellationToken.ThrowIfCancellationRequested(); WriteEntryState state = WriteEntryState.CheckFile; IFileInfo fileInfo = null; for (; ;) { switch (state) { case WriteEntryState.CheckFile: try { if (UpdateFilePath(logFile, entry, cancellationToken) && logFile.AppendStream != null) { logFile.CloseAppendStream(); } state = logFile.AppendStream == null ? WriteEntryState.TryCreateStream : WriteEntryState.Write; } catch (Exception ex) when(!(ex is OperationCanceledException)) { state = WriteEntryState.Idle; } break; case WriteEntryState.TryCreateStream: try { fileInfo = logFile.FileAppender.FileProvider.GetFileInfo(Path.Combine(logFile.BasePath, logFile.CurrentPath)); logFile.AppendStream = logFile.FileAppender.CreateAppendStream(fileInfo); state = WriteEntryState.Write; } catch (Exception ex) when(!(ex is OperationCanceledException)) { state = WriteEntryState.RetryCreateStream; } break; case WriteEntryState.RetryCreateStream: try { if (await logFile.FileAppender.EnsureDirAsync(fileInfo, cancellationToken).ConfigureAwait(false)) { logFile.AppendStream = logFile.FileAppender.CreateAppendStream(fileInfo); state = WriteEntryState.Write; } else { state = WriteEntryState.Idle; } } catch (Exception ex) when(!(ex is OperationCanceledException)) { // discarding entry when file path is invalid if (logFile.CurrentPath.IndexOfAny(s_invalidPathChars.Value) >= 0) { return; } state = WriteEntryState.Idle; } break; case WriteEntryState.Write: try { try { await WriteEntryCoreAsync(logFile, entry, cancellationToken).ConfigureAwait(false); if (logFile.AccessMode == LogFileAccessMode.KeepOpenAndAutoFlush) { // FlushAsync is extremely slow currently // https://github.com/dotnet/corefx/issues/32837 logFile.AppendStream.Flush(); } } finally { if (logFile.AccessMode == LogFileAccessMode.OpenTemporarily) { logFile.CloseAppendStream(); } } return; } catch (Exception ex) when(!(ex is OperationCanceledException)) { state = WriteEntryState.Idle; } break; case WriteEntryState.Idle: // discarding failed entry on forced complete if (Context.WriteRetryDelay > TimeSpan.Zero) { await Task.Delay(Context.WriteRetryDelay, cancellationToken).ConfigureAwait(false); } else { cancellationToken.ThrowIfCancellationRequested(); } state = WriteEntryState.CheckFile; break; } } }
protected virtual bool CheckLogFile(LogFileInfo logFile, string postfix, IFileAppender fileAppender, Encoding fileEncoding, FileLogEntry entry) { if (logFile.Settings.MaxFileSize > 0) { var fileInfo = fileAppender.FileProvider.GetFileInfo(logFile.GetFilePath(postfix)); if (fileInfo.Exists && (fileInfo.IsDirectory || fileInfo.Length + fileEncoding.GetByteCount(entry.Text) > logFile.Settings.MaxFileSize)) { logFile.Counter++; return(false); } } return(true); }
protected virtual Encoding GetFileEncoding(LogFileInfo logFile, FileLogEntry entry) { return(Settings.FileEncoding); }
protected virtual bool HasPostfix(LogFileInfo logFile, FileLogEntry entry) { return(!string.IsNullOrEmpty(logFile.Settings.DateFormat) || logFile.Settings.MaxFileSize > 0); }
protected virtual Encoding GetFileEncoding(LogFileInfo logFile, FileLogEntry entry) { return(logFile.Settings.FileEncoding ?? Encoding.UTF8); }
protected virtual string GetDate(string inlineFormat, LogFileInfo logFile, FileLogEntry entry) { return(entry.Timestamp.ToLocalTime().ToString(inlineFormat ?? logFile.DateFormat, CultureInfo.InvariantCulture)); }